1189251Ssam/* 2189251Ssam * WPA Supplicant / Control interface (shared code for all backends) 3346981Scy * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9214734Srpaulo#include "utils/includes.h" 10281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 11281806Srpaulo#include <netinet/ip.h> 12281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 13189251Ssam 14351611Scy#include <net/ethernet.h> 15214734Srpaulo#include "utils/common.h" 16214734Srpaulo#include "utils/eloop.h" 17281806Srpaulo#include "utils/uuid.h" 18337817Scy#include "utils/module_tests.h" 19252726Srpaulo#include "common/version.h" 20214734Srpaulo#include "common/ieee802_11_defs.h" 21252726Srpaulo#include "common/ieee802_11_common.h" 22214734Srpaulo#include "common/wpa_ctrl.h" 23346981Scy#ifdef CONFIG_DPP 24346981Scy#include "common/dpp.h" 25346981Scy#endif /* CONFIG_DPP */ 26281806Srpaulo#include "crypto/tls.h" 27281806Srpaulo#include "ap/hostapd.h" 28214734Srpaulo#include "eap_peer/eap.h" 29214734Srpaulo#include "eapol_supp/eapol_supp_sm.h" 30214734Srpaulo#include "rsn_supp/wpa.h" 31214734Srpaulo#include "rsn_supp/preauth.h" 32214734Srpaulo#include "rsn_supp/pmksa_cache.h" 33214734Srpaulo#include "l2_packet/l2_packet.h" 34214734Srpaulo#include "wps/wps.h" 35289549Srpaulo#include "fst/fst.h" 36289549Srpaulo#include "fst/fst_ctrl_iface.h" 37189251Ssam#include "config.h" 38189251Ssam#include "wpa_supplicant_i.h" 39214734Srpaulo#include "driver_i.h" 40214734Srpaulo#include "wps_supplicant.h" 41214734Srpaulo#include "ibss_rsn.h" 42214734Srpaulo#include "ap.h" 43252726Srpaulo#include "p2p_supplicant.h" 44252726Srpaulo#include "p2p/p2p.h" 45252726Srpaulo#include "hs20_supplicant.h" 46252726Srpaulo#include "wifi_display.h" 47214734Srpaulo#include "notify.h" 48214734Srpaulo#include "bss.h" 49214734Srpaulo#include "scan.h" 50189251Ssam#include "ctrl_iface.h" 51252726Srpaulo#include "interworking.h" 52252726Srpaulo#include "blacklist.h" 53252726Srpaulo#include "autoscan.h" 54252726Srpaulo#include "wnm_sta.h" 55281806Srpaulo#include "offchannel.h" 56281806Srpaulo#include "drivers/driver.h" 57281806Srpaulo#include "mesh.h" 58346981Scy#include "dpp_supplicant.h" 59346981Scy#include "sme.h" 60189251Ssam 61189251Ssamstatic int wpa_supplicant_global_iface_list(struct wpa_global *global, 62189251Ssam char *buf, int len); 63189251Ssamstatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, 64337817Scy const char *input, 65189251Ssam char *buf, int len); 66281806Srpaulostatic int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, 67281806Srpaulo char *val); 68189251Ssam 69346981Scy 70252726Srpaulostatic int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) 71252726Srpaulo{ 72252726Srpaulo char *pos; 73252726Srpaulo u8 addr[ETH_ALEN], *filter = NULL, *n; 74252726Srpaulo size_t count = 0; 75252726Srpaulo 76252726Srpaulo pos = val; 77252726Srpaulo while (pos) { 78252726Srpaulo if (*pos == '\0') 79252726Srpaulo break; 80252726Srpaulo if (hwaddr_aton(pos, addr)) { 81252726Srpaulo os_free(filter); 82252726Srpaulo return -1; 83252726Srpaulo } 84252726Srpaulo n = os_realloc_array(filter, count + 1, ETH_ALEN); 85252726Srpaulo if (n == NULL) { 86252726Srpaulo os_free(filter); 87252726Srpaulo return -1; 88252726Srpaulo } 89252726Srpaulo filter = n; 90252726Srpaulo os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN); 91252726Srpaulo count++; 92252726Srpaulo 93252726Srpaulo pos = os_strchr(pos, ' '); 94252726Srpaulo if (pos) 95252726Srpaulo pos++; 96252726Srpaulo } 97252726Srpaulo 98252726Srpaulo wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN); 99252726Srpaulo os_free(wpa_s->bssid_filter); 100252726Srpaulo wpa_s->bssid_filter = filter; 101252726Srpaulo wpa_s->bssid_filter_count = count; 102252726Srpaulo 103252726Srpaulo return 0; 104252726Srpaulo} 105252726Srpaulo 106252726Srpaulo 107252726Srpaulostatic int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val) 108252726Srpaulo{ 109252726Srpaulo char *pos; 110252726Srpaulo u8 addr[ETH_ALEN], *bssid = NULL, *n; 111252726Srpaulo struct wpa_ssid_value *ssid = NULL, *ns; 112252726Srpaulo size_t count = 0, ssid_count = 0; 113252726Srpaulo struct wpa_ssid *c; 114252726Srpaulo 115252726Srpaulo /* 116281806Srpaulo * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | "" 117252726Srpaulo * SSID_SPEC ::= ssid <SSID_HEX> 118252726Srpaulo * BSSID_SPEC ::= bssid <BSSID_HEX> 119252726Srpaulo */ 120252726Srpaulo 121252726Srpaulo pos = val; 122252726Srpaulo while (pos) { 123252726Srpaulo if (*pos == '\0') 124252726Srpaulo break; 125252726Srpaulo if (os_strncmp(pos, "bssid ", 6) == 0) { 126252726Srpaulo int res; 127252726Srpaulo pos += 6; 128252726Srpaulo res = hwaddr_aton2(pos, addr); 129252726Srpaulo if (res < 0) { 130252726Srpaulo os_free(ssid); 131252726Srpaulo os_free(bssid); 132252726Srpaulo wpa_printf(MSG_DEBUG, "Invalid disallow_aps " 133252726Srpaulo "BSSID value '%s'", pos); 134252726Srpaulo return -1; 135252726Srpaulo } 136252726Srpaulo pos += res; 137252726Srpaulo n = os_realloc_array(bssid, count + 1, ETH_ALEN); 138252726Srpaulo if (n == NULL) { 139252726Srpaulo os_free(ssid); 140252726Srpaulo os_free(bssid); 141252726Srpaulo return -1; 142252726Srpaulo } 143252726Srpaulo bssid = n; 144252726Srpaulo os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN); 145252726Srpaulo count++; 146252726Srpaulo } else if (os_strncmp(pos, "ssid ", 5) == 0) { 147252726Srpaulo char *end; 148252726Srpaulo pos += 5; 149252726Srpaulo 150252726Srpaulo end = pos; 151252726Srpaulo while (*end) { 152252726Srpaulo if (*end == '\0' || *end == ' ') 153252726Srpaulo break; 154252726Srpaulo end++; 155252726Srpaulo } 156252726Srpaulo 157252726Srpaulo ns = os_realloc_array(ssid, ssid_count + 1, 158252726Srpaulo sizeof(struct wpa_ssid_value)); 159252726Srpaulo if (ns == NULL) { 160252726Srpaulo os_free(ssid); 161252726Srpaulo os_free(bssid); 162252726Srpaulo return -1; 163252726Srpaulo } 164252726Srpaulo ssid = ns; 165252726Srpaulo 166289549Srpaulo if ((end - pos) & 0x01 || 167289549Srpaulo end - pos > 2 * SSID_MAX_LEN || 168252726Srpaulo hexstr2bin(pos, ssid[ssid_count].ssid, 169252726Srpaulo (end - pos) / 2) < 0) { 170252726Srpaulo os_free(ssid); 171252726Srpaulo os_free(bssid); 172252726Srpaulo wpa_printf(MSG_DEBUG, "Invalid disallow_aps " 173252726Srpaulo "SSID value '%s'", pos); 174252726Srpaulo return -1; 175252726Srpaulo } 176252726Srpaulo ssid[ssid_count].ssid_len = (end - pos) / 2; 177252726Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID", 178252726Srpaulo ssid[ssid_count].ssid, 179252726Srpaulo ssid[ssid_count].ssid_len); 180252726Srpaulo ssid_count++; 181252726Srpaulo pos = end; 182252726Srpaulo } else { 183252726Srpaulo wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value " 184252726Srpaulo "'%s'", pos); 185252726Srpaulo os_free(ssid); 186252726Srpaulo os_free(bssid); 187252726Srpaulo return -1; 188252726Srpaulo } 189252726Srpaulo 190252726Srpaulo pos = os_strchr(pos, ' '); 191252726Srpaulo if (pos) 192252726Srpaulo pos++; 193252726Srpaulo } 194252726Srpaulo 195252726Srpaulo wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN); 196252726Srpaulo os_free(wpa_s->disallow_aps_bssid); 197252726Srpaulo wpa_s->disallow_aps_bssid = bssid; 198252726Srpaulo wpa_s->disallow_aps_bssid_count = count; 199252726Srpaulo 200252726Srpaulo wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count); 201252726Srpaulo os_free(wpa_s->disallow_aps_ssid); 202252726Srpaulo wpa_s->disallow_aps_ssid = ssid; 203252726Srpaulo wpa_s->disallow_aps_ssid_count = ssid_count; 204252726Srpaulo 205252726Srpaulo if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING) 206252726Srpaulo return 0; 207252726Srpaulo 208252726Srpaulo c = wpa_s->current_ssid; 209252726Srpaulo if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS) 210252726Srpaulo return 0; 211252726Srpaulo 212252726Srpaulo if (!disallowed_bssid(wpa_s, wpa_s->bssid) && 213252726Srpaulo !disallowed_ssid(wpa_s, c->ssid, c->ssid_len)) 214252726Srpaulo return 0; 215252726Srpaulo 216252726Srpaulo wpa_printf(MSG_DEBUG, "Disconnect and try to find another network " 217252726Srpaulo "because current AP was marked disallowed"); 218252726Srpaulo 219252726Srpaulo#ifdef CONFIG_SME 220252726Srpaulo wpa_s->sme.prev_bssid_set = 0; 221252726Srpaulo#endif /* CONFIG_SME */ 222252726Srpaulo wpa_s->reassociate = 1; 223281806Srpaulo wpa_s->own_disconnect_req = 1; 224252726Srpaulo wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 225252726Srpaulo wpa_supplicant_req_scan(wpa_s, 0, 0); 226252726Srpaulo 227252726Srpaulo return 0; 228252726Srpaulo} 229252726Srpaulo 230252726Srpaulo 231281806Srpaulo#ifndef CONFIG_NO_CONFIG_BLOBS 232281806Srpaulostatic int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos) 233281806Srpaulo{ 234281806Srpaulo char *name = pos; 235281806Srpaulo struct wpa_config_blob *blob; 236281806Srpaulo size_t len; 237281806Srpaulo 238281806Srpaulo pos = os_strchr(pos, ' '); 239281806Srpaulo if (pos == NULL) 240281806Srpaulo return -1; 241281806Srpaulo *pos++ = '\0'; 242281806Srpaulo len = os_strlen(pos); 243281806Srpaulo if (len & 1) 244281806Srpaulo return -1; 245281806Srpaulo 246281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name); 247281806Srpaulo blob = os_zalloc(sizeof(*blob)); 248281806Srpaulo if (blob == NULL) 249281806Srpaulo return -1; 250281806Srpaulo blob->name = os_strdup(name); 251281806Srpaulo blob->data = os_malloc(len / 2); 252281806Srpaulo if (blob->name == NULL || blob->data == NULL) { 253281806Srpaulo wpa_config_free_blob(blob); 254281806Srpaulo return -1; 255281806Srpaulo } 256281806Srpaulo 257281806Srpaulo if (hexstr2bin(pos, blob->data, len / 2) < 0) { 258281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data"); 259281806Srpaulo wpa_config_free_blob(blob); 260281806Srpaulo return -1; 261281806Srpaulo } 262281806Srpaulo blob->len = len / 2; 263281806Srpaulo 264281806Srpaulo wpa_config_set_blob(wpa_s->conf, blob); 265281806Srpaulo 266281806Srpaulo return 0; 267281806Srpaulo} 268281806Srpaulo#endif /* CONFIG_NO_CONFIG_BLOBS */ 269281806Srpaulo 270281806Srpaulo 271281806Srpaulostatic int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd) 272281806Srpaulo{ 273281806Srpaulo char *params; 274281806Srpaulo char *pos; 275281806Srpaulo int *freqs = NULL; 276281806Srpaulo int ret; 277281806Srpaulo 278281806Srpaulo if (atoi(cmd)) { 279281806Srpaulo params = os_strchr(cmd, ' '); 280281806Srpaulo os_free(wpa_s->manual_sched_scan_freqs); 281281806Srpaulo if (params) { 282281806Srpaulo params++; 283281806Srpaulo pos = os_strstr(params, "freq="); 284281806Srpaulo if (pos) 285281806Srpaulo freqs = freq_range_to_channel_list(wpa_s, 286281806Srpaulo pos + 5); 287281806Srpaulo } 288281806Srpaulo wpa_s->manual_sched_scan_freqs = freqs; 289281806Srpaulo ret = wpas_start_pno(wpa_s); 290281806Srpaulo } else { 291281806Srpaulo ret = wpas_stop_pno(wpa_s); 292281806Srpaulo } 293281806Srpaulo return ret; 294281806Srpaulo} 295281806Srpaulo 296281806Srpaulo 297289549Srpaulostatic int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) 298289549Srpaulo{ 299289549Srpaulo union wpa_event_data event; 300289549Srpaulo 301289549Srpaulo if (os_strcmp(band, "AUTO") == 0) 302289549Srpaulo wpa_s->setband = WPA_SETBAND_AUTO; 303289549Srpaulo else if (os_strcmp(band, "5G") == 0) 304289549Srpaulo wpa_s->setband = WPA_SETBAND_5G; 305289549Srpaulo else if (os_strcmp(band, "2G") == 0) 306289549Srpaulo wpa_s->setband = WPA_SETBAND_2G; 307289549Srpaulo else 308289549Srpaulo return -1; 309289549Srpaulo 310289549Srpaulo if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) { 311289549Srpaulo os_memset(&event, 0, sizeof(event)); 312289549Srpaulo event.channel_list_changed.initiator = REGDOM_SET_BY_USER; 313289549Srpaulo event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; 314289549Srpaulo wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event); 315289549Srpaulo } 316289549Srpaulo 317289549Srpaulo return 0; 318289549Srpaulo} 319289549Srpaulo 320289549Srpaulo 321337817Scystatic int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, 322337817Scy const char *cmd) 323337817Scy{ 324337817Scy struct wpabuf *lci; 325337817Scy 326337817Scy if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { 327337817Scy wpabuf_free(wpa_s->lci); 328337817Scy wpa_s->lci = NULL; 329337817Scy return 0; 330337817Scy } 331337817Scy 332337817Scy lci = wpabuf_parse_bin(cmd); 333337817Scy if (!lci) 334337817Scy return -1; 335337817Scy 336337817Scy if (os_get_reltime(&wpa_s->lci_time)) { 337337817Scy wpabuf_free(lci); 338337817Scy return -1; 339337817Scy } 340337817Scy 341337817Scy wpabuf_free(wpa_s->lci); 342337817Scy wpa_s->lci = lci; 343337817Scy 344337817Scy return 0; 345337817Scy} 346337817Scy 347337817Scy 348346981Scystatic int 349346981Scywpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd) 350346981Scy{ 351346981Scy int relative_rssi; 352346981Scy 353346981Scy if (os_strcmp(cmd, "disable") == 0) { 354346981Scy wpa_s->srp.relative_rssi_set = 0; 355346981Scy return 0; 356346981Scy } 357346981Scy 358346981Scy relative_rssi = atoi(cmd); 359346981Scy if (relative_rssi < 0 || relative_rssi > 100) 360346981Scy return -1; 361346981Scy wpa_s->srp.relative_rssi = relative_rssi; 362346981Scy wpa_s->srp.relative_rssi_set = 1; 363346981Scy return 0; 364346981Scy} 365346981Scy 366346981Scy 367346981Scystatic int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s, 368346981Scy const char *cmd) 369346981Scy{ 370346981Scy char *pos; 371346981Scy int adjust_rssi; 372346981Scy 373346981Scy /* <band>:adjust_value */ 374346981Scy pos = os_strchr(cmd, ':'); 375346981Scy if (!pos) 376346981Scy return -1; 377346981Scy pos++; 378346981Scy adjust_rssi = atoi(pos); 379346981Scy if (adjust_rssi < -100 || adjust_rssi > 100) 380346981Scy return -1; 381346981Scy 382346981Scy if (os_strncmp(cmd, "2G", 2) == 0) 383346981Scy wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G; 384346981Scy else if (os_strncmp(cmd, "5G", 2) == 0) 385346981Scy wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G; 386346981Scy else 387346981Scy return -1; 388346981Scy 389346981Scy wpa_s->srp.relative_adjust_rssi = adjust_rssi; 390346981Scy 391346981Scy return 0; 392346981Scy} 393346981Scy 394346981Scy 395346981Scystatic int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s, 396346981Scy const char *cmd) 397346981Scy{ 398346981Scy struct wpabuf *ric_ies; 399346981Scy 400346981Scy if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { 401346981Scy wpabuf_free(wpa_s->ric_ies); 402346981Scy wpa_s->ric_ies = NULL; 403346981Scy return 0; 404346981Scy } 405346981Scy 406346981Scy ric_ies = wpabuf_parse_bin(cmd); 407346981Scy if (!ric_ies) 408346981Scy return -1; 409346981Scy 410346981Scy wpabuf_free(wpa_s->ric_ies); 411346981Scy wpa_s->ric_ies = ric_ies; 412346981Scy 413346981Scy return 0; 414346981Scy} 415346981Scy 416346981Scy 417189251Ssamstatic int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, 418189251Ssam char *cmd) 419189251Ssam{ 420189251Ssam char *value; 421189251Ssam int ret = 0; 422189251Ssam 423189251Ssam value = os_strchr(cmd, ' '); 424189251Ssam if (value == NULL) 425189251Ssam return -1; 426189251Ssam *value++ = '\0'; 427189251Ssam 428189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); 429189251Ssam if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { 430189251Ssam eapol_sm_configure(wpa_s->eapol, 431189251Ssam atoi(value), -1, -1, -1); 432189251Ssam } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) { 433189251Ssam eapol_sm_configure(wpa_s->eapol, 434189251Ssam -1, atoi(value), -1, -1); 435189251Ssam } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) { 436189251Ssam eapol_sm_configure(wpa_s->eapol, 437189251Ssam -1, -1, atoi(value), -1); 438189251Ssam } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { 439189251Ssam eapol_sm_configure(wpa_s->eapol, 440189251Ssam -1, -1, -1, atoi(value)); 441189251Ssam } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { 442189251Ssam if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 443346981Scy atoi(value))) { 444189251Ssam ret = -1; 445346981Scy } else { 446346981Scy value[-1] = '='; 447346981Scy wpa_config_process_global(wpa_s->conf, cmd, -1); 448346981Scy } 449189251Ssam } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 450189251Ssam 0) { 451189251Ssam if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 452346981Scy atoi(value))) { 453189251Ssam ret = -1; 454346981Scy } else { 455346981Scy value[-1] = '='; 456346981Scy wpa_config_process_global(wpa_s->conf, cmd, -1); 457346981Scy } 458189251Ssam } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { 459346981Scy if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 460346981Scy atoi(value))) { 461189251Ssam ret = -1; 462346981Scy } else { 463346981Scy value[-1] = '='; 464346981Scy wpa_config_process_global(wpa_s->conf, cmd, -1); 465346981Scy } 466252726Srpaulo } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { 467252726Srpaulo wpa_s->wps_fragment_size = atoi(value); 468252726Srpaulo#ifdef CONFIG_WPS_TESTING 469252726Srpaulo } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { 470252726Srpaulo long int val; 471252726Srpaulo val = strtol(value, NULL, 0); 472252726Srpaulo if (val < 0 || val > 0xff) { 473252726Srpaulo ret = -1; 474252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid " 475252726Srpaulo "wps_version_number %ld", val); 476252726Srpaulo } else { 477252726Srpaulo wps_version_number = val; 478252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " 479252726Srpaulo "version %u.%u", 480252726Srpaulo (wps_version_number & 0xf0) >> 4, 481252726Srpaulo wps_version_number & 0x0f); 482252726Srpaulo } 483252726Srpaulo } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { 484252726Srpaulo wps_testing_dummy_cred = atoi(value); 485252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", 486252726Srpaulo wps_testing_dummy_cred); 487281806Srpaulo } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { 488281806Srpaulo wps_corrupt_pkhash = atoi(value); 489281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", 490281806Srpaulo wps_corrupt_pkhash); 491337817Scy } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) { 492337817Scy if (value[0] == '\0') { 493337817Scy wps_force_auth_types_in_use = 0; 494337817Scy } else { 495337817Scy wps_force_auth_types = strtol(value, NULL, 0); 496337817Scy wps_force_auth_types_in_use = 1; 497337817Scy } 498337817Scy } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) { 499337817Scy if (value[0] == '\0') { 500337817Scy wps_force_encr_types_in_use = 0; 501337817Scy } else { 502337817Scy wps_force_encr_types = strtol(value, NULL, 0); 503337817Scy wps_force_encr_types_in_use = 1; 504337817Scy } 505252726Srpaulo#endif /* CONFIG_WPS_TESTING */ 506252726Srpaulo } else if (os_strcasecmp(cmd, "ampdu") == 0) { 507252726Srpaulo if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) 508252726Srpaulo ret = -1; 509281806Srpaulo#ifdef CONFIG_TDLS 510252726Srpaulo#ifdef CONFIG_TDLS_TESTING 511252726Srpaulo } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { 512252726Srpaulo tdls_testing = strtol(value, NULL, 0); 513252726Srpaulo wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); 514252726Srpaulo#endif /* CONFIG_TDLS_TESTING */ 515252726Srpaulo } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) { 516252726Srpaulo int disabled = atoi(value); 517252726Srpaulo wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled); 518252726Srpaulo if (disabled) { 519252726Srpaulo if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0) 520252726Srpaulo ret = -1; 521252726Srpaulo } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0) 522252726Srpaulo ret = -1; 523252726Srpaulo wpa_tdls_enable(wpa_s->wpa, !disabled); 524252726Srpaulo#endif /* CONFIG_TDLS */ 525252726Srpaulo } else if (os_strcasecmp(cmd, "pno") == 0) { 526281806Srpaulo ret = wpas_ctrl_pno(wpa_s, value); 527252726Srpaulo } else if (os_strcasecmp(cmd, "radio_disabled") == 0) { 528252726Srpaulo int disabled = atoi(value); 529252726Srpaulo if (wpa_drv_radio_disable(wpa_s, disabled) < 0) 530252726Srpaulo ret = -1; 531252726Srpaulo else if (disabled) 532252726Srpaulo wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 533252726Srpaulo } else if (os_strcasecmp(cmd, "uapsd") == 0) { 534252726Srpaulo if (os_strcmp(value, "disable") == 0) 535252726Srpaulo wpa_s->set_sta_uapsd = 0; 536252726Srpaulo else { 537252726Srpaulo int be, bk, vi, vo; 538252726Srpaulo char *pos; 539252726Srpaulo /* format: BE,BK,VI,VO;max SP Length */ 540252726Srpaulo be = atoi(value); 541252726Srpaulo pos = os_strchr(value, ','); 542252726Srpaulo if (pos == NULL) 543252726Srpaulo return -1; 544252726Srpaulo pos++; 545252726Srpaulo bk = atoi(pos); 546252726Srpaulo pos = os_strchr(pos, ','); 547252726Srpaulo if (pos == NULL) 548252726Srpaulo return -1; 549252726Srpaulo pos++; 550252726Srpaulo vi = atoi(pos); 551252726Srpaulo pos = os_strchr(pos, ','); 552252726Srpaulo if (pos == NULL) 553252726Srpaulo return -1; 554252726Srpaulo pos++; 555252726Srpaulo vo = atoi(pos); 556252726Srpaulo /* ignore max SP Length for now */ 557189251Ssam 558252726Srpaulo wpa_s->set_sta_uapsd = 1; 559252726Srpaulo wpa_s->sta_uapsd = 0; 560252726Srpaulo if (be) 561252726Srpaulo wpa_s->sta_uapsd |= BIT(0); 562252726Srpaulo if (bk) 563252726Srpaulo wpa_s->sta_uapsd |= BIT(1); 564252726Srpaulo if (vi) 565252726Srpaulo wpa_s->sta_uapsd |= BIT(2); 566252726Srpaulo if (vo) 567252726Srpaulo wpa_s->sta_uapsd |= BIT(3); 568252726Srpaulo } 569252726Srpaulo } else if (os_strcasecmp(cmd, "ps") == 0) { 570252726Srpaulo ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1); 571252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY 572252726Srpaulo } else if (os_strcasecmp(cmd, "wifi_display") == 0) { 573281806Srpaulo int enabled = !!atoi(value); 574281806Srpaulo if (enabled && !wpa_s->global->p2p) 575281806Srpaulo ret = -1; 576281806Srpaulo else 577281806Srpaulo wifi_display_enable(wpa_s->global, enabled); 578252726Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 579252726Srpaulo } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { 580252726Srpaulo ret = set_bssid_filter(wpa_s, value); 581252726Srpaulo } else if (os_strcasecmp(cmd, "disallow_aps") == 0) { 582252726Srpaulo ret = set_disallow_aps(wpa_s, value); 583252726Srpaulo } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) { 584252726Srpaulo wpa_s->no_keep_alive = !!atoi(value); 585346981Scy#ifdef CONFIG_DPP 586346981Scy } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { 587346981Scy os_free(wpa_s->dpp_configurator_params); 588346981Scy wpa_s->dpp_configurator_params = os_strdup(value); 589346981Scy } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { 590346981Scy wpa_s->dpp_init_max_tries = atoi(value); 591346981Scy } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { 592346981Scy wpa_s->dpp_init_retry_time = atoi(value); 593346981Scy } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) { 594346981Scy wpa_s->dpp_resp_wait_time = atoi(value); 595346981Scy } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) { 596346981Scy wpa_s->dpp_resp_max_tries = atoi(value); 597346981Scy } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) { 598346981Scy wpa_s->dpp_resp_retry_time = atoi(value); 599281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 600346981Scy } else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) { 601346981Scy if (hwaddr_aton(value, dpp_pkex_own_mac_override)) 602346981Scy ret = -1; 603346981Scy } else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) { 604346981Scy if (hwaddr_aton(value, dpp_pkex_peer_mac_override)) 605346981Scy ret = -1; 606346981Scy } else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) { 607346981Scy size_t hex_len = os_strlen(value); 608346981Scy 609346981Scy if (hex_len > 610346981Scy 2 * sizeof(dpp_pkex_ephemeral_key_override)) 611346981Scy ret = -1; 612346981Scy else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override, 613346981Scy hex_len / 2)) 614346981Scy ret = -1; 615346981Scy else 616346981Scy dpp_pkex_ephemeral_key_override_len = hex_len / 2; 617346981Scy } else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) { 618346981Scy size_t hex_len = os_strlen(value); 619346981Scy 620346981Scy if (hex_len > 2 * sizeof(dpp_protocol_key_override)) 621346981Scy ret = -1; 622346981Scy else if (hexstr2bin(value, dpp_protocol_key_override, 623346981Scy hex_len / 2)) 624346981Scy ret = -1; 625346981Scy else 626346981Scy dpp_protocol_key_override_len = hex_len / 2; 627346981Scy } else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) { 628346981Scy size_t hex_len = os_strlen(value); 629346981Scy 630346981Scy if (hex_len > 2 * sizeof(dpp_nonce_override)) 631346981Scy ret = -1; 632346981Scy else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2)) 633346981Scy ret = -1; 634346981Scy else 635346981Scy dpp_nonce_override_len = hex_len / 2; 636346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 637346981Scy#endif /* CONFIG_DPP */ 638346981Scy#ifdef CONFIG_TESTING_OPTIONS 639281806Srpaulo } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { 640281806Srpaulo wpa_s->ext_mgmt_frame_handling = !!atoi(value); 641281806Srpaulo } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { 642281806Srpaulo wpa_s->ext_eapol_frame_io = !!atoi(value); 643281806Srpaulo#ifdef CONFIG_AP 644281806Srpaulo if (wpa_s->ap_iface) { 645281806Srpaulo wpa_s->ap_iface->bss[0]->ext_eapol_frame_io = 646281806Srpaulo wpa_s->ext_eapol_frame_io; 647281806Srpaulo } 648281806Srpaulo#endif /* CONFIG_AP */ 649281806Srpaulo } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) { 650281806Srpaulo wpa_s->extra_roc_dur = atoi(value); 651281806Srpaulo } else if (os_strcasecmp(cmd, "test_failure") == 0) { 652281806Srpaulo wpa_s->test_failure = atoi(value); 653337817Scy } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) { 654337817Scy wpa_s->p2p_go_csa_on_inv = !!atoi(value); 655337817Scy } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) { 656337817Scy wpa_s->ignore_auth_resp = !!atoi(value); 657337817Scy } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { 658337817Scy wpa_s->ignore_assoc_disallow = !!atoi(value); 659346981Scy wpa_drv_ignore_assoc_disallow(wpa_s, 660346981Scy wpa_s->ignore_assoc_disallow); 661337817Scy } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) { 662337817Scy wpa_s->reject_btm_req_reason = atoi(value); 663346981Scy } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) { 664346981Scy os_free(wpa_s->get_pref_freq_list_override); 665346981Scy if (!value[0]) 666346981Scy wpa_s->get_pref_freq_list_override = NULL; 667346981Scy else 668346981Scy wpa_s->get_pref_freq_list_override = os_strdup(value); 669346981Scy } else if (os_strcasecmp(cmd, "sae_commit_override") == 0) { 670346981Scy wpabuf_free(wpa_s->sae_commit_override); 671346981Scy if (value[0] == '\0') 672346981Scy wpa_s->sae_commit_override = NULL; 673346981Scy else 674346981Scy wpa_s->sae_commit_override = wpabuf_parse_bin(value); 675346981Scy#ifdef CONFIG_DPP 676346981Scy } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { 677346981Scy os_free(wpa_s->dpp_config_obj_override); 678346981Scy if (value[0] == '\0') 679346981Scy wpa_s->dpp_config_obj_override = NULL; 680346981Scy else 681346981Scy wpa_s->dpp_config_obj_override = os_strdup(value); 682346981Scy } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) { 683346981Scy os_free(wpa_s->dpp_discovery_override); 684346981Scy if (value[0] == '\0') 685346981Scy wpa_s->dpp_discovery_override = NULL; 686346981Scy else 687346981Scy wpa_s->dpp_discovery_override = os_strdup(value); 688346981Scy } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) { 689346981Scy os_free(wpa_s->dpp_groups_override); 690346981Scy if (value[0] == '\0') 691346981Scy wpa_s->dpp_groups_override = NULL; 692346981Scy else 693346981Scy wpa_s->dpp_groups_override = os_strdup(value); 694346981Scy } else if (os_strcasecmp(cmd, 695346981Scy "dpp_ignore_netaccesskey_mismatch") == 0) { 696346981Scy wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value); 697346981Scy } else if (os_strcasecmp(cmd, "dpp_test") == 0) { 698346981Scy dpp_test = atoi(value); 699346981Scy#endif /* CONFIG_DPP */ 700281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 701346981Scy#ifdef CONFIG_FILS 702346981Scy } else if (os_strcasecmp(cmd, "disable_fils") == 0) { 703346981Scy wpa_s->disable_fils = !!atoi(value); 704346981Scy wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils); 705346981Scy wpa_supplicant_set_default_scan_ies(wpa_s); 706346981Scy#endif /* CONFIG_FILS */ 707281806Srpaulo#ifndef CONFIG_NO_CONFIG_BLOBS 708281806Srpaulo } else if (os_strcmp(cmd, "blob") == 0) { 709281806Srpaulo ret = wpas_ctrl_set_blob(wpa_s, value); 710281806Srpaulo#endif /* CONFIG_NO_CONFIG_BLOBS */ 711281806Srpaulo } else if (os_strcasecmp(cmd, "setband") == 0) { 712289549Srpaulo ret = wpas_ctrl_set_band(wpa_s, value); 713337817Scy#ifdef CONFIG_MBO 714337817Scy } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { 715337817Scy ret = wpas_mbo_update_non_pref_chan(wpa_s, value); 716346981Scy if (ret == 0) { 717346981Scy value[-1] = '='; 718346981Scy wpa_config_process_global(wpa_s->conf, cmd, -1); 719346981Scy } 720337817Scy } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { 721337817Scy wpas_mbo_update_cell_capa(wpa_s, atoi(value)); 722346981Scy } else if (os_strcasecmp(cmd, "oce") == 0) { 723346981Scy wpa_s->conf->oce = atoi(value); 724346981Scy if (wpa_s->conf->oce) { 725346981Scy if ((wpa_s->conf->oce & OCE_STA) && 726346981Scy (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA)) 727346981Scy wpa_s->enable_oce = OCE_STA; 728346981Scy 729346981Scy if ((wpa_s->conf->oce & OCE_STA_CFON) && 730346981Scy (wpa_s->drv_flags & 731346981Scy WPA_DRIVER_FLAGS_OCE_STA_CFON)) { 732346981Scy /* TODO: Need to add STA-CFON support */ 733346981Scy wpa_printf(MSG_ERROR, 734346981Scy "OCE STA-CFON feature is not yet supported"); 735346981Scy return -1; 736346981Scy } 737346981Scy } else { 738346981Scy wpa_s->enable_oce = 0; 739346981Scy } 740346981Scy wpa_supplicant_set_default_scan_ies(wpa_s); 741337817Scy#endif /* CONFIG_MBO */ 742337817Scy } else if (os_strcasecmp(cmd, "lci") == 0) { 743337817Scy ret = wpas_ctrl_iface_set_lci(wpa_s, value); 744346981Scy } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) { 745346981Scy ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value)); 746346981Scy } else if (os_strcasecmp(cmd, "relative_rssi") == 0) { 747346981Scy ret = wpas_ctrl_set_relative_rssi(wpa_s, value); 748346981Scy } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) { 749346981Scy ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value); 750346981Scy } else if (os_strcasecmp(cmd, "ric_ies") == 0) { 751346981Scy ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value); 752346981Scy } else if (os_strcasecmp(cmd, "roaming") == 0) { 753346981Scy ret = wpa_drv_roaming(wpa_s, atoi(value), NULL); 754346981Scy#ifdef CONFIG_WNM 755346981Scy } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) { 756346981Scy struct wpabuf *elems; 757346981Scy 758346981Scy elems = wpabuf_parse_bin(value); 759346981Scy if (!elems) 760346981Scy return -1; 761346981Scy wnm_set_coloc_intf_elems(wpa_s, elems); 762346981Scy#endif /* CONFIG_WNM */ 763252726Srpaulo } else { 764252726Srpaulo value[-1] = '='; 765252726Srpaulo ret = wpa_config_process_global(wpa_s->conf, cmd, -1); 766252726Srpaulo if (ret == 0) 767252726Srpaulo wpa_supplicant_update_config(wpa_s); 768252726Srpaulo } 769252726Srpaulo 770189251Ssam return ret; 771189251Ssam} 772189251Ssam 773189251Ssam 774252726Srpaulostatic int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, 775252726Srpaulo char *cmd, char *buf, size_t buflen) 776252726Srpaulo{ 777252726Srpaulo int res = -1; 778252726Srpaulo 779252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); 780252726Srpaulo 781252726Srpaulo if (os_strcmp(cmd, "version") == 0) { 782252726Srpaulo res = os_snprintf(buf, buflen, "%s", VERSION_STR); 783252726Srpaulo } else if (os_strcasecmp(cmd, "country") == 0) { 784252726Srpaulo if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) 785252726Srpaulo res = os_snprintf(buf, buflen, "%c%c", 786252726Srpaulo wpa_s->conf->country[0], 787252726Srpaulo wpa_s->conf->country[1]); 788252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY 789252726Srpaulo } else if (os_strcasecmp(cmd, "wifi_display") == 0) { 790281806Srpaulo int enabled; 791281806Srpaulo if (wpa_s->global->p2p == NULL || 792281806Srpaulo wpa_s->global->p2p_disabled) 793281806Srpaulo enabled = 0; 794281806Srpaulo else 795281806Srpaulo enabled = wpa_s->global->wifi_display; 796281806Srpaulo res = os_snprintf(buf, buflen, "%d", enabled); 797281806Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 798281806Srpaulo#ifdef CONFIG_TESTING_GET_GTK 799281806Srpaulo } else if (os_strcmp(cmd, "gtk") == 0) { 800281806Srpaulo if (wpa_s->last_gtk_len == 0) 801252726Srpaulo return -1; 802281806Srpaulo res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk, 803281806Srpaulo wpa_s->last_gtk_len); 804252726Srpaulo return res; 805281806Srpaulo#endif /* CONFIG_TESTING_GET_GTK */ 806281806Srpaulo } else if (os_strcmp(cmd, "tls_library") == 0) { 807281806Srpaulo res = tls_get_library_version(buf, buflen); 808346981Scy#ifdef CONFIG_TESTING_OPTIONS 809346981Scy } else if (os_strcmp(cmd, "anonce") == 0) { 810346981Scy return wpa_snprintf_hex(buf, buflen, 811346981Scy wpa_sm_get_anonce(wpa_s->wpa), 812346981Scy WPA_NONCE_LEN); 813346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 814281806Srpaulo } else { 815281806Srpaulo res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen); 816252726Srpaulo } 817252726Srpaulo 818281806Srpaulo if (os_snprintf_error(buflen, res)) 819252726Srpaulo return -1; 820252726Srpaulo return res; 821252726Srpaulo} 822252726Srpaulo 823252726Srpaulo 824189251Ssam#ifdef IEEE8021X_EAPOL 825189251Ssamstatic int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, 826189251Ssam char *addr) 827189251Ssam{ 828189251Ssam u8 bssid[ETH_ALEN]; 829189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 830189251Ssam 831189251Ssam if (hwaddr_aton(addr, bssid)) { 832189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address " 833189251Ssam "'%s'", addr); 834189251Ssam return -1; 835189251Ssam } 836189251Ssam 837189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid)); 838189251Ssam rsn_preauth_deinit(wpa_s->wpa); 839189251Ssam if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL)) 840189251Ssam return -1; 841189251Ssam 842189251Ssam return 0; 843189251Ssam} 844189251Ssam#endif /* IEEE8021X_EAPOL */ 845189251Ssam 846189251Ssam 847252726Srpaulo#ifdef CONFIG_TDLS 848252726Srpaulo 849252726Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_discover( 850252726Srpaulo struct wpa_supplicant *wpa_s, char *addr) 851252726Srpaulo{ 852252726Srpaulo u8 peer[ETH_ALEN]; 853252726Srpaulo int ret; 854252726Srpaulo 855252726Srpaulo if (hwaddr_aton(addr, peer)) { 856252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid " 857252726Srpaulo "address '%s'", addr); 858252726Srpaulo return -1; 859252726Srpaulo } 860252726Srpaulo 861252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR, 862252726Srpaulo MAC2STR(peer)); 863252726Srpaulo 864252726Srpaulo if (wpa_tdls_is_external_setup(wpa_s->wpa)) 865252726Srpaulo ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); 866252726Srpaulo else 867252726Srpaulo ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); 868252726Srpaulo 869252726Srpaulo return ret; 870252726Srpaulo} 871252726Srpaulo 872252726Srpaulo 873252726Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_setup( 874252726Srpaulo struct wpa_supplicant *wpa_s, char *addr) 875252726Srpaulo{ 876252726Srpaulo u8 peer[ETH_ALEN]; 877252726Srpaulo int ret; 878252726Srpaulo 879252726Srpaulo if (hwaddr_aton(addr, peer)) { 880252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid " 881252726Srpaulo "address '%s'", addr); 882252726Srpaulo return -1; 883252726Srpaulo } 884252726Srpaulo 885252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR, 886252726Srpaulo MAC2STR(peer)); 887252726Srpaulo 888281806Srpaulo if ((wpa_s->conf->tdls_external_control) && 889281806Srpaulo wpa_tdls_is_external_setup(wpa_s->wpa)) 890281806Srpaulo return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); 891252726Srpaulo 892281806Srpaulo wpa_tdls_remove(wpa_s->wpa, peer); 893281806Srpaulo 894281806Srpaulo if (wpa_tdls_is_external_setup(wpa_s->wpa)) 895281806Srpaulo ret = wpa_tdls_start(wpa_s->wpa, peer); 896281806Srpaulo else 897281806Srpaulo ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); 898281806Srpaulo 899252726Srpaulo return ret; 900252726Srpaulo} 901252726Srpaulo 902252726Srpaulo 903252726Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_teardown( 904252726Srpaulo struct wpa_supplicant *wpa_s, char *addr) 905252726Srpaulo{ 906252726Srpaulo u8 peer[ETH_ALEN]; 907281806Srpaulo int ret; 908252726Srpaulo 909281806Srpaulo if (os_strcmp(addr, "*") == 0) { 910281806Srpaulo /* remove everyone */ 911281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *"); 912281806Srpaulo wpa_tdls_teardown_peers(wpa_s->wpa); 913281806Srpaulo return 0; 914281806Srpaulo } 915281806Srpaulo 916252726Srpaulo if (hwaddr_aton(addr, peer)) { 917252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid " 918252726Srpaulo "address '%s'", addr); 919252726Srpaulo return -1; 920252726Srpaulo } 921252726Srpaulo 922252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR, 923252726Srpaulo MAC2STR(peer)); 924252726Srpaulo 925281806Srpaulo if ((wpa_s->conf->tdls_external_control) && 926281806Srpaulo wpa_tdls_is_external_setup(wpa_s->wpa)) 927281806Srpaulo return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); 928281806Srpaulo 929281806Srpaulo if (wpa_tdls_is_external_setup(wpa_s->wpa)) 930281806Srpaulo ret = wpa_tdls_teardown_link( 931281806Srpaulo wpa_s->wpa, peer, 932281806Srpaulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 933281806Srpaulo else 934281806Srpaulo ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); 935281806Srpaulo 936281806Srpaulo return ret; 937252726Srpaulo} 938252726Srpaulo 939281806Srpaulo 940281806Srpaulostatic int ctrl_iface_get_capability_tdls( 941281806Srpaulo struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 942281806Srpaulo{ 943281806Srpaulo int ret; 944281806Srpaulo 945281806Srpaulo ret = os_snprintf(buf, buflen, "%s\n", 946281806Srpaulo wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ? 947281806Srpaulo (wpa_s->drv_flags & 948281806Srpaulo WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ? 949281806Srpaulo "EXTERNAL" : "INTERNAL") : "UNSUPPORTED"); 950281806Srpaulo if (os_snprintf_error(buflen, ret)) 951281806Srpaulo return -1; 952281806Srpaulo return ret; 953281806Srpaulo} 954281806Srpaulo 955281806Srpaulo 956281806Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_chan_switch( 957281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 958281806Srpaulo{ 959281806Srpaulo u8 peer[ETH_ALEN]; 960281806Srpaulo struct hostapd_freq_params freq_params; 961281806Srpaulo u8 oper_class; 962281806Srpaulo char *pos, *end; 963281806Srpaulo 964281806Srpaulo if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { 965281806Srpaulo wpa_printf(MSG_INFO, 966281806Srpaulo "tdls_chanswitch: Only supported with external setup"); 967281806Srpaulo return -1; 968281806Srpaulo } 969281806Srpaulo 970281806Srpaulo os_memset(&freq_params, 0, sizeof(freq_params)); 971281806Srpaulo 972281806Srpaulo pos = os_strchr(cmd, ' '); 973281806Srpaulo if (pos == NULL) 974281806Srpaulo return -1; 975281806Srpaulo *pos++ = '\0'; 976281806Srpaulo 977281806Srpaulo oper_class = strtol(pos, &end, 10); 978281806Srpaulo if (pos == end) { 979281806Srpaulo wpa_printf(MSG_INFO, 980281806Srpaulo "tdls_chanswitch: Invalid op class provided"); 981281806Srpaulo return -1; 982281806Srpaulo } 983281806Srpaulo 984281806Srpaulo pos = end; 985281806Srpaulo freq_params.freq = atoi(pos); 986281806Srpaulo if (freq_params.freq == 0) { 987281806Srpaulo wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided"); 988281806Srpaulo return -1; 989281806Srpaulo } 990281806Srpaulo 991281806Srpaulo#define SET_FREQ_SETTING(str) \ 992281806Srpaulo do { \ 993281806Srpaulo const char *pos2 = os_strstr(pos, " " #str "="); \ 994281806Srpaulo if (pos2) { \ 995281806Srpaulo pos2 += sizeof(" " #str "=") - 1; \ 996281806Srpaulo freq_params.str = atoi(pos2); \ 997281806Srpaulo } \ 998281806Srpaulo } while (0) 999281806Srpaulo 1000281806Srpaulo SET_FREQ_SETTING(center_freq1); 1001281806Srpaulo SET_FREQ_SETTING(center_freq2); 1002281806Srpaulo SET_FREQ_SETTING(bandwidth); 1003281806Srpaulo SET_FREQ_SETTING(sec_channel_offset); 1004281806Srpaulo#undef SET_FREQ_SETTING 1005281806Srpaulo 1006281806Srpaulo freq_params.ht_enabled = !!os_strstr(pos, " ht"); 1007281806Srpaulo freq_params.vht_enabled = !!os_strstr(pos, " vht"); 1008281806Srpaulo 1009281806Srpaulo if (hwaddr_aton(cmd, peer)) { 1010281806Srpaulo wpa_printf(MSG_DEBUG, 1011281806Srpaulo "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'", 1012281806Srpaulo cmd); 1013281806Srpaulo return -1; 1014281806Srpaulo } 1015281806Srpaulo 1016281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR 1017281806Srpaulo " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s", 1018281806Srpaulo MAC2STR(peer), oper_class, freq_params.freq, 1019281806Srpaulo freq_params.center_freq1, freq_params.center_freq2, 1020281806Srpaulo freq_params.bandwidth, freq_params.sec_channel_offset, 1021281806Srpaulo freq_params.ht_enabled ? " HT" : "", 1022281806Srpaulo freq_params.vht_enabled ? " VHT" : ""); 1023281806Srpaulo 1024281806Srpaulo return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class, 1025281806Srpaulo &freq_params); 1026281806Srpaulo} 1027281806Srpaulo 1028281806Srpaulo 1029281806Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch( 1030281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 1031281806Srpaulo{ 1032281806Srpaulo u8 peer[ETH_ALEN]; 1033281806Srpaulo 1034281806Srpaulo if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { 1035281806Srpaulo wpa_printf(MSG_INFO, 1036281806Srpaulo "tdls_chanswitch: Only supported with external setup"); 1037281806Srpaulo return -1; 1038281806Srpaulo } 1039281806Srpaulo 1040281806Srpaulo if (hwaddr_aton(cmd, peer)) { 1041281806Srpaulo wpa_printf(MSG_DEBUG, 1042281806Srpaulo "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'", 1043281806Srpaulo cmd); 1044281806Srpaulo return -1; 1045281806Srpaulo } 1046281806Srpaulo 1047281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR, 1048281806Srpaulo MAC2STR(peer)); 1049281806Srpaulo 1050281806Srpaulo return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer); 1051281806Srpaulo} 1052281806Srpaulo 1053289549Srpaulo 1054289549Srpaulostatic int wpa_supplicant_ctrl_iface_tdls_link_status( 1055289549Srpaulo struct wpa_supplicant *wpa_s, const char *addr, 1056289549Srpaulo char *buf, size_t buflen) 1057289549Srpaulo{ 1058289549Srpaulo u8 peer[ETH_ALEN]; 1059289549Srpaulo const char *tdls_status; 1060289549Srpaulo int ret; 1061289549Srpaulo 1062289549Srpaulo if (hwaddr_aton(addr, peer)) { 1063289549Srpaulo wpa_printf(MSG_DEBUG, 1064289549Srpaulo "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'", 1065289549Srpaulo addr); 1066289549Srpaulo return -1; 1067289549Srpaulo } 1068289549Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR, 1069289549Srpaulo MAC2STR(peer)); 1070289549Srpaulo 1071289549Srpaulo tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); 1072289549Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status); 1073289549Srpaulo ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status); 1074289549Srpaulo if (os_snprintf_error(buflen, ret)) 1075289549Srpaulo return -1; 1076289549Srpaulo 1077289549Srpaulo return ret; 1078289549Srpaulo} 1079289549Srpaulo 1080252726Srpaulo#endif /* CONFIG_TDLS */ 1081252726Srpaulo 1082252726Srpaulo 1083281806Srpaulostatic int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd) 1084281806Srpaulo{ 1085281806Srpaulo char *token, *context = NULL; 1086281806Srpaulo struct wmm_ac_ts_setup_params params = { 1087281806Srpaulo .tsid = 0xff, 1088281806Srpaulo .direction = 0xff, 1089281806Srpaulo }; 1090281806Srpaulo 1091281806Srpaulo while ((token = str_token(cmd, " ", &context))) { 1092281806Srpaulo if (sscanf(token, "tsid=%i", ¶ms.tsid) == 1 || 1093281806Srpaulo sscanf(token, "up=%i", ¶ms.user_priority) == 1 || 1094281806Srpaulo sscanf(token, "nominal_msdu_size=%i", 1095281806Srpaulo ¶ms.nominal_msdu_size) == 1 || 1096281806Srpaulo sscanf(token, "mean_data_rate=%i", 1097281806Srpaulo ¶ms.mean_data_rate) == 1 || 1098281806Srpaulo sscanf(token, "min_phy_rate=%i", 1099281806Srpaulo ¶ms.minimum_phy_rate) == 1 || 1100281806Srpaulo sscanf(token, "sba=%i", 1101281806Srpaulo ¶ms.surplus_bandwidth_allowance) == 1) 1102281806Srpaulo continue; 1103281806Srpaulo 1104281806Srpaulo if (os_strcasecmp(token, "downlink") == 0) { 1105281806Srpaulo params.direction = WMM_TSPEC_DIRECTION_DOWNLINK; 1106281806Srpaulo } else if (os_strcasecmp(token, "uplink") == 0) { 1107281806Srpaulo params.direction = WMM_TSPEC_DIRECTION_UPLINK; 1108281806Srpaulo } else if (os_strcasecmp(token, "bidi") == 0) { 1109281806Srpaulo params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL; 1110281806Srpaulo } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) { 1111281806Srpaulo params.fixed_nominal_msdu = 1; 1112281806Srpaulo } else { 1113281806Srpaulo wpa_printf(MSG_DEBUG, 1114281806Srpaulo "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'", 1115281806Srpaulo token); 1116281806Srpaulo return -1; 1117281806Srpaulo } 1118281806Srpaulo 1119281806Srpaulo } 1120281806Srpaulo 1121281806Srpaulo return wpas_wmm_ac_addts(wpa_s, ¶ms); 1122281806Srpaulo} 1123281806Srpaulo 1124281806Srpaulo 1125281806Srpaulostatic int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd) 1126281806Srpaulo{ 1127281806Srpaulo u8 tsid = atoi(cmd); 1128281806Srpaulo 1129281806Srpaulo return wpas_wmm_ac_delts(wpa_s, tsid); 1130281806Srpaulo} 1131281806Srpaulo 1132281806Srpaulo 1133189251Ssam#ifdef CONFIG_IEEE80211R 1134189251Ssamstatic int wpa_supplicant_ctrl_iface_ft_ds( 1135189251Ssam struct wpa_supplicant *wpa_s, char *addr) 1136189251Ssam{ 1137189251Ssam u8 target_ap[ETH_ALEN]; 1138214734Srpaulo struct wpa_bss *bss; 1139214734Srpaulo const u8 *mdie; 1140189251Ssam 1141189251Ssam if (hwaddr_aton(addr, target_ap)) { 1142189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid " 1143214734Srpaulo "address '%s'", addr); 1144189251Ssam return -1; 1145189251Ssam } 1146189251Ssam 1147189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap)); 1148189251Ssam 1149214734Srpaulo bss = wpa_bss_get_bssid(wpa_s, target_ap); 1150214734Srpaulo if (bss) 1151214734Srpaulo mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); 1152214734Srpaulo else 1153214734Srpaulo mdie = NULL; 1154214734Srpaulo 1155214734Srpaulo return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie); 1156189251Ssam} 1157189251Ssam#endif /* CONFIG_IEEE80211R */ 1158189251Ssam 1159189251Ssam 1160189251Ssam#ifdef CONFIG_WPS 1161189251Ssamstatic int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, 1162189251Ssam char *cmd) 1163189251Ssam{ 1164214734Srpaulo u8 bssid[ETH_ALEN], *_bssid = bssid; 1165252726Srpaulo#ifdef CONFIG_P2P 1166252726Srpaulo u8 p2p_dev_addr[ETH_ALEN]; 1167252726Srpaulo#endif /* CONFIG_P2P */ 1168252726Srpaulo#ifdef CONFIG_AP 1169252726Srpaulo u8 *_p2p_dev_addr = NULL; 1170252726Srpaulo#endif /* CONFIG_AP */ 1171346981Scy char *pos; 1172346981Scy int multi_ap = 0; 1173189251Ssam 1174346981Scy if (!cmd || os_strcmp(cmd, "any") == 0 || 1175346981Scy os_strncmp(cmd, "any ", 4) == 0) { 1176214734Srpaulo _bssid = NULL; 1177252726Srpaulo#ifdef CONFIG_P2P 1178252726Srpaulo } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { 1179252726Srpaulo if (hwaddr_aton(cmd + 13, p2p_dev_addr)) { 1180252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid " 1181252726Srpaulo "P2P Device Address '%s'", 1182252726Srpaulo cmd + 13); 1183252726Srpaulo return -1; 1184252726Srpaulo } 1185252726Srpaulo _p2p_dev_addr = p2p_dev_addr; 1186252726Srpaulo#endif /* CONFIG_P2P */ 1187346981Scy } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) { 1188346981Scy _bssid = NULL; 1189346981Scy multi_ap = atoi(cmd + 9); 1190252726Srpaulo } else if (hwaddr_aton(cmd, bssid)) { 1191189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", 1192189251Ssam cmd); 1193189251Ssam return -1; 1194189251Ssam } 1195189251Ssam 1196346981Scy if (cmd) { 1197346981Scy pos = os_strstr(cmd, " multi_ap="); 1198346981Scy if (pos) { 1199346981Scy pos += 10; 1200346981Scy multi_ap = atoi(pos); 1201346981Scy } 1202346981Scy } 1203346981Scy 1204214734Srpaulo#ifdef CONFIG_AP 1205214734Srpaulo if (wpa_s->ap_iface) 1206252726Srpaulo return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); 1207214734Srpaulo#endif /* CONFIG_AP */ 1208214734Srpaulo 1209346981Scy return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap); 1210189251Ssam} 1211189251Ssam 1212189251Ssam 1213189251Ssamstatic int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, 1214189251Ssam char *cmd, char *buf, 1215189251Ssam size_t buflen) 1216189251Ssam{ 1217189251Ssam u8 bssid[ETH_ALEN], *_bssid = bssid; 1218189251Ssam char *pin; 1219189251Ssam int ret; 1220189251Ssam 1221189251Ssam pin = os_strchr(cmd, ' '); 1222189251Ssam if (pin) 1223189251Ssam *pin++ = '\0'; 1224189251Ssam 1225189251Ssam if (os_strcmp(cmd, "any") == 0) 1226189251Ssam _bssid = NULL; 1227252726Srpaulo else if (os_strcmp(cmd, "get") == 0) { 1228337817Scy if (wps_generate_pin((unsigned int *) &ret) < 0) 1229337817Scy return -1; 1230252726Srpaulo goto done; 1231252726Srpaulo } else if (hwaddr_aton(cmd, bssid)) { 1232189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", 1233189251Ssam cmd); 1234189251Ssam return -1; 1235189251Ssam } 1236189251Ssam 1237214734Srpaulo#ifdef CONFIG_AP 1238252726Srpaulo if (wpa_s->ap_iface) { 1239252726Srpaulo int timeout = 0; 1240252726Srpaulo char *pos; 1241252726Srpaulo 1242252726Srpaulo if (pin) { 1243252726Srpaulo pos = os_strchr(pin, ' '); 1244252726Srpaulo if (pos) { 1245252726Srpaulo *pos++ = '\0'; 1246252726Srpaulo timeout = atoi(pos); 1247252726Srpaulo } 1248252726Srpaulo } 1249252726Srpaulo 1250214734Srpaulo return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin, 1251252726Srpaulo buf, buflen, timeout); 1252252726Srpaulo } 1253214734Srpaulo#endif /* CONFIG_AP */ 1254214734Srpaulo 1255189251Ssam if (pin) { 1256252726Srpaulo ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, 1257252726Srpaulo DEV_PW_DEFAULT); 1258189251Ssam if (ret < 0) 1259189251Ssam return -1; 1260189251Ssam ret = os_snprintf(buf, buflen, "%s", pin); 1261281806Srpaulo if (os_snprintf_error(buflen, ret)) 1262189251Ssam return -1; 1263189251Ssam return ret; 1264189251Ssam } 1265189251Ssam 1266252726Srpaulo ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); 1267189251Ssam if (ret < 0) 1268189251Ssam return -1; 1269189251Ssam 1270252726Srpaulodone: 1271189251Ssam /* Return the generated PIN */ 1272189251Ssam ret = os_snprintf(buf, buflen, "%08d", ret); 1273281806Srpaulo if (os_snprintf_error(buflen, ret)) 1274189251Ssam return -1; 1275189251Ssam return ret; 1276189251Ssam} 1277189251Ssam 1278189251Ssam 1279252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_check_pin( 1280252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 1281252726Srpaulo{ 1282252726Srpaulo char pin[9]; 1283252726Srpaulo size_t len; 1284252726Srpaulo char *pos; 1285252726Srpaulo int ret; 1286252726Srpaulo 1287252726Srpaulo wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", 1288252726Srpaulo (u8 *) cmd, os_strlen(cmd)); 1289252726Srpaulo for (pos = cmd, len = 0; *pos != '\0'; pos++) { 1290252726Srpaulo if (*pos < '0' || *pos > '9') 1291252726Srpaulo continue; 1292252726Srpaulo pin[len++] = *pos; 1293252726Srpaulo if (len == 9) { 1294252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); 1295252726Srpaulo return -1; 1296252726Srpaulo } 1297252726Srpaulo } 1298252726Srpaulo if (len != 4 && len != 8) { 1299252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); 1300252726Srpaulo return -1; 1301252726Srpaulo } 1302252726Srpaulo pin[len] = '\0'; 1303252726Srpaulo 1304252726Srpaulo if (len == 8) { 1305252726Srpaulo unsigned int pin_val; 1306252726Srpaulo pin_val = atoi(pin); 1307252726Srpaulo if (!wps_pin_valid(pin_val)) { 1308252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); 1309252726Srpaulo ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); 1310281806Srpaulo if (os_snprintf_error(buflen, ret)) 1311252726Srpaulo return -1; 1312252726Srpaulo return ret; 1313252726Srpaulo } 1314252726Srpaulo } 1315252726Srpaulo 1316252726Srpaulo ret = os_snprintf(buf, buflen, "%s", pin); 1317281806Srpaulo if (os_snprintf_error(buflen, ret)) 1318252726Srpaulo return -1; 1319252726Srpaulo 1320252726Srpaulo return ret; 1321252726Srpaulo} 1322252726Srpaulo 1323252726Srpaulo 1324252726Srpaulo#ifdef CONFIG_WPS_NFC 1325252726Srpaulo 1326252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s, 1327214734Srpaulo char *cmd) 1328214734Srpaulo{ 1329252726Srpaulo u8 bssid[ETH_ALEN], *_bssid = bssid; 1330214734Srpaulo 1331252726Srpaulo if (cmd == NULL || cmd[0] == '\0') 1332252726Srpaulo _bssid = NULL; 1333252726Srpaulo else if (hwaddr_aton(cmd, bssid)) 1334214734Srpaulo return -1; 1335214734Srpaulo 1336281806Srpaulo return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL, 1337281806Srpaulo 0, 0); 1338252726Srpaulo} 1339252726Srpaulo 1340252726Srpaulo 1341281806Srpaulostatic int wpa_supplicant_ctrl_iface_wps_nfc_config_token( 1342281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1343281806Srpaulo{ 1344281806Srpaulo int ndef; 1345281806Srpaulo struct wpabuf *buf; 1346281806Srpaulo int res; 1347281806Srpaulo char *pos; 1348281806Srpaulo 1349281806Srpaulo pos = os_strchr(cmd, ' '); 1350281806Srpaulo if (pos) 1351281806Srpaulo *pos++ = '\0'; 1352281806Srpaulo if (os_strcmp(cmd, "WPS") == 0) 1353281806Srpaulo ndef = 0; 1354281806Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 1355281806Srpaulo ndef = 1; 1356281806Srpaulo else 1357281806Srpaulo return -1; 1358281806Srpaulo 1359281806Srpaulo buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos); 1360281806Srpaulo if (buf == NULL) 1361281806Srpaulo return -1; 1362281806Srpaulo 1363281806Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1364281806Srpaulo wpabuf_len(buf)); 1365281806Srpaulo reply[res++] = '\n'; 1366281806Srpaulo reply[res] = '\0'; 1367281806Srpaulo 1368281806Srpaulo wpabuf_free(buf); 1369281806Srpaulo 1370281806Srpaulo return res; 1371281806Srpaulo} 1372281806Srpaulo 1373281806Srpaulo 1374252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_nfc_token( 1375252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1376252726Srpaulo{ 1377252726Srpaulo int ndef; 1378252726Srpaulo struct wpabuf *buf; 1379252726Srpaulo int res; 1380252726Srpaulo 1381252726Srpaulo if (os_strcmp(cmd, "WPS") == 0) 1382252726Srpaulo ndef = 0; 1383252726Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 1384252726Srpaulo ndef = 1; 1385252726Srpaulo else 1386214734Srpaulo return -1; 1387214734Srpaulo 1388252726Srpaulo buf = wpas_wps_nfc_token(wpa_s, ndef); 1389252726Srpaulo if (buf == NULL) 1390252726Srpaulo return -1; 1391214734Srpaulo 1392252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1393252726Srpaulo wpabuf_len(buf)); 1394252726Srpaulo reply[res++] = '\n'; 1395252726Srpaulo reply[res] = '\0'; 1396252726Srpaulo 1397252726Srpaulo wpabuf_free(buf); 1398252726Srpaulo 1399252726Srpaulo return res; 1400214734Srpaulo} 1401214734Srpaulo 1402214734Srpaulo 1403252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_nfc_tag_read( 1404252726Srpaulo struct wpa_supplicant *wpa_s, char *pos) 1405252726Srpaulo{ 1406252726Srpaulo size_t len; 1407252726Srpaulo struct wpabuf *buf; 1408252726Srpaulo int ret; 1409281806Srpaulo char *freq; 1410281806Srpaulo int forced_freq = 0; 1411252726Srpaulo 1412281806Srpaulo freq = strstr(pos, " freq="); 1413281806Srpaulo if (freq) { 1414281806Srpaulo *freq = '\0'; 1415281806Srpaulo freq += 6; 1416281806Srpaulo forced_freq = atoi(freq); 1417281806Srpaulo } 1418281806Srpaulo 1419252726Srpaulo len = os_strlen(pos); 1420252726Srpaulo if (len & 0x01) 1421252726Srpaulo return -1; 1422252726Srpaulo len /= 2; 1423252726Srpaulo 1424252726Srpaulo buf = wpabuf_alloc(len); 1425252726Srpaulo if (buf == NULL) 1426252726Srpaulo return -1; 1427252726Srpaulo if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 1428252726Srpaulo wpabuf_free(buf); 1429252726Srpaulo return -1; 1430252726Srpaulo } 1431252726Srpaulo 1432281806Srpaulo ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq); 1433252726Srpaulo wpabuf_free(buf); 1434252726Srpaulo 1435252726Srpaulo return ret; 1436252726Srpaulo} 1437252726Srpaulo 1438252726Srpaulo 1439252726Srpaulostatic int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s, 1440281806Srpaulo char *reply, size_t max_len, 1441281806Srpaulo int ndef) 1442252726Srpaulo{ 1443252726Srpaulo struct wpabuf *buf; 1444252726Srpaulo int res; 1445252726Srpaulo 1446281806Srpaulo buf = wpas_wps_nfc_handover_req(wpa_s, ndef); 1447252726Srpaulo if (buf == NULL) 1448252726Srpaulo return -1; 1449252726Srpaulo 1450252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1451252726Srpaulo wpabuf_len(buf)); 1452252726Srpaulo reply[res++] = '\n'; 1453252726Srpaulo reply[res] = '\0'; 1454252726Srpaulo 1455252726Srpaulo wpabuf_free(buf); 1456252726Srpaulo 1457252726Srpaulo return res; 1458252726Srpaulo} 1459252726Srpaulo 1460252726Srpaulo 1461281806Srpaulo#ifdef CONFIG_P2P 1462281806Srpaulostatic int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s, 1463281806Srpaulo char *reply, size_t max_len, 1464281806Srpaulo int ndef) 1465281806Srpaulo{ 1466281806Srpaulo struct wpabuf *buf; 1467281806Srpaulo int res; 1468281806Srpaulo 1469281806Srpaulo buf = wpas_p2p_nfc_handover_req(wpa_s, ndef); 1470281806Srpaulo if (buf == NULL) { 1471281806Srpaulo wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request"); 1472281806Srpaulo return -1; 1473281806Srpaulo } 1474281806Srpaulo 1475281806Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1476281806Srpaulo wpabuf_len(buf)); 1477281806Srpaulo reply[res++] = '\n'; 1478281806Srpaulo reply[res] = '\0'; 1479281806Srpaulo 1480281806Srpaulo wpabuf_free(buf); 1481281806Srpaulo 1482281806Srpaulo return res; 1483281806Srpaulo} 1484281806Srpaulo#endif /* CONFIG_P2P */ 1485281806Srpaulo 1486281806Srpaulo 1487252726Srpaulostatic int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s, 1488252726Srpaulo char *cmd, char *reply, 1489252726Srpaulo size_t max_len) 1490252726Srpaulo{ 1491252726Srpaulo char *pos; 1492281806Srpaulo int ndef; 1493252726Srpaulo 1494252726Srpaulo pos = os_strchr(cmd, ' '); 1495252726Srpaulo if (pos == NULL) 1496252726Srpaulo return -1; 1497252726Srpaulo *pos++ = '\0'; 1498252726Srpaulo 1499281806Srpaulo if (os_strcmp(cmd, "WPS") == 0) 1500281806Srpaulo ndef = 0; 1501281806Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 1502281806Srpaulo ndef = 1; 1503281806Srpaulo else 1504252726Srpaulo return -1; 1505252726Srpaulo 1506281806Srpaulo if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { 1507281806Srpaulo if (!ndef) 1508281806Srpaulo return -1; 1509281806Srpaulo return wpas_ctrl_nfc_get_handover_req_wps( 1510281806Srpaulo wpa_s, reply, max_len, ndef); 1511252726Srpaulo } 1512252726Srpaulo 1513281806Srpaulo#ifdef CONFIG_P2P 1514281806Srpaulo if (os_strcmp(pos, "P2P-CR") == 0) { 1515281806Srpaulo return wpas_ctrl_nfc_get_handover_req_p2p( 1516281806Srpaulo wpa_s, reply, max_len, ndef); 1517281806Srpaulo } 1518281806Srpaulo#endif /* CONFIG_P2P */ 1519281806Srpaulo 1520252726Srpaulo return -1; 1521252726Srpaulo} 1522252726Srpaulo 1523252726Srpaulo 1524252726Srpaulostatic int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s, 1525281806Srpaulo char *reply, size_t max_len, 1526281806Srpaulo int ndef, int cr, char *uuid) 1527252726Srpaulo{ 1528252726Srpaulo struct wpabuf *buf; 1529252726Srpaulo int res; 1530252726Srpaulo 1531281806Srpaulo buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid); 1532252726Srpaulo if (buf == NULL) 1533252726Srpaulo return -1; 1534252726Srpaulo 1535252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1536252726Srpaulo wpabuf_len(buf)); 1537252726Srpaulo reply[res++] = '\n'; 1538252726Srpaulo reply[res] = '\0'; 1539252726Srpaulo 1540252726Srpaulo wpabuf_free(buf); 1541252726Srpaulo 1542252726Srpaulo return res; 1543252726Srpaulo} 1544252726Srpaulo 1545252726Srpaulo 1546281806Srpaulo#ifdef CONFIG_P2P 1547281806Srpaulostatic int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s, 1548281806Srpaulo char *reply, size_t max_len, 1549281806Srpaulo int ndef, int tag) 1550281806Srpaulo{ 1551281806Srpaulo struct wpabuf *buf; 1552281806Srpaulo int res; 1553281806Srpaulo 1554281806Srpaulo buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag); 1555281806Srpaulo if (buf == NULL) 1556281806Srpaulo return -1; 1557281806Srpaulo 1558281806Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1559281806Srpaulo wpabuf_len(buf)); 1560281806Srpaulo reply[res++] = '\n'; 1561281806Srpaulo reply[res] = '\0'; 1562281806Srpaulo 1563281806Srpaulo wpabuf_free(buf); 1564281806Srpaulo 1565281806Srpaulo return res; 1566281806Srpaulo} 1567281806Srpaulo#endif /* CONFIG_P2P */ 1568281806Srpaulo 1569281806Srpaulo 1570252726Srpaulostatic int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s, 1571252726Srpaulo char *cmd, char *reply, 1572252726Srpaulo size_t max_len) 1573252726Srpaulo{ 1574281806Srpaulo char *pos, *pos2; 1575281806Srpaulo int ndef; 1576252726Srpaulo 1577252726Srpaulo pos = os_strchr(cmd, ' '); 1578252726Srpaulo if (pos == NULL) 1579252726Srpaulo return -1; 1580252726Srpaulo *pos++ = '\0'; 1581252726Srpaulo 1582281806Srpaulo if (os_strcmp(cmd, "WPS") == 0) 1583281806Srpaulo ndef = 0; 1584281806Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 1585281806Srpaulo ndef = 1; 1586281806Srpaulo else 1587252726Srpaulo return -1; 1588252726Srpaulo 1589281806Srpaulo pos2 = os_strchr(pos, ' '); 1590281806Srpaulo if (pos2) 1591281806Srpaulo *pos2++ = '\0'; 1592281806Srpaulo if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { 1593281806Srpaulo if (!ndef) 1594281806Srpaulo return -1; 1595281806Srpaulo return wpas_ctrl_nfc_get_handover_sel_wps( 1596281806Srpaulo wpa_s, reply, max_len, ndef, 1597281806Srpaulo os_strcmp(pos, "WPS-CR") == 0, pos2); 1598252726Srpaulo } 1599252726Srpaulo 1600281806Srpaulo#ifdef CONFIG_P2P 1601281806Srpaulo if (os_strcmp(pos, "P2P-CR") == 0) { 1602281806Srpaulo return wpas_ctrl_nfc_get_handover_sel_p2p( 1603281806Srpaulo wpa_s, reply, max_len, ndef, 0); 1604281806Srpaulo } 1605281806Srpaulo 1606281806Srpaulo if (os_strcmp(pos, "P2P-CR-TAG") == 0) { 1607281806Srpaulo return wpas_ctrl_nfc_get_handover_sel_p2p( 1608281806Srpaulo wpa_s, reply, max_len, ndef, 1); 1609281806Srpaulo } 1610281806Srpaulo#endif /* CONFIG_P2P */ 1611281806Srpaulo 1612252726Srpaulo return -1; 1613252726Srpaulo} 1614252726Srpaulo 1615252726Srpaulo 1616281806Srpaulostatic int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s, 1617281806Srpaulo char *cmd) 1618252726Srpaulo{ 1619252726Srpaulo size_t len; 1620281806Srpaulo struct wpabuf *req, *sel; 1621252726Srpaulo int ret; 1622281806Srpaulo char *pos, *role, *type, *pos2; 1623281806Srpaulo#ifdef CONFIG_P2P 1624281806Srpaulo char *freq; 1625281806Srpaulo int forced_freq = 0; 1626252726Srpaulo 1627281806Srpaulo freq = strstr(cmd, " freq="); 1628281806Srpaulo if (freq) { 1629281806Srpaulo *freq = '\0'; 1630281806Srpaulo freq += 6; 1631281806Srpaulo forced_freq = atoi(freq); 1632281806Srpaulo } 1633281806Srpaulo#endif /* CONFIG_P2P */ 1634281806Srpaulo 1635281806Srpaulo role = cmd; 1636281806Srpaulo pos = os_strchr(role, ' '); 1637281806Srpaulo if (pos == NULL) { 1638281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report"); 1639252726Srpaulo return -1; 1640281806Srpaulo } 1641281806Srpaulo *pos++ = '\0'; 1642252726Srpaulo 1643281806Srpaulo type = pos; 1644281806Srpaulo pos = os_strchr(type, ' '); 1645281806Srpaulo if (pos == NULL) { 1646281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report"); 1647252726Srpaulo return -1; 1648281806Srpaulo } 1649281806Srpaulo *pos++ = '\0'; 1650281806Srpaulo 1651281806Srpaulo pos2 = os_strchr(pos, ' '); 1652281806Srpaulo if (pos2 == NULL) { 1653281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report"); 1654252726Srpaulo return -1; 1655252726Srpaulo } 1656281806Srpaulo *pos2++ = '\0'; 1657252726Srpaulo 1658281806Srpaulo len = os_strlen(pos); 1659281806Srpaulo if (len & 0x01) { 1660281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report"); 1661281806Srpaulo return -1; 1662281806Srpaulo } 1663281806Srpaulo len /= 2; 1664252726Srpaulo 1665281806Srpaulo req = wpabuf_alloc(len); 1666281806Srpaulo if (req == NULL) { 1667281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message"); 1668281806Srpaulo return -1; 1669281806Srpaulo } 1670281806Srpaulo if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { 1671281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report"); 1672281806Srpaulo wpabuf_free(req); 1673281806Srpaulo return -1; 1674281806Srpaulo } 1675252726Srpaulo 1676281806Srpaulo len = os_strlen(pos2); 1677281806Srpaulo if (len & 0x01) { 1678281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report"); 1679281806Srpaulo wpabuf_free(req); 1680252726Srpaulo return -1; 1681281806Srpaulo } 1682252726Srpaulo len /= 2; 1683252726Srpaulo 1684281806Srpaulo sel = wpabuf_alloc(len); 1685281806Srpaulo if (sel == NULL) { 1686281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message"); 1687281806Srpaulo wpabuf_free(req); 1688252726Srpaulo return -1; 1689281806Srpaulo } 1690281806Srpaulo if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { 1691281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report"); 1692281806Srpaulo wpabuf_free(req); 1693281806Srpaulo wpabuf_free(sel); 1694252726Srpaulo return -1; 1695252726Srpaulo } 1696252726Srpaulo 1697281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d", 1698281806Srpaulo role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel)); 1699252726Srpaulo 1700281806Srpaulo if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) { 1701281806Srpaulo ret = wpas_wps_nfc_report_handover(wpa_s, req, sel); 1702281806Srpaulo#ifdef CONFIG_AP 1703281806Srpaulo } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) 1704281806Srpaulo { 1705281806Srpaulo ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel); 1706281806Srpaulo if (ret < 0) 1707281806Srpaulo ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel); 1708281806Srpaulo#endif /* CONFIG_AP */ 1709281806Srpaulo#ifdef CONFIG_P2P 1710281806Srpaulo } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0) 1711281806Srpaulo { 1712281806Srpaulo ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0); 1713281806Srpaulo } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0) 1714281806Srpaulo { 1715281806Srpaulo ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel, 1716281806Srpaulo forced_freq); 1717281806Srpaulo#endif /* CONFIG_P2P */ 1718281806Srpaulo } else { 1719281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " 1720281806Srpaulo "reported: role=%s type=%s", role, type); 1721281806Srpaulo ret = -1; 1722281806Srpaulo } 1723281806Srpaulo wpabuf_free(req); 1724281806Srpaulo wpabuf_free(sel); 1725281806Srpaulo 1726281806Srpaulo if (ret) 1727281806Srpaulo wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages"); 1728281806Srpaulo 1729252726Srpaulo return ret; 1730252726Srpaulo} 1731252726Srpaulo 1732252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1733252726Srpaulo 1734252726Srpaulo 1735189251Ssamstatic int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s, 1736189251Ssam char *cmd) 1737189251Ssam{ 1738252726Srpaulo u8 bssid[ETH_ALEN]; 1739189251Ssam char *pin; 1740214734Srpaulo char *new_ssid; 1741214734Srpaulo char *new_auth; 1742214734Srpaulo char *new_encr; 1743214734Srpaulo char *new_key; 1744214734Srpaulo struct wps_new_ap_settings ap; 1745189251Ssam 1746189251Ssam pin = os_strchr(cmd, ' '); 1747189251Ssam if (pin == NULL) 1748189251Ssam return -1; 1749189251Ssam *pin++ = '\0'; 1750189251Ssam 1751252726Srpaulo if (hwaddr_aton(cmd, bssid)) { 1752189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'", 1753189251Ssam cmd); 1754189251Ssam return -1; 1755189251Ssam } 1756189251Ssam 1757214734Srpaulo new_ssid = os_strchr(pin, ' '); 1758214734Srpaulo if (new_ssid == NULL) 1759252726Srpaulo return wpas_wps_start_reg(wpa_s, bssid, pin, NULL); 1760214734Srpaulo *new_ssid++ = '\0'; 1761214734Srpaulo 1762214734Srpaulo new_auth = os_strchr(new_ssid, ' '); 1763214734Srpaulo if (new_auth == NULL) 1764214734Srpaulo return -1; 1765214734Srpaulo *new_auth++ = '\0'; 1766214734Srpaulo 1767214734Srpaulo new_encr = os_strchr(new_auth, ' '); 1768214734Srpaulo if (new_encr == NULL) 1769214734Srpaulo return -1; 1770214734Srpaulo *new_encr++ = '\0'; 1771214734Srpaulo 1772214734Srpaulo new_key = os_strchr(new_encr, ' '); 1773214734Srpaulo if (new_key == NULL) 1774214734Srpaulo return -1; 1775214734Srpaulo *new_key++ = '\0'; 1776214734Srpaulo 1777214734Srpaulo os_memset(&ap, 0, sizeof(ap)); 1778214734Srpaulo ap.ssid_hex = new_ssid; 1779214734Srpaulo ap.auth = new_auth; 1780214734Srpaulo ap.encr = new_encr; 1781214734Srpaulo ap.key_hex = new_key; 1782252726Srpaulo return wpas_wps_start_reg(wpa_s, bssid, pin, &ap); 1783189251Ssam} 1784214734Srpaulo 1785214734Srpaulo 1786252726Srpaulo#ifdef CONFIG_AP 1787252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s, 1788252726Srpaulo char *cmd, char *buf, 1789252726Srpaulo size_t buflen) 1790252726Srpaulo{ 1791252726Srpaulo int timeout = 300; 1792252726Srpaulo char *pos; 1793252726Srpaulo const char *pin_txt; 1794252726Srpaulo 1795252726Srpaulo if (!wpa_s->ap_iface) 1796252726Srpaulo return -1; 1797252726Srpaulo 1798252726Srpaulo pos = os_strchr(cmd, ' '); 1799252726Srpaulo if (pos) 1800252726Srpaulo *pos++ = '\0'; 1801252726Srpaulo 1802252726Srpaulo if (os_strcmp(cmd, "disable") == 0) { 1803252726Srpaulo wpas_wps_ap_pin_disable(wpa_s); 1804252726Srpaulo return os_snprintf(buf, buflen, "OK\n"); 1805252726Srpaulo } 1806252726Srpaulo 1807252726Srpaulo if (os_strcmp(cmd, "random") == 0) { 1808252726Srpaulo if (pos) 1809252726Srpaulo timeout = atoi(pos); 1810252726Srpaulo pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout); 1811252726Srpaulo if (pin_txt == NULL) 1812252726Srpaulo return -1; 1813252726Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 1814252726Srpaulo } 1815252726Srpaulo 1816252726Srpaulo if (os_strcmp(cmd, "get") == 0) { 1817252726Srpaulo pin_txt = wpas_wps_ap_pin_get(wpa_s); 1818252726Srpaulo if (pin_txt == NULL) 1819252726Srpaulo return -1; 1820252726Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 1821252726Srpaulo } 1822252726Srpaulo 1823252726Srpaulo if (os_strcmp(cmd, "set") == 0) { 1824252726Srpaulo char *pin; 1825252726Srpaulo if (pos == NULL) 1826252726Srpaulo return -1; 1827252726Srpaulo pin = pos; 1828252726Srpaulo pos = os_strchr(pos, ' '); 1829252726Srpaulo if (pos) { 1830252726Srpaulo *pos++ = '\0'; 1831252726Srpaulo timeout = atoi(pos); 1832252726Srpaulo } 1833252726Srpaulo if (os_strlen(pin) > buflen) 1834252726Srpaulo return -1; 1835252726Srpaulo if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0) 1836252726Srpaulo return -1; 1837252726Srpaulo return os_snprintf(buf, buflen, "%s", pin); 1838252726Srpaulo } 1839252726Srpaulo 1840252726Srpaulo return -1; 1841252726Srpaulo} 1842252726Srpaulo#endif /* CONFIG_AP */ 1843252726Srpaulo 1844252726Srpaulo 1845214734Srpaulo#ifdef CONFIG_WPS_ER 1846214734Srpaulostatic int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s, 1847214734Srpaulo char *cmd) 1848214734Srpaulo{ 1849252726Srpaulo char *uuid = cmd, *pin, *pos; 1850252726Srpaulo u8 addr_buf[ETH_ALEN], *addr = NULL; 1851214734Srpaulo pin = os_strchr(uuid, ' '); 1852214734Srpaulo if (pin == NULL) 1853214734Srpaulo return -1; 1854214734Srpaulo *pin++ = '\0'; 1855252726Srpaulo pos = os_strchr(pin, ' '); 1856252726Srpaulo if (pos) { 1857252726Srpaulo *pos++ = '\0'; 1858252726Srpaulo if (hwaddr_aton(pos, addr_buf) == 0) 1859252726Srpaulo addr = addr_buf; 1860252726Srpaulo } 1861252726Srpaulo return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin); 1862214734Srpaulo} 1863214734Srpaulo 1864214734Srpaulo 1865214734Srpaulostatic int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s, 1866214734Srpaulo char *cmd) 1867214734Srpaulo{ 1868214734Srpaulo char *uuid = cmd, *pin; 1869214734Srpaulo pin = os_strchr(uuid, ' '); 1870214734Srpaulo if (pin == NULL) 1871214734Srpaulo return -1; 1872214734Srpaulo *pin++ = '\0'; 1873214734Srpaulo return wpas_wps_er_learn(wpa_s, uuid, pin); 1874214734Srpaulo} 1875252726Srpaulo 1876252726Srpaulo 1877252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_er_set_config( 1878252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 1879252726Srpaulo{ 1880252726Srpaulo char *uuid = cmd, *id; 1881252726Srpaulo id = os_strchr(uuid, ' '); 1882252726Srpaulo if (id == NULL) 1883252726Srpaulo return -1; 1884252726Srpaulo *id++ = '\0'; 1885252726Srpaulo return wpas_wps_er_set_config(wpa_s, uuid, atoi(id)); 1886252726Srpaulo} 1887252726Srpaulo 1888252726Srpaulo 1889252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_er_config( 1890252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 1891252726Srpaulo{ 1892252726Srpaulo char *pin; 1893252726Srpaulo char *new_ssid; 1894252726Srpaulo char *new_auth; 1895252726Srpaulo char *new_encr; 1896252726Srpaulo char *new_key; 1897252726Srpaulo struct wps_new_ap_settings ap; 1898252726Srpaulo 1899252726Srpaulo pin = os_strchr(cmd, ' '); 1900252726Srpaulo if (pin == NULL) 1901252726Srpaulo return -1; 1902252726Srpaulo *pin++ = '\0'; 1903252726Srpaulo 1904252726Srpaulo new_ssid = os_strchr(pin, ' '); 1905252726Srpaulo if (new_ssid == NULL) 1906252726Srpaulo return -1; 1907252726Srpaulo *new_ssid++ = '\0'; 1908252726Srpaulo 1909252726Srpaulo new_auth = os_strchr(new_ssid, ' '); 1910252726Srpaulo if (new_auth == NULL) 1911252726Srpaulo return -1; 1912252726Srpaulo *new_auth++ = '\0'; 1913252726Srpaulo 1914252726Srpaulo new_encr = os_strchr(new_auth, ' '); 1915252726Srpaulo if (new_encr == NULL) 1916252726Srpaulo return -1; 1917252726Srpaulo *new_encr++ = '\0'; 1918252726Srpaulo 1919252726Srpaulo new_key = os_strchr(new_encr, ' '); 1920252726Srpaulo if (new_key == NULL) 1921252726Srpaulo return -1; 1922252726Srpaulo *new_key++ = '\0'; 1923252726Srpaulo 1924252726Srpaulo os_memset(&ap, 0, sizeof(ap)); 1925252726Srpaulo ap.ssid_hex = new_ssid; 1926252726Srpaulo ap.auth = new_auth; 1927252726Srpaulo ap.encr = new_encr; 1928252726Srpaulo ap.key_hex = new_key; 1929252726Srpaulo return wpas_wps_er_config(wpa_s, cmd, pin, &ap); 1930252726Srpaulo} 1931252726Srpaulo 1932252726Srpaulo 1933252726Srpaulo#ifdef CONFIG_WPS_NFC 1934252726Srpaulostatic int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( 1935252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1936252726Srpaulo{ 1937252726Srpaulo int ndef; 1938252726Srpaulo struct wpabuf *buf; 1939252726Srpaulo int res; 1940252726Srpaulo char *uuid; 1941252726Srpaulo 1942252726Srpaulo uuid = os_strchr(cmd, ' '); 1943252726Srpaulo if (uuid == NULL) 1944252726Srpaulo return -1; 1945252726Srpaulo *uuid++ = '\0'; 1946252726Srpaulo 1947252726Srpaulo if (os_strcmp(cmd, "WPS") == 0) 1948252726Srpaulo ndef = 0; 1949252726Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 1950252726Srpaulo ndef = 1; 1951252726Srpaulo else 1952252726Srpaulo return -1; 1953252726Srpaulo 1954252726Srpaulo buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid); 1955252726Srpaulo if (buf == NULL) 1956252726Srpaulo return -1; 1957252726Srpaulo 1958252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1959252726Srpaulo wpabuf_len(buf)); 1960252726Srpaulo reply[res++] = '\n'; 1961252726Srpaulo reply[res] = '\0'; 1962252726Srpaulo 1963252726Srpaulo wpabuf_free(buf); 1964252726Srpaulo 1965252726Srpaulo return res; 1966252726Srpaulo} 1967252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1968214734Srpaulo#endif /* CONFIG_WPS_ER */ 1969214734Srpaulo 1970189251Ssam#endif /* CONFIG_WPS */ 1971189251Ssam 1972189251Ssam 1973214734Srpaulo#ifdef CONFIG_IBSS_RSN 1974214734Srpaulostatic int wpa_supplicant_ctrl_iface_ibss_rsn( 1975214734Srpaulo struct wpa_supplicant *wpa_s, char *addr) 1976214734Srpaulo{ 1977214734Srpaulo u8 peer[ETH_ALEN]; 1978214734Srpaulo 1979214734Srpaulo if (hwaddr_aton(addr, peer)) { 1980214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid " 1981214734Srpaulo "address '%s'", addr); 1982214734Srpaulo return -1; 1983214734Srpaulo } 1984214734Srpaulo 1985214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR, 1986214734Srpaulo MAC2STR(peer)); 1987214734Srpaulo 1988214734Srpaulo return ibss_rsn_start(wpa_s->ibss_rsn, peer); 1989214734Srpaulo} 1990214734Srpaulo#endif /* CONFIG_IBSS_RSN */ 1991214734Srpaulo 1992214734Srpaulo 1993189251Ssamstatic int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, 1994189251Ssam char *rsp) 1995189251Ssam{ 1996189251Ssam#ifdef IEEE8021X_EAPOL 1997189251Ssam char *pos, *id_pos; 1998189251Ssam int id; 1999189251Ssam struct wpa_ssid *ssid; 2000189251Ssam 2001189251Ssam pos = os_strchr(rsp, '-'); 2002189251Ssam if (pos == NULL) 2003189251Ssam return -1; 2004189251Ssam *pos++ = '\0'; 2005189251Ssam id_pos = pos; 2006189251Ssam pos = os_strchr(pos, ':'); 2007189251Ssam if (pos == NULL) 2008189251Ssam return -1; 2009189251Ssam *pos++ = '\0'; 2010189251Ssam id = atoi(id_pos); 2011189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id); 2012189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 2013189251Ssam (u8 *) pos, os_strlen(pos)); 2014189251Ssam 2015189251Ssam ssid = wpa_config_get_network(wpa_s->conf, id); 2016189251Ssam if (ssid == NULL) { 2017189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 2018189251Ssam "to update", id); 2019189251Ssam return -1; 2020189251Ssam } 2021189251Ssam 2022252726Srpaulo return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp, 2023252726Srpaulo pos); 2024189251Ssam#else /* IEEE8021X_EAPOL */ 2025189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); 2026189251Ssam return -1; 2027189251Ssam#endif /* IEEE8021X_EAPOL */ 2028189251Ssam} 2029189251Ssam 2030189251Ssam 2031189251Ssamstatic int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, 2032189251Ssam const char *params, 2033189251Ssam char *buf, size_t buflen) 2034189251Ssam{ 2035189251Ssam char *pos, *end, tmp[30]; 2036252726Srpaulo int res, verbose, wps, ret; 2037281806Srpaulo#ifdef CONFIG_HS20 2038281806Srpaulo const u8 *hs20; 2039281806Srpaulo#endif /* CONFIG_HS20 */ 2040281806Srpaulo const u8 *sess_id; 2041281806Srpaulo size_t sess_id_len; 2042189251Ssam 2043281806Srpaulo if (os_strcmp(params, "-DRIVER") == 0) 2044281806Srpaulo return wpa_drv_status(wpa_s, buf, buflen); 2045189251Ssam verbose = os_strcmp(params, "-VERBOSE") == 0; 2046252726Srpaulo wps = os_strcmp(params, "-WPS") == 0; 2047189251Ssam pos = buf; 2048189251Ssam end = buf + buflen; 2049189251Ssam if (wpa_s->wpa_state >= WPA_ASSOCIATED) { 2050189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 2051189251Ssam ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", 2052189251Ssam MAC2STR(wpa_s->bssid)); 2053281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2054189251Ssam return pos - buf; 2055189251Ssam pos += ret; 2056281806Srpaulo ret = os_snprintf(pos, end - pos, "freq=%u\n", 2057281806Srpaulo wpa_s->assoc_freq); 2058281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2059281806Srpaulo return pos - buf; 2060281806Srpaulo pos += ret; 2061189251Ssam if (ssid) { 2062189251Ssam u8 *_ssid = ssid->ssid; 2063189251Ssam size_t ssid_len = ssid->ssid_len; 2064289549Srpaulo u8 ssid_buf[SSID_MAX_LEN]; 2065189251Ssam if (ssid_len == 0) { 2066189251Ssam int _res = wpa_drv_get_ssid(wpa_s, ssid_buf); 2067189251Ssam if (_res < 0) 2068189251Ssam ssid_len = 0; 2069189251Ssam else 2070189251Ssam ssid_len = _res; 2071189251Ssam _ssid = ssid_buf; 2072189251Ssam } 2073189251Ssam ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n", 2074189251Ssam wpa_ssid_txt(_ssid, ssid_len), 2075189251Ssam ssid->id); 2076281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2077189251Ssam return pos - buf; 2078189251Ssam pos += ret; 2079189251Ssam 2080252726Srpaulo if (wps && ssid->passphrase && 2081252726Srpaulo wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && 2082252726Srpaulo (ssid->mode == WPAS_MODE_AP || 2083252726Srpaulo ssid->mode == WPAS_MODE_P2P_GO)) { 2084252726Srpaulo ret = os_snprintf(pos, end - pos, 2085252726Srpaulo "passphrase=%s\n", 2086252726Srpaulo ssid->passphrase); 2087281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2088252726Srpaulo return pos - buf; 2089252726Srpaulo pos += ret; 2090252726Srpaulo } 2091189251Ssam if (ssid->id_str) { 2092189251Ssam ret = os_snprintf(pos, end - pos, 2093189251Ssam "id_str=%s\n", 2094189251Ssam ssid->id_str); 2095281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2096189251Ssam return pos - buf; 2097189251Ssam pos += ret; 2098189251Ssam } 2099214734Srpaulo 2100214734Srpaulo switch (ssid->mode) { 2101214734Srpaulo case WPAS_MODE_INFRA: 2102214734Srpaulo ret = os_snprintf(pos, end - pos, 2103214734Srpaulo "mode=station\n"); 2104214734Srpaulo break; 2105214734Srpaulo case WPAS_MODE_IBSS: 2106214734Srpaulo ret = os_snprintf(pos, end - pos, 2107214734Srpaulo "mode=IBSS\n"); 2108214734Srpaulo break; 2109214734Srpaulo case WPAS_MODE_AP: 2110214734Srpaulo ret = os_snprintf(pos, end - pos, 2111214734Srpaulo "mode=AP\n"); 2112214734Srpaulo break; 2113252726Srpaulo case WPAS_MODE_P2P_GO: 2114252726Srpaulo ret = os_snprintf(pos, end - pos, 2115252726Srpaulo "mode=P2P GO\n"); 2116252726Srpaulo break; 2117252726Srpaulo case WPAS_MODE_P2P_GROUP_FORMATION: 2118252726Srpaulo ret = os_snprintf(pos, end - pos, 2119252726Srpaulo "mode=P2P GO - group " 2120252726Srpaulo "formation\n"); 2121252726Srpaulo break; 2122337817Scy case WPAS_MODE_MESH: 2123337817Scy ret = os_snprintf(pos, end - pos, 2124337817Scy "mode=mesh\n"); 2125337817Scy break; 2126214734Srpaulo default: 2127214734Srpaulo ret = 0; 2128214734Srpaulo break; 2129214734Srpaulo } 2130281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2131214734Srpaulo return pos - buf; 2132214734Srpaulo pos += ret; 2133189251Ssam } 2134189251Ssam 2135346981Scy if (wpa_s->connection_set && 2136346981Scy (wpa_s->connection_ht || wpa_s->connection_vht || 2137346981Scy wpa_s->connection_he)) { 2138346981Scy ret = os_snprintf(pos, end - pos, 2139346981Scy "wifi_generation=%u\n", 2140346981Scy wpa_s->connection_he ? 6 : 2141346981Scy (wpa_s->connection_vht ? 5 : 4)); 2142346981Scy if (os_snprintf_error(end - pos, ret)) 2143346981Scy return pos - buf; 2144346981Scy pos += ret; 2145346981Scy } 2146346981Scy 2147214734Srpaulo#ifdef CONFIG_AP 2148214734Srpaulo if (wpa_s->ap_iface) { 2149214734Srpaulo pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, 2150214734Srpaulo end - pos, 2151214734Srpaulo verbose); 2152214734Srpaulo } else 2153214734Srpaulo#endif /* CONFIG_AP */ 2154189251Ssam pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); 2155189251Ssam } 2156346981Scy#ifdef CONFIG_SME 2157281806Srpaulo#ifdef CONFIG_SAE 2158281806Srpaulo if (wpa_s->wpa_state >= WPA_ASSOCIATED && 2159281806Srpaulo#ifdef CONFIG_AP 2160281806Srpaulo !wpa_s->ap_iface && 2161281806Srpaulo#endif /* CONFIG_AP */ 2162281806Srpaulo wpa_s->sme.sae.state == SAE_ACCEPTED) { 2163281806Srpaulo ret = os_snprintf(pos, end - pos, "sae_group=%d\n", 2164281806Srpaulo wpa_s->sme.sae.group); 2165281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2166281806Srpaulo return pos - buf; 2167281806Srpaulo pos += ret; 2168281806Srpaulo } 2169281806Srpaulo#endif /* CONFIG_SAE */ 2170346981Scy#endif /* CONFIG_SME */ 2171189251Ssam ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", 2172189251Ssam wpa_supplicant_state_txt(wpa_s->wpa_state)); 2173281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2174189251Ssam return pos - buf; 2175189251Ssam pos += ret; 2176189251Ssam 2177189251Ssam if (wpa_s->l2 && 2178189251Ssam l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) { 2179189251Ssam ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp); 2180281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2181189251Ssam return pos - buf; 2182189251Ssam pos += ret; 2183189251Ssam } 2184189251Ssam 2185252726Srpaulo#ifdef CONFIG_P2P 2186252726Srpaulo if (wpa_s->global->p2p) { 2187252726Srpaulo ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR 2188252726Srpaulo "\n", MAC2STR(wpa_s->global->p2p_dev_addr)); 2189281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2190252726Srpaulo return pos - buf; 2191252726Srpaulo pos += ret; 2192252726Srpaulo } 2193252726Srpaulo#endif /* CONFIG_P2P */ 2194252726Srpaulo 2195252726Srpaulo ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n", 2196252726Srpaulo MAC2STR(wpa_s->own_addr)); 2197281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2198252726Srpaulo return pos - buf; 2199252726Srpaulo pos += ret; 2200252726Srpaulo 2201252726Srpaulo#ifdef CONFIG_HS20 2202252726Srpaulo if (wpa_s->current_bss && 2203281806Srpaulo (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss, 2204281806Srpaulo HS20_IE_VENDOR_TYPE)) && 2205252726Srpaulo wpa_s->wpa_proto == WPA_PROTO_RSN && 2206252726Srpaulo wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { 2207281806Srpaulo int release = 1; 2208281806Srpaulo if (hs20[1] >= 5) { 2209281806Srpaulo u8 rel_num = (hs20[6] & 0xf0) >> 4; 2210281806Srpaulo release = rel_num + 1; 2211281806Srpaulo } 2212281806Srpaulo ret = os_snprintf(pos, end - pos, "hs20=%d\n", release); 2213281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2214252726Srpaulo return pos - buf; 2215252726Srpaulo pos += ret; 2216252726Srpaulo } 2217252726Srpaulo 2218252726Srpaulo if (wpa_s->current_ssid) { 2219252726Srpaulo struct wpa_cred *cred; 2220252726Srpaulo char *type; 2221252726Srpaulo 2222252726Srpaulo for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 2223281806Srpaulo size_t i; 2224281806Srpaulo 2225252726Srpaulo if (wpa_s->current_ssid->parent_cred != cred) 2226252726Srpaulo continue; 2227281806Srpaulo 2228281806Srpaulo if (cred->provisioning_sp) { 2229281806Srpaulo ret = os_snprintf(pos, end - pos, 2230281806Srpaulo "provisioning_sp=%s\n", 2231281806Srpaulo cred->provisioning_sp); 2232281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2233281806Srpaulo return pos - buf; 2234281806Srpaulo pos += ret; 2235281806Srpaulo } 2236281806Srpaulo 2237252726Srpaulo if (!cred->domain) 2238281806Srpaulo goto no_domain; 2239252726Srpaulo 2240281806Srpaulo i = 0; 2241281806Srpaulo if (wpa_s->current_bss && wpa_s->current_bss->anqp) { 2242281806Srpaulo struct wpabuf *names = 2243281806Srpaulo wpa_s->current_bss->anqp->domain_name; 2244281806Srpaulo for (i = 0; names && i < cred->num_domain; i++) 2245281806Srpaulo { 2246281806Srpaulo if (domain_name_list_contains( 2247281806Srpaulo names, cred->domain[i], 1)) 2248281806Srpaulo break; 2249281806Srpaulo } 2250281806Srpaulo if (i == cred->num_domain) 2251281806Srpaulo i = 0; /* show first entry by default */ 2252281806Srpaulo } 2253252726Srpaulo ret = os_snprintf(pos, end - pos, "home_sp=%s\n", 2254281806Srpaulo cred->domain[i]); 2255281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2256252726Srpaulo return pos - buf; 2257252726Srpaulo pos += ret; 2258252726Srpaulo 2259281806Srpaulo no_domain: 2260252726Srpaulo if (wpa_s->current_bss == NULL || 2261252726Srpaulo wpa_s->current_bss->anqp == NULL) 2262252726Srpaulo res = -1; 2263252726Srpaulo else 2264252726Srpaulo res = interworking_home_sp_cred( 2265252726Srpaulo wpa_s, cred, 2266252726Srpaulo wpa_s->current_bss->anqp->domain_name); 2267252726Srpaulo if (res > 0) 2268252726Srpaulo type = "home"; 2269252726Srpaulo else if (res == 0) 2270252726Srpaulo type = "roaming"; 2271252726Srpaulo else 2272252726Srpaulo type = "unknown"; 2273252726Srpaulo 2274252726Srpaulo ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type); 2275281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2276252726Srpaulo return pos - buf; 2277252726Srpaulo pos += ret; 2278252726Srpaulo 2279252726Srpaulo break; 2280252726Srpaulo } 2281252726Srpaulo } 2282252726Srpaulo#endif /* CONFIG_HS20 */ 2283252726Srpaulo 2284189251Ssam if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || 2285189251Ssam wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 2286189251Ssam res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, 2287189251Ssam verbose); 2288189251Ssam if (res >= 0) 2289189251Ssam pos += res; 2290189251Ssam } 2291189251Ssam 2292346981Scy#ifdef CONFIG_MACSEC 2293346981Scy res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos); 2294346981Scy if (res > 0) 2295346981Scy pos += res; 2296346981Scy#endif /* CONFIG_MACSEC */ 2297346981Scy 2298281806Srpaulo sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len); 2299281806Srpaulo if (sess_id) { 2300281806Srpaulo char *start = pos; 2301281806Srpaulo 2302281806Srpaulo ret = os_snprintf(pos, end - pos, "eap_session_id="); 2303281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2304281806Srpaulo return start - buf; 2305281806Srpaulo pos += ret; 2306281806Srpaulo ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len); 2307281806Srpaulo if (ret <= 0) 2308281806Srpaulo return start - buf; 2309281806Srpaulo pos += ret; 2310281806Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 2311281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2312281806Srpaulo return start - buf; 2313281806Srpaulo pos += ret; 2314281806Srpaulo } 2315281806Srpaulo 2316189251Ssam res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose); 2317189251Ssam if (res >= 0) 2318189251Ssam pos += res; 2319189251Ssam 2320281806Srpaulo#ifdef CONFIG_WPS 2321281806Srpaulo { 2322281806Srpaulo char uuid_str[100]; 2323281806Srpaulo uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str)); 2324281806Srpaulo ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str); 2325281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2326281806Srpaulo return pos - buf; 2327281806Srpaulo pos += ret; 2328281806Srpaulo } 2329281806Srpaulo#endif /* CONFIG_WPS */ 2330281806Srpaulo 2331346981Scy if (wpa_s->ieee80211ac) { 2332346981Scy ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n"); 2333346981Scy if (os_snprintf_error(end - pos, ret)) 2334346981Scy return pos - buf; 2335346981Scy pos += ret; 2336346981Scy } 2337346981Scy 2338281806Srpaulo#ifdef ANDROID 2339281806Srpaulo /* 2340281806Srpaulo * Allow using the STATUS command with default behavior, say for debug, 2341281806Srpaulo * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE 2342281806Srpaulo * events with STATUS-NO_EVENTS. 2343281806Srpaulo */ 2344281806Srpaulo if (os_strcmp(params, "-NO_EVENTS")) { 2345281806Srpaulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE 2346281806Srpaulo "id=%d state=%d BSSID=" MACSTR " SSID=%s", 2347281806Srpaulo wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, 2348281806Srpaulo wpa_s->wpa_state, 2349281806Srpaulo MAC2STR(wpa_s->bssid), 2350281806Srpaulo wpa_s->current_ssid && wpa_s->current_ssid->ssid ? 2351281806Srpaulo wpa_ssid_txt(wpa_s->current_ssid->ssid, 2352281806Srpaulo wpa_s->current_ssid->ssid_len) : ""); 2353281806Srpaulo if (wpa_s->wpa_state == WPA_COMPLETED) { 2354281806Srpaulo struct wpa_ssid *ssid = wpa_s->current_ssid; 2355281806Srpaulo wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED 2356281806Srpaulo "- connection to " MACSTR 2357281806Srpaulo " completed %s [id=%d id_str=%s]", 2358281806Srpaulo MAC2STR(wpa_s->bssid), "(auth)", 2359281806Srpaulo ssid ? ssid->id : -1, 2360281806Srpaulo ssid && ssid->id_str ? ssid->id_str : ""); 2361281806Srpaulo } 2362281806Srpaulo } 2363281806Srpaulo#endif /* ANDROID */ 2364281806Srpaulo 2365189251Ssam return pos - buf; 2366189251Ssam} 2367189251Ssam 2368189251Ssam 2369189251Ssamstatic int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, 2370189251Ssam char *cmd) 2371189251Ssam{ 2372189251Ssam char *pos; 2373189251Ssam int id; 2374189251Ssam struct wpa_ssid *ssid; 2375189251Ssam u8 bssid[ETH_ALEN]; 2376189251Ssam 2377189251Ssam /* cmd: "<network id> <BSSID>" */ 2378189251Ssam pos = os_strchr(cmd, ' '); 2379189251Ssam if (pos == NULL) 2380189251Ssam return -1; 2381189251Ssam *pos++ = '\0'; 2382189251Ssam id = atoi(cmd); 2383189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos); 2384189251Ssam if (hwaddr_aton(pos, bssid)) { 2385189251Ssam wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos); 2386189251Ssam return -1; 2387189251Ssam } 2388189251Ssam 2389189251Ssam ssid = wpa_config_get_network(wpa_s->conf, id); 2390189251Ssam if (ssid == NULL) { 2391189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 2392189251Ssam "to update", id); 2393189251Ssam return -1; 2394189251Ssam } 2395189251Ssam 2396189251Ssam os_memcpy(ssid->bssid, bssid, ETH_ALEN); 2397189251Ssam ssid->bssid_set = !is_zero_ether_addr(bssid); 2398189251Ssam 2399189251Ssam return 0; 2400189251Ssam} 2401189251Ssam 2402189251Ssam 2403252726Srpaulostatic int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s, 2404252726Srpaulo char *cmd, char *buf, 2405252726Srpaulo size_t buflen) 2406252726Srpaulo{ 2407252726Srpaulo u8 bssid[ETH_ALEN]; 2408252726Srpaulo struct wpa_blacklist *e; 2409252726Srpaulo char *pos, *end; 2410252726Srpaulo int ret; 2411252726Srpaulo 2412252726Srpaulo /* cmd: "BLACKLIST [<BSSID>]" */ 2413252726Srpaulo if (*cmd == '\0') { 2414252726Srpaulo pos = buf; 2415252726Srpaulo end = buf + buflen; 2416252726Srpaulo e = wpa_s->blacklist; 2417252726Srpaulo while (e) { 2418252726Srpaulo ret = os_snprintf(pos, end - pos, MACSTR "\n", 2419252726Srpaulo MAC2STR(e->bssid)); 2420281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2421252726Srpaulo return pos - buf; 2422252726Srpaulo pos += ret; 2423252726Srpaulo e = e->next; 2424252726Srpaulo } 2425252726Srpaulo return pos - buf; 2426252726Srpaulo } 2427252726Srpaulo 2428252726Srpaulo cmd++; 2429252726Srpaulo if (os_strncmp(cmd, "clear", 5) == 0) { 2430252726Srpaulo wpa_blacklist_clear(wpa_s); 2431252726Srpaulo os_memcpy(buf, "OK\n", 3); 2432252726Srpaulo return 3; 2433252726Srpaulo } 2434252726Srpaulo 2435252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd); 2436252726Srpaulo if (hwaddr_aton(cmd, bssid)) { 2437252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd); 2438252726Srpaulo return -1; 2439252726Srpaulo } 2440252726Srpaulo 2441252726Srpaulo /* 2442252726Srpaulo * Add the BSSID twice, so its count will be 2, causing it to be 2443252726Srpaulo * skipped when processing scan results. 2444252726Srpaulo */ 2445252726Srpaulo ret = wpa_blacklist_add(wpa_s, bssid); 2446281806Srpaulo if (ret < 0) 2447252726Srpaulo return -1; 2448252726Srpaulo ret = wpa_blacklist_add(wpa_s, bssid); 2449281806Srpaulo if (ret < 0) 2450252726Srpaulo return -1; 2451252726Srpaulo os_memcpy(buf, "OK\n", 3); 2452252726Srpaulo return 3; 2453252726Srpaulo} 2454252726Srpaulo 2455252726Srpaulo 2456252726Srpaulostatic int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s, 2457252726Srpaulo char *cmd, char *buf, 2458252726Srpaulo size_t buflen) 2459252726Srpaulo{ 2460252726Srpaulo char *pos, *end, *stamp; 2461252726Srpaulo int ret; 2462252726Srpaulo 2463252726Srpaulo /* cmd: "LOG_LEVEL [<level>]" */ 2464252726Srpaulo if (*cmd == '\0') { 2465252726Srpaulo pos = buf; 2466252726Srpaulo end = buf + buflen; 2467252726Srpaulo ret = os_snprintf(pos, end - pos, "Current level: %s\n" 2468252726Srpaulo "Timestamp: %d\n", 2469252726Srpaulo debug_level_str(wpa_debug_level), 2470252726Srpaulo wpa_debug_timestamp); 2471281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2472252726Srpaulo ret = 0; 2473252726Srpaulo 2474252726Srpaulo return ret; 2475252726Srpaulo } 2476252726Srpaulo 2477252726Srpaulo while (*cmd == ' ') 2478252726Srpaulo cmd++; 2479252726Srpaulo 2480252726Srpaulo stamp = os_strchr(cmd, ' '); 2481252726Srpaulo if (stamp) { 2482252726Srpaulo *stamp++ = '\0'; 2483252726Srpaulo while (*stamp == ' ') { 2484252726Srpaulo stamp++; 2485252726Srpaulo } 2486252726Srpaulo } 2487252726Srpaulo 2488289549Srpaulo if (os_strlen(cmd)) { 2489252726Srpaulo int level = str_to_debug_level(cmd); 2490252726Srpaulo if (level < 0) 2491252726Srpaulo return -1; 2492252726Srpaulo wpa_debug_level = level; 2493252726Srpaulo } 2494252726Srpaulo 2495252726Srpaulo if (stamp && os_strlen(stamp)) 2496252726Srpaulo wpa_debug_timestamp = atoi(stamp); 2497252726Srpaulo 2498252726Srpaulo os_memcpy(buf, "OK\n", 3); 2499252726Srpaulo return 3; 2500252726Srpaulo} 2501252726Srpaulo 2502252726Srpaulo 2503189251Ssamstatic int wpa_supplicant_ctrl_iface_list_networks( 2504281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 2505189251Ssam{ 2506281806Srpaulo char *pos, *end, *prev; 2507189251Ssam struct wpa_ssid *ssid; 2508189251Ssam int ret; 2509189251Ssam 2510189251Ssam pos = buf; 2511189251Ssam end = buf + buflen; 2512189251Ssam ret = os_snprintf(pos, end - pos, 2513189251Ssam "network id / ssid / bssid / flags\n"); 2514281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2515189251Ssam return pos - buf; 2516189251Ssam pos += ret; 2517189251Ssam 2518189251Ssam ssid = wpa_s->conf->ssid; 2519281806Srpaulo 2520281806Srpaulo /* skip over ssids until we find next one */ 2521281806Srpaulo if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) { 2522281806Srpaulo int last_id = atoi(cmd + 8); 2523281806Srpaulo if (last_id != -1) { 2524281806Srpaulo while (ssid != NULL && ssid->id <= last_id) { 2525281806Srpaulo ssid = ssid->next; 2526281806Srpaulo } 2527281806Srpaulo } 2528281806Srpaulo } 2529281806Srpaulo 2530189251Ssam while (ssid) { 2531281806Srpaulo prev = pos; 2532189251Ssam ret = os_snprintf(pos, end - pos, "%d\t%s", 2533189251Ssam ssid->id, 2534189251Ssam wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 2535281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2536281806Srpaulo return prev - buf; 2537189251Ssam pos += ret; 2538189251Ssam if (ssid->bssid_set) { 2539189251Ssam ret = os_snprintf(pos, end - pos, "\t" MACSTR, 2540189251Ssam MAC2STR(ssid->bssid)); 2541189251Ssam } else { 2542189251Ssam ret = os_snprintf(pos, end - pos, "\tany"); 2543189251Ssam } 2544281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2545281806Srpaulo return prev - buf; 2546189251Ssam pos += ret; 2547252726Srpaulo ret = os_snprintf(pos, end - pos, "\t%s%s%s%s", 2548189251Ssam ssid == wpa_s->current_ssid ? 2549189251Ssam "[CURRENT]" : "", 2550252726Srpaulo ssid->disabled ? "[DISABLED]" : "", 2551252726Srpaulo ssid->disabled_until.sec ? 2552252726Srpaulo "[TEMP-DISABLED]" : "", 2553252726Srpaulo ssid->disabled == 2 ? "[P2P-PERSISTENT]" : 2554252726Srpaulo ""); 2555281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2556281806Srpaulo return prev - buf; 2557189251Ssam pos += ret; 2558189251Ssam ret = os_snprintf(pos, end - pos, "\n"); 2559281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2560281806Srpaulo return prev - buf; 2561189251Ssam pos += ret; 2562189251Ssam 2563189251Ssam ssid = ssid->next; 2564189251Ssam } 2565189251Ssam 2566189251Ssam return pos - buf; 2567189251Ssam} 2568189251Ssam 2569189251Ssam 2570189251Ssamstatic char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) 2571189251Ssam{ 2572281806Srpaulo int ret; 2573189251Ssam ret = os_snprintf(pos, end - pos, "-"); 2574281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2575189251Ssam return pos; 2576189251Ssam pos += ret; 2577281806Srpaulo ret = wpa_write_ciphers(pos, end, cipher, "+"); 2578281806Srpaulo if (ret < 0) 2579281806Srpaulo return pos; 2580281806Srpaulo pos += ret; 2581189251Ssam return pos; 2582189251Ssam} 2583189251Ssam 2584189251Ssam 2585189251Ssamstatic char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, 2586189251Ssam const u8 *ie, size_t ie_len) 2587189251Ssam{ 2588189251Ssam struct wpa_ie_data data; 2589281806Srpaulo char *start; 2590281806Srpaulo int ret; 2591189251Ssam 2592189251Ssam ret = os_snprintf(pos, end - pos, "[%s-", proto); 2593281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2594189251Ssam return pos; 2595189251Ssam pos += ret; 2596189251Ssam 2597189251Ssam if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) { 2598189251Ssam ret = os_snprintf(pos, end - pos, "?]"); 2599281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2600189251Ssam return pos; 2601189251Ssam pos += ret; 2602189251Ssam return pos; 2603189251Ssam } 2604189251Ssam 2605281806Srpaulo start = pos; 2606189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 2607281806Srpaulo ret = os_snprintf(pos, end - pos, "%sEAP", 2608281806Srpaulo pos == start ? "" : "+"); 2609281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2610189251Ssam return pos; 2611189251Ssam pos += ret; 2612189251Ssam } 2613189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_PSK) { 2614281806Srpaulo ret = os_snprintf(pos, end - pos, "%sPSK", 2615281806Srpaulo pos == start ? "" : "+"); 2616281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2617189251Ssam return pos; 2618189251Ssam pos += ret; 2619189251Ssam } 2620189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 2621281806Srpaulo ret = os_snprintf(pos, end - pos, "%sNone", 2622281806Srpaulo pos == start ? "" : "+"); 2623281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2624189251Ssam return pos; 2625189251Ssam pos += ret; 2626189251Ssam } 2627281806Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_SAE) { 2628281806Srpaulo ret = os_snprintf(pos, end - pos, "%sSAE", 2629281806Srpaulo pos == start ? "" : "+"); 2630281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2631281806Srpaulo return pos; 2632281806Srpaulo pos += ret; 2633281806Srpaulo } 2634189251Ssam#ifdef CONFIG_IEEE80211R 2635189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 2636189251Ssam ret = os_snprintf(pos, end - pos, "%sFT/EAP", 2637281806Srpaulo pos == start ? "" : "+"); 2638281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2639189251Ssam return pos; 2640189251Ssam pos += ret; 2641189251Ssam } 2642189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) { 2643189251Ssam ret = os_snprintf(pos, end - pos, "%sFT/PSK", 2644281806Srpaulo pos == start ? "" : "+"); 2645281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2646189251Ssam return pos; 2647189251Ssam pos += ret; 2648189251Ssam } 2649281806Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) { 2650281806Srpaulo ret = os_snprintf(pos, end - pos, "%sFT/SAE", 2651281806Srpaulo pos == start ? "" : "+"); 2652281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2653281806Srpaulo return pos; 2654281806Srpaulo pos += ret; 2655281806Srpaulo } 2656189251Ssam#endif /* CONFIG_IEEE80211R */ 2657189251Ssam#ifdef CONFIG_IEEE80211W 2658189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 2659189251Ssam ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", 2660281806Srpaulo pos == start ? "" : "+"); 2661281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2662189251Ssam return pos; 2663189251Ssam pos += ret; 2664189251Ssam } 2665189251Ssam if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 2666189251Ssam ret = os_snprintf(pos, end - pos, "%sPSK-SHA256", 2667281806Srpaulo pos == start ? "" : "+"); 2668281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2669189251Ssam return pos; 2670189251Ssam pos += ret; 2671189251Ssam } 2672189251Ssam#endif /* CONFIG_IEEE80211W */ 2673189251Ssam 2674281806Srpaulo#ifdef CONFIG_SUITEB 2675281806Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 2676281806Srpaulo ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B", 2677281806Srpaulo pos == start ? "" : "+"); 2678281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2679281806Srpaulo return pos; 2680281806Srpaulo pos += ret; 2681281806Srpaulo } 2682281806Srpaulo#endif /* CONFIG_SUITEB */ 2683281806Srpaulo 2684281806Srpaulo#ifdef CONFIG_SUITEB192 2685281806Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 2686281806Srpaulo ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192", 2687281806Srpaulo pos == start ? "" : "+"); 2688281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2689281806Srpaulo return pos; 2690281806Srpaulo pos += ret; 2691281806Srpaulo } 2692281806Srpaulo#endif /* CONFIG_SUITEB192 */ 2693281806Srpaulo 2694346981Scy#ifdef CONFIG_FILS 2695346981Scy if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { 2696346981Scy ret = os_snprintf(pos, end - pos, "%sFILS-SHA256", 2697346981Scy pos == start ? "" : "+"); 2698346981Scy if (os_snprintf_error(end - pos, ret)) 2699346981Scy return pos; 2700346981Scy pos += ret; 2701346981Scy } 2702346981Scy if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { 2703346981Scy ret = os_snprintf(pos, end - pos, "%sFILS-SHA384", 2704346981Scy pos == start ? "" : "+"); 2705346981Scy if (os_snprintf_error(end - pos, ret)) 2706346981Scy return pos; 2707346981Scy pos += ret; 2708346981Scy } 2709346981Scy#ifdef CONFIG_IEEE80211R 2710346981Scy if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { 2711346981Scy ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256", 2712346981Scy pos == start ? "" : "+"); 2713346981Scy if (os_snprintf_error(end - pos, ret)) 2714346981Scy return pos; 2715346981Scy pos += ret; 2716346981Scy } 2717346981Scy if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { 2718346981Scy ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384", 2719346981Scy pos == start ? "" : "+"); 2720346981Scy if (os_snprintf_error(end - pos, ret)) 2721346981Scy return pos; 2722346981Scy pos += ret; 2723346981Scy } 2724346981Scy#endif /* CONFIG_IEEE80211R */ 2725346981Scy#endif /* CONFIG_FILS */ 2726346981Scy 2727346981Scy#ifdef CONFIG_OWE 2728346981Scy if (data.key_mgmt & WPA_KEY_MGMT_OWE) { 2729346981Scy ret = os_snprintf(pos, end - pos, "%sOWE", 2730346981Scy pos == start ? "" : "+"); 2731346981Scy if (os_snprintf_error(end - pos, ret)) 2732346981Scy return pos; 2733346981Scy pos += ret; 2734346981Scy } 2735346981Scy#endif /* CONFIG_OWE */ 2736346981Scy 2737346981Scy#ifdef CONFIG_DPP 2738346981Scy if (data.key_mgmt & WPA_KEY_MGMT_DPP) { 2739346981Scy ret = os_snprintf(pos, end - pos, "%sDPP", 2740346981Scy pos == start ? "" : "+"); 2741346981Scy if (os_snprintf_error(end - pos, ret)) 2742346981Scy return pos; 2743346981Scy pos += ret; 2744346981Scy } 2745346981Scy#endif /* CONFIG_DPP */ 2746346981Scy 2747289549Srpaulo if (data.key_mgmt & WPA_KEY_MGMT_OSEN) { 2748289549Srpaulo ret = os_snprintf(pos, end - pos, "%sOSEN", 2749289549Srpaulo pos == start ? "" : "+"); 2750289549Srpaulo if (os_snprintf_error(end - pos, ret)) 2751289549Srpaulo return pos; 2752289549Srpaulo pos += ret; 2753289549Srpaulo } 2754289549Srpaulo 2755189251Ssam pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); 2756189251Ssam 2757189251Ssam if (data.capabilities & WPA_CAPABILITY_PREAUTH) { 2758189251Ssam ret = os_snprintf(pos, end - pos, "-preauth"); 2759281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2760189251Ssam return pos; 2761189251Ssam pos += ret; 2762189251Ssam } 2763189251Ssam 2764189251Ssam ret = os_snprintf(pos, end - pos, "]"); 2765281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2766189251Ssam return pos; 2767189251Ssam pos += ret; 2768189251Ssam 2769189251Ssam return pos; 2770189251Ssam} 2771189251Ssam 2772214734Srpaulo 2773214734Srpaulo#ifdef CONFIG_WPS 2774252726Srpaulostatic char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s, 2775252726Srpaulo char *pos, char *end, 2776214734Srpaulo struct wpabuf *wps_ie) 2777189251Ssam{ 2778189251Ssam int ret; 2779189251Ssam const char *txt; 2780189251Ssam 2781189251Ssam if (wps_ie == NULL) 2782189251Ssam return pos; 2783189251Ssam if (wps_is_selected_pbc_registrar(wps_ie)) 2784189251Ssam txt = "[WPS-PBC]"; 2785252726Srpaulo else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0)) 2786252726Srpaulo txt = "[WPS-AUTH]"; 2787189251Ssam else if (wps_is_selected_pin_registrar(wps_ie)) 2788189251Ssam txt = "[WPS-PIN]"; 2789189251Ssam else 2790189251Ssam txt = "[WPS]"; 2791189251Ssam 2792189251Ssam ret = os_snprintf(pos, end - pos, "%s", txt); 2793281806Srpaulo if (!os_snprintf_error(end - pos, ret)) 2794189251Ssam pos += ret; 2795189251Ssam wpabuf_free(wps_ie); 2796214734Srpaulo return pos; 2797214734Srpaulo} 2798189251Ssam#endif /* CONFIG_WPS */ 2799189251Ssam 2800214734Srpaulo 2801252726Srpaulostatic char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s, 2802252726Srpaulo char *pos, char *end, 2803214734Srpaulo const struct wpa_bss *bss) 2804214734Srpaulo{ 2805214734Srpaulo#ifdef CONFIG_WPS 2806214734Srpaulo struct wpabuf *wps_ie; 2807214734Srpaulo wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 2808252726Srpaulo return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie); 2809214734Srpaulo#else /* CONFIG_WPS */ 2810189251Ssam return pos; 2811214734Srpaulo#endif /* CONFIG_WPS */ 2812189251Ssam} 2813189251Ssam 2814189251Ssam 2815189251Ssam/* Format one result on one text line into a buffer. */ 2816189251Ssamstatic int wpa_supplicant_ctrl_iface_scan_result( 2817252726Srpaulo struct wpa_supplicant *wpa_s, 2818214734Srpaulo const struct wpa_bss *bss, char *buf, size_t buflen) 2819189251Ssam{ 2820189251Ssam char *pos, *end; 2821189251Ssam int ret; 2822346981Scy const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe; 2823189251Ssam 2824281806Srpaulo mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); 2825252726Srpaulo p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); 2826281806Srpaulo if (!p2p) 2827281806Srpaulo p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE); 2828252726Srpaulo if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN && 2829252726Srpaulo os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 2830252726Srpaulo 0) 2831252726Srpaulo return 0; /* Do not show P2P listen discovery results here */ 2832252726Srpaulo 2833189251Ssam pos = buf; 2834189251Ssam end = buf + buflen; 2835189251Ssam 2836189251Ssam ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", 2837214734Srpaulo MAC2STR(bss->bssid), bss->freq, bss->level); 2838281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2839252726Srpaulo return -1; 2840189251Ssam pos += ret; 2841214734Srpaulo ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 2842189251Ssam if (ie) 2843189251Ssam pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); 2844214734Srpaulo ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); 2845281806Srpaulo if (ie2) { 2846281806Srpaulo pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2", 2847281806Srpaulo ie2, 2 + ie2[1]); 2848281806Srpaulo } 2849289549Srpaulo osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); 2850289549Srpaulo if (osen_ie) 2851289549Srpaulo pos = wpa_supplicant_ie_txt(pos, end, "OSEN", 2852289549Srpaulo osen_ie, 2 + osen_ie[1]); 2853346981Scy owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); 2854346981Scy if (owe) { 2855346981Scy ret = os_snprintf(pos, end - pos, 2856346981Scy ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]"); 2857346981Scy if (os_snprintf_error(end - pos, ret)) 2858346981Scy return -1; 2859346981Scy pos += ret; 2860346981Scy } 2861252726Srpaulo pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); 2862289549Srpaulo if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) { 2863189251Ssam ret = os_snprintf(pos, end - pos, "[WEP]"); 2864281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2865252726Srpaulo return -1; 2866189251Ssam pos += ret; 2867189251Ssam } 2868281806Srpaulo if (mesh) { 2869281806Srpaulo ret = os_snprintf(pos, end - pos, "[MESH]"); 2870281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2871252726Srpaulo return -1; 2872189251Ssam pos += ret; 2873189251Ssam } 2874281806Srpaulo if (bss_is_dmg(bss)) { 2875281806Srpaulo const char *s; 2876281806Srpaulo ret = os_snprintf(pos, end - pos, "[DMG]"); 2877281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2878252726Srpaulo return -1; 2879214734Srpaulo pos += ret; 2880281806Srpaulo switch (bss->caps & IEEE80211_CAP_DMG_MASK) { 2881281806Srpaulo case IEEE80211_CAP_DMG_IBSS: 2882281806Srpaulo s = "[IBSS]"; 2883281806Srpaulo break; 2884281806Srpaulo case IEEE80211_CAP_DMG_AP: 2885281806Srpaulo s = "[ESS]"; 2886281806Srpaulo break; 2887281806Srpaulo case IEEE80211_CAP_DMG_PBSS: 2888281806Srpaulo s = "[PBSS]"; 2889281806Srpaulo break; 2890281806Srpaulo default: 2891281806Srpaulo s = ""; 2892281806Srpaulo break; 2893281806Srpaulo } 2894281806Srpaulo ret = os_snprintf(pos, end - pos, "%s", s); 2895281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2896281806Srpaulo return -1; 2897281806Srpaulo pos += ret; 2898281806Srpaulo } else { 2899281806Srpaulo if (bss->caps & IEEE80211_CAP_IBSS) { 2900281806Srpaulo ret = os_snprintf(pos, end - pos, "[IBSS]"); 2901281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2902281806Srpaulo return -1; 2903281806Srpaulo pos += ret; 2904281806Srpaulo } 2905281806Srpaulo if (bss->caps & IEEE80211_CAP_ESS) { 2906281806Srpaulo ret = os_snprintf(pos, end - pos, "[ESS]"); 2907281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2908281806Srpaulo return -1; 2909281806Srpaulo pos += ret; 2910281806Srpaulo } 2911214734Srpaulo } 2912252726Srpaulo if (p2p) { 2913252726Srpaulo ret = os_snprintf(pos, end - pos, "[P2P]"); 2914281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2915252726Srpaulo return -1; 2916252726Srpaulo pos += ret; 2917252726Srpaulo } 2918252726Srpaulo#ifdef CONFIG_HS20 2919252726Srpaulo if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) { 2920252726Srpaulo ret = os_snprintf(pos, end - pos, "[HS20]"); 2921281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2922252726Srpaulo return -1; 2923252726Srpaulo pos += ret; 2924252726Srpaulo } 2925252726Srpaulo#endif /* CONFIG_HS20 */ 2926346981Scy#ifdef CONFIG_FILS 2927346981Scy if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { 2928346981Scy ret = os_snprintf(pos, end - pos, "[FILS]"); 2929346981Scy if (os_snprintf_error(end - pos, ret)) 2930346981Scy return -1; 2931346981Scy pos += ret; 2932346981Scy } 2933346981Scy#endif /* CONFIG_FILS */ 2934289549Srpaulo#ifdef CONFIG_FST 2935289549Srpaulo if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { 2936289549Srpaulo ret = os_snprintf(pos, end - pos, "[FST]"); 2937289549Srpaulo if (os_snprintf_error(end - pos, ret)) 2938289549Srpaulo return -1; 2939289549Srpaulo pos += ret; 2940289549Srpaulo } 2941289549Srpaulo#endif /* CONFIG_FST */ 2942346981Scy if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) { 2943346981Scy ret = os_snprintf(pos, end - pos, "[UTF-8]"); 2944346981Scy if (os_snprintf_error(end - pos, ret)) 2945346981Scy return -1; 2946346981Scy pos += ret; 2947346981Scy } 2948189251Ssam 2949189251Ssam ret = os_snprintf(pos, end - pos, "\t%s", 2950214734Srpaulo wpa_ssid_txt(bss->ssid, bss->ssid_len)); 2951281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2952252726Srpaulo return -1; 2953189251Ssam pos += ret; 2954189251Ssam 2955189251Ssam ret = os_snprintf(pos, end - pos, "\n"); 2956281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2957252726Srpaulo return -1; 2958189251Ssam pos += ret; 2959189251Ssam 2960189251Ssam return pos - buf; 2961189251Ssam} 2962189251Ssam 2963189251Ssam 2964189251Ssamstatic int wpa_supplicant_ctrl_iface_scan_results( 2965189251Ssam struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 2966189251Ssam{ 2967189251Ssam char *pos, *end; 2968214734Srpaulo struct wpa_bss *bss; 2969189251Ssam int ret; 2970189251Ssam 2971189251Ssam pos = buf; 2972189251Ssam end = buf + buflen; 2973189251Ssam ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / " 2974189251Ssam "flags / ssid\n"); 2975281806Srpaulo if (os_snprintf_error(end - pos, ret)) 2976189251Ssam return pos - buf; 2977189251Ssam pos += ret; 2978189251Ssam 2979214734Srpaulo dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 2980252726Srpaulo ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos, 2981189251Ssam end - pos); 2982189251Ssam if (ret < 0 || ret >= end - pos) 2983189251Ssam return pos - buf; 2984189251Ssam pos += ret; 2985189251Ssam } 2986189251Ssam 2987189251Ssam return pos - buf; 2988189251Ssam} 2989189251Ssam 2990189251Ssam 2991281806Srpaulo#ifdef CONFIG_MESH 2992281806Srpaulo 2993281806Srpaulostatic int wpa_supplicant_ctrl_iface_mesh_interface_add( 2994281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 2995281806Srpaulo{ 2996281806Srpaulo char *pos, ifname[IFNAMSIZ + 1]; 2997281806Srpaulo 2998281806Srpaulo ifname[0] = '\0'; 2999281806Srpaulo 3000281806Srpaulo pos = os_strstr(cmd, "ifname="); 3001281806Srpaulo if (pos) { 3002281806Srpaulo pos += 7; 3003281806Srpaulo os_strlcpy(ifname, pos, sizeof(ifname)); 3004281806Srpaulo } 3005281806Srpaulo 3006281806Srpaulo if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0) 3007281806Srpaulo return -1; 3008281806Srpaulo 3009281806Srpaulo os_strlcpy(reply, ifname, max_len); 3010281806Srpaulo return os_strlen(ifname); 3011281806Srpaulo} 3012281806Srpaulo 3013281806Srpaulo 3014281806Srpaulostatic int wpa_supplicant_ctrl_iface_mesh_group_add( 3015281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 3016281806Srpaulo{ 3017281806Srpaulo int id; 3018281806Srpaulo struct wpa_ssid *ssid; 3019281806Srpaulo 3020281806Srpaulo id = atoi(cmd); 3021281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id); 3022281806Srpaulo 3023281806Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 3024281806Srpaulo if (ssid == NULL) { 3025281806Srpaulo wpa_printf(MSG_DEBUG, 3026281806Srpaulo "CTRL_IFACE: Could not find network id=%d", id); 3027281806Srpaulo return -1; 3028281806Srpaulo } 3029281806Srpaulo if (ssid->mode != WPAS_MODE_MESH) { 3030281806Srpaulo wpa_printf(MSG_DEBUG, 3031281806Srpaulo "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network"); 3032281806Srpaulo return -1; 3033281806Srpaulo } 3034281806Srpaulo if (ssid->key_mgmt != WPA_KEY_MGMT_NONE && 3035281806Srpaulo ssid->key_mgmt != WPA_KEY_MGMT_SAE) { 3036281806Srpaulo wpa_printf(MSG_ERROR, 3037281806Srpaulo "CTRL_IFACE: key_mgmt for mesh network should be open or SAE"); 3038281806Srpaulo return -1; 3039281806Srpaulo } 3040281806Srpaulo 3041281806Srpaulo /* 3042281806Srpaulo * TODO: If necessary write our own group_add function, 3043281806Srpaulo * for now we can reuse select_network 3044281806Srpaulo */ 3045281806Srpaulo wpa_supplicant_select_network(wpa_s, ssid); 3046281806Srpaulo 3047281806Srpaulo return 0; 3048281806Srpaulo} 3049281806Srpaulo 3050281806Srpaulo 3051281806Srpaulostatic int wpa_supplicant_ctrl_iface_mesh_group_remove( 3052281806Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 3053281806Srpaulo{ 3054281806Srpaulo struct wpa_supplicant *orig; 3055281806Srpaulo struct wpa_global *global; 3056281806Srpaulo int found = 0; 3057281806Srpaulo 3058281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd); 3059281806Srpaulo 3060281806Srpaulo global = wpa_s->global; 3061281806Srpaulo orig = wpa_s; 3062281806Srpaulo 3063281806Srpaulo for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 3064281806Srpaulo if (os_strcmp(wpa_s->ifname, cmd) == 0) { 3065281806Srpaulo found = 1; 3066281806Srpaulo break; 3067281806Srpaulo } 3068281806Srpaulo } 3069281806Srpaulo if (!found) { 3070281806Srpaulo wpa_printf(MSG_ERROR, 3071281806Srpaulo "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found", 3072281806Srpaulo cmd); 3073281806Srpaulo return -1; 3074281806Srpaulo } 3075281806Srpaulo if (wpa_s->mesh_if_created && wpa_s == orig) { 3076281806Srpaulo wpa_printf(MSG_ERROR, 3077281806Srpaulo "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself"); 3078281806Srpaulo return -1; 3079281806Srpaulo } 3080281806Srpaulo 3081281806Srpaulo wpa_s->reassociate = 0; 3082281806Srpaulo wpa_s->disconnected = 1; 3083281806Srpaulo wpa_supplicant_cancel_sched_scan(wpa_s); 3084281806Srpaulo wpa_supplicant_cancel_scan(wpa_s); 3085281806Srpaulo 3086281806Srpaulo /* 3087281806Srpaulo * TODO: If necessary write our own group_remove function, 3088281806Srpaulo * for now we can reuse deauthenticate 3089281806Srpaulo */ 3090281806Srpaulo wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 3091281806Srpaulo 3092281806Srpaulo if (wpa_s->mesh_if_created) 3093281806Srpaulo wpa_supplicant_remove_iface(global, wpa_s, 0); 3094281806Srpaulo 3095281806Srpaulo return 0; 3096281806Srpaulo} 3097281806Srpaulo 3098337817Scy 3099337817Scystatic int wpa_supplicant_ctrl_iface_mesh_peer_remove( 3100337817Scy struct wpa_supplicant *wpa_s, char *cmd) 3101337817Scy{ 3102337817Scy u8 addr[ETH_ALEN]; 3103337817Scy 3104337817Scy if (hwaddr_aton(cmd, addr) < 0) 3105337817Scy return -1; 3106337817Scy 3107337817Scy return wpas_mesh_peer_remove(wpa_s, addr); 3108337817Scy} 3109337817Scy 3110337817Scy 3111337817Scystatic int wpa_supplicant_ctrl_iface_mesh_peer_add( 3112337817Scy struct wpa_supplicant *wpa_s, char *cmd) 3113337817Scy{ 3114337817Scy u8 addr[ETH_ALEN]; 3115337817Scy int duration; 3116337817Scy char *pos; 3117337817Scy 3118337817Scy pos = os_strstr(cmd, " duration="); 3119337817Scy if (pos) { 3120337817Scy *pos = '\0'; 3121337817Scy duration = atoi(pos + 10); 3122337817Scy } else { 3123337817Scy duration = -1; 3124337817Scy } 3125337817Scy 3126337817Scy if (hwaddr_aton(cmd, addr)) 3127337817Scy return -1; 3128337817Scy 3129337817Scy return wpas_mesh_peer_add(wpa_s, addr, duration); 3130337817Scy} 3131337817Scy 3132351611Scy 3133351611Scystatic int wpa_supplicant_ctrl_iface_mesh_link_probe( 3134351611Scy struct wpa_supplicant *wpa_s, char *cmd) 3135351611Scy{ 3136351611Scy struct ether_header *eth; 3137351611Scy u8 addr[ETH_ALEN]; 3138351611Scy u8 *buf; 3139351611Scy char *pos; 3140351611Scy size_t payload_len = 0, len; 3141351611Scy int ret = -1; 3142351611Scy 3143351611Scy if (hwaddr_aton(cmd, addr)) 3144351611Scy return -1; 3145351611Scy 3146351611Scy pos = os_strstr(cmd, " payload="); 3147351611Scy if (pos) { 3148351611Scy pos = pos + 9; 3149351611Scy payload_len = os_strlen(pos); 3150351611Scy if (payload_len & 1) 3151351611Scy return -1; 3152351611Scy 3153351611Scy payload_len /= 2; 3154351611Scy } 3155351611Scy 3156351611Scy len = ETH_HLEN + payload_len; 3157351611Scy buf = os_malloc(len); 3158351611Scy if (!buf) 3159351611Scy return -1; 3160351611Scy 3161351611Scy eth = (struct ether_header *) buf; 3162351611Scy os_memcpy(eth->ether_dhost, addr, ETH_ALEN); 3163351611Scy os_memcpy(eth->ether_shost, wpa_s->own_addr, ETH_ALEN); 3164351611Scy eth->ether_type = htons(ETH_P_802_3); 3165351611Scy 3166351611Scy if (payload_len && hexstr2bin(pos, buf + ETH_HLEN, payload_len) < 0) 3167351611Scy goto fail; 3168351611Scy 3169351611Scy ret = wpa_drv_mesh_link_probe(wpa_s, addr, buf, len); 3170351611Scyfail: 3171351611Scy os_free(buf); 3172351611Scy return -ret; 3173351611Scy} 3174351611Scy 3175281806Srpaulo#endif /* CONFIG_MESH */ 3176281806Srpaulo 3177281806Srpaulo 3178189251Ssamstatic int wpa_supplicant_ctrl_iface_select_network( 3179189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 3180189251Ssam{ 3181189251Ssam int id; 3182189251Ssam struct wpa_ssid *ssid; 3183281806Srpaulo char *pos; 3184189251Ssam 3185189251Ssam /* cmd: "<network id>" or "any" */ 3186281806Srpaulo if (os_strncmp(cmd, "any", 3) == 0) { 3187189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any"); 3188214734Srpaulo ssid = NULL; 3189214734Srpaulo } else { 3190214734Srpaulo id = atoi(cmd); 3191214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id); 3192214734Srpaulo 3193214734Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 3194214734Srpaulo if (ssid == NULL) { 3195214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3196214734Srpaulo "network id=%d", id); 3197214734Srpaulo return -1; 3198189251Ssam } 3199252726Srpaulo if (ssid->disabled == 2) { 3200252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 3201252726Srpaulo "SELECT_NETWORK with persistent P2P group"); 3202252726Srpaulo return -1; 3203252726Srpaulo } 3204189251Ssam } 3205189251Ssam 3206281806Srpaulo pos = os_strstr(cmd, " freq="); 3207281806Srpaulo if (pos) { 3208281806Srpaulo int *freqs = freq_range_to_channel_list(wpa_s, pos + 6); 3209281806Srpaulo if (freqs) { 3210346981Scy os_free(wpa_s->select_network_scan_freqs); 3211346981Scy wpa_s->select_network_scan_freqs = freqs; 3212281806Srpaulo } 3213281806Srpaulo } 3214281806Srpaulo 3215289549Srpaulo wpa_s->scan_min_time.sec = 0; 3216289549Srpaulo wpa_s->scan_min_time.usec = 0; 3217214734Srpaulo wpa_supplicant_select_network(wpa_s, ssid); 3218189251Ssam 3219189251Ssam return 0; 3220189251Ssam} 3221189251Ssam 3222189251Ssam 3223189251Ssamstatic int wpa_supplicant_ctrl_iface_enable_network( 3224189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 3225189251Ssam{ 3226189251Ssam int id; 3227189251Ssam struct wpa_ssid *ssid; 3228189251Ssam 3229189251Ssam /* cmd: "<network id>" or "all" */ 3230189251Ssam if (os_strcmp(cmd, "all") == 0) { 3231189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all"); 3232214734Srpaulo ssid = NULL; 3233214734Srpaulo } else { 3234214734Srpaulo id = atoi(cmd); 3235214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id); 3236214734Srpaulo 3237214734Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 3238214734Srpaulo if (ssid == NULL) { 3239214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3240214734Srpaulo "network id=%d", id); 3241214734Srpaulo return -1; 3242189251Ssam } 3243252726Srpaulo if (ssid->disabled == 2) { 3244252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 3245252726Srpaulo "ENABLE_NETWORK with persistent P2P group"); 3246252726Srpaulo return -1; 3247252726Srpaulo } 3248252726Srpaulo 3249252726Srpaulo if (os_strstr(cmd, " no-connect")) { 3250252726Srpaulo ssid->disabled = 0; 3251252726Srpaulo return 0; 3252252726Srpaulo } 3253189251Ssam } 3254289549Srpaulo wpa_s->scan_min_time.sec = 0; 3255289549Srpaulo wpa_s->scan_min_time.usec = 0; 3256214734Srpaulo wpa_supplicant_enable_network(wpa_s, ssid); 3257189251Ssam 3258189251Ssam return 0; 3259189251Ssam} 3260189251Ssam 3261189251Ssam 3262189251Ssamstatic int wpa_supplicant_ctrl_iface_disable_network( 3263189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 3264189251Ssam{ 3265189251Ssam int id; 3266189251Ssam struct wpa_ssid *ssid; 3267189251Ssam 3268189251Ssam /* cmd: "<network id>" or "all" */ 3269189251Ssam if (os_strcmp(cmd, "all") == 0) { 3270189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all"); 3271214734Srpaulo ssid = NULL; 3272214734Srpaulo } else { 3273214734Srpaulo id = atoi(cmd); 3274214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id); 3275214734Srpaulo 3276214734Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 3277214734Srpaulo if (ssid == NULL) { 3278214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3279214734Srpaulo "network id=%d", id); 3280214734Srpaulo return -1; 3281189251Ssam } 3282252726Srpaulo if (ssid->disabled == 2) { 3283252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 3284252726Srpaulo "DISABLE_NETWORK with persistent P2P " 3285252726Srpaulo "group"); 3286252726Srpaulo return -1; 3287252726Srpaulo } 3288189251Ssam } 3289214734Srpaulo wpa_supplicant_disable_network(wpa_s, ssid); 3290189251Ssam 3291189251Ssam return 0; 3292189251Ssam} 3293189251Ssam 3294189251Ssam 3295189251Ssamstatic int wpa_supplicant_ctrl_iface_add_network( 3296189251Ssam struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 3297189251Ssam{ 3298189251Ssam struct wpa_ssid *ssid; 3299189251Ssam int ret; 3300189251Ssam 3301189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); 3302189251Ssam 3303337817Scy ssid = wpa_supplicant_add_network(wpa_s); 3304189251Ssam if (ssid == NULL) 3305189251Ssam return -1; 3306214734Srpaulo 3307189251Ssam ret = os_snprintf(buf, buflen, "%d\n", ssid->id); 3308281806Srpaulo if (os_snprintf_error(buflen, ret)) 3309189251Ssam return -1; 3310189251Ssam return ret; 3311189251Ssam} 3312189251Ssam 3313189251Ssam 3314189251Ssamstatic int wpa_supplicant_ctrl_iface_remove_network( 3315189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 3316189251Ssam{ 3317189251Ssam int id; 3318189251Ssam struct wpa_ssid *ssid; 3319337817Scy int result; 3320189251Ssam 3321189251Ssam /* cmd: "<network id>" or "all" */ 3322189251Ssam if (os_strcmp(cmd, "all") == 0) { 3323189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); 3324281806Srpaulo if (wpa_s->sched_scanning) 3325281806Srpaulo wpa_supplicant_cancel_sched_scan(wpa_s); 3326281806Srpaulo 3327252726Srpaulo eapol_sm_invalidate_cached_session(wpa_s->eapol); 3328189251Ssam if (wpa_s->current_ssid) { 3329252726Srpaulo#ifdef CONFIG_SME 3330252726Srpaulo wpa_s->sme.prev_bssid_set = 0; 3331252726Srpaulo#endif /* CONFIG_SME */ 3332252726Srpaulo wpa_sm_set_config(wpa_s->wpa, NULL); 3333252726Srpaulo eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); 3334289549Srpaulo if (wpa_s->wpa_state >= WPA_AUTHENTICATING) 3335289549Srpaulo wpa_s->own_disconnect_req = 1; 3336252726Srpaulo wpa_supplicant_deauthenticate( 3337252726Srpaulo wpa_s, WLAN_REASON_DEAUTH_LEAVING); 3338189251Ssam } 3339281806Srpaulo ssid = wpa_s->conf->ssid; 3340281806Srpaulo while (ssid) { 3341281806Srpaulo struct wpa_ssid *remove_ssid = ssid; 3342281806Srpaulo id = ssid->id; 3343281806Srpaulo ssid = ssid->next; 3344281806Srpaulo if (wpa_s->last_ssid == remove_ssid) 3345281806Srpaulo wpa_s->last_ssid = NULL; 3346281806Srpaulo wpas_notify_network_removed(wpa_s, remove_ssid); 3347281806Srpaulo wpa_config_remove_network(wpa_s->conf, id); 3348281806Srpaulo } 3349189251Ssam return 0; 3350189251Ssam } 3351189251Ssam 3352189251Ssam id = atoi(cmd); 3353189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); 3354189251Ssam 3355337817Scy result = wpa_supplicant_remove_network(wpa_s, id); 3356337817Scy if (result == -1) { 3357189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " 3358189251Ssam "id=%d", id); 3359189251Ssam return -1; 3360189251Ssam } 3361337817Scy if (result == -2) { 3362252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the " 3363252726Srpaulo "network id=%d", id); 3364252726Srpaulo return -1; 3365252726Srpaulo } 3366189251Ssam return 0; 3367189251Ssam} 3368189251Ssam 3369189251Ssam 3370281806Srpaulostatic int wpa_supplicant_ctrl_iface_update_network( 3371281806Srpaulo struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, 3372281806Srpaulo char *name, char *value) 3373281806Srpaulo{ 3374337817Scy int ret; 3375337817Scy 3376337817Scy ret = wpa_config_set(ssid, name, value, 0); 3377337817Scy if (ret < 0) { 3378281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " 3379281806Srpaulo "variable '%s'", name); 3380281806Srpaulo return -1; 3381281806Srpaulo } 3382337817Scy if (ret == 1) 3383337817Scy return 0; /* No change to the previously configured value */ 3384281806Srpaulo 3385281806Srpaulo if (os_strcmp(name, "bssid") != 0 && 3386346981Scy os_strcmp(name, "bssid_hint") != 0 && 3387337817Scy os_strcmp(name, "priority") != 0) { 3388281806Srpaulo wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); 3389281806Srpaulo 3390337817Scy if (wpa_s->current_ssid == ssid || 3391337817Scy wpa_s->current_ssid == NULL) { 3392337817Scy /* 3393337817Scy * Invalidate the EAP session cache if anything in the 3394337817Scy * current or previously used configuration changes. 3395337817Scy */ 3396337817Scy eapol_sm_invalidate_cached_session(wpa_s->eapol); 3397337817Scy } 3398281806Srpaulo } 3399281806Srpaulo 3400281806Srpaulo if ((os_strcmp(name, "psk") == 0 && 3401281806Srpaulo value[0] == '"' && ssid->ssid_len) || 3402281806Srpaulo (os_strcmp(name, "ssid") == 0 && ssid->passphrase)) 3403281806Srpaulo wpa_config_update_psk(ssid); 3404281806Srpaulo else if (os_strcmp(name, "priority") == 0) 3405281806Srpaulo wpa_config_update_prio_list(wpa_s->conf); 3406281806Srpaulo 3407281806Srpaulo return 0; 3408281806Srpaulo} 3409281806Srpaulo 3410281806Srpaulo 3411189251Ssamstatic int wpa_supplicant_ctrl_iface_set_network( 3412189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 3413189251Ssam{ 3414281806Srpaulo int id, ret, prev_bssid_set, prev_disabled; 3415189251Ssam struct wpa_ssid *ssid; 3416189251Ssam char *name, *value; 3417281806Srpaulo u8 prev_bssid[ETH_ALEN]; 3418189251Ssam 3419189251Ssam /* cmd: "<network id> <variable name> <value>" */ 3420189251Ssam name = os_strchr(cmd, ' '); 3421189251Ssam if (name == NULL) 3422189251Ssam return -1; 3423189251Ssam *name++ = '\0'; 3424189251Ssam 3425189251Ssam value = os_strchr(name, ' '); 3426189251Ssam if (value == NULL) 3427189251Ssam return -1; 3428189251Ssam *value++ = '\0'; 3429189251Ssam 3430189251Ssam id = atoi(cmd); 3431189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'", 3432189251Ssam id, name); 3433189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 3434189251Ssam (u8 *) value, os_strlen(value)); 3435189251Ssam 3436189251Ssam ssid = wpa_config_get_network(wpa_s->conf, id); 3437189251Ssam if (ssid == NULL) { 3438189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " 3439189251Ssam "id=%d", id); 3440189251Ssam return -1; 3441189251Ssam } 3442189251Ssam 3443281806Srpaulo prev_bssid_set = ssid->bssid_set; 3444281806Srpaulo prev_disabled = ssid->disabled; 3445281806Srpaulo os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN); 3446281806Srpaulo ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, 3447281806Srpaulo value); 3448281806Srpaulo if (ret == 0 && 3449281806Srpaulo (ssid->bssid_set != prev_bssid_set || 3450281806Srpaulo os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0)) 3451281806Srpaulo wpas_notify_network_bssid_set_changed(wpa_s, ssid); 3452189251Ssam 3453281806Srpaulo if (prev_disabled != ssid->disabled && 3454281806Srpaulo (prev_disabled == 2 || ssid->disabled == 2)) 3455281806Srpaulo wpas_notify_network_type_changed(wpa_s, ssid); 3456252726Srpaulo 3457281806Srpaulo return ret; 3458189251Ssam} 3459189251Ssam 3460189251Ssam 3461189251Ssamstatic int wpa_supplicant_ctrl_iface_get_network( 3462189251Ssam struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 3463189251Ssam{ 3464189251Ssam int id; 3465189251Ssam size_t res; 3466189251Ssam struct wpa_ssid *ssid; 3467189251Ssam char *name, *value; 3468189251Ssam 3469189251Ssam /* cmd: "<network id> <variable name>" */ 3470189251Ssam name = os_strchr(cmd, ' '); 3471189251Ssam if (name == NULL || buflen == 0) 3472189251Ssam return -1; 3473189251Ssam *name++ = '\0'; 3474189251Ssam 3475189251Ssam id = atoi(cmd); 3476289549Srpaulo wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'", 3477189251Ssam id, name); 3478189251Ssam 3479189251Ssam ssid = wpa_config_get_network(wpa_s->conf, id); 3480189251Ssam if (ssid == NULL) { 3481289549Srpaulo wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network " 3482189251Ssam "id=%d", id); 3483189251Ssam return -1; 3484189251Ssam } 3485189251Ssam 3486189251Ssam value = wpa_config_get_no_key(ssid, name); 3487189251Ssam if (value == NULL) { 3488289549Srpaulo wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network " 3489189251Ssam "variable '%s'", name); 3490189251Ssam return -1; 3491189251Ssam } 3492189251Ssam 3493189251Ssam res = os_strlcpy(buf, value, buflen); 3494189251Ssam if (res >= buflen) { 3495189251Ssam os_free(value); 3496189251Ssam return -1; 3497189251Ssam } 3498189251Ssam 3499189251Ssam os_free(value); 3500189251Ssam 3501189251Ssam return res; 3502189251Ssam} 3503189251Ssam 3504189251Ssam 3505281806Srpaulostatic int wpa_supplicant_ctrl_iface_dup_network( 3506289549Srpaulo struct wpa_supplicant *wpa_s, char *cmd, 3507289549Srpaulo struct wpa_supplicant *dst_wpa_s) 3508281806Srpaulo{ 3509281806Srpaulo struct wpa_ssid *ssid_s, *ssid_d; 3510281806Srpaulo char *name, *id, *value; 3511281806Srpaulo int id_s, id_d, ret; 3512281806Srpaulo 3513281806Srpaulo /* cmd: "<src network id> <dst network id> <variable name>" */ 3514281806Srpaulo id = os_strchr(cmd, ' '); 3515281806Srpaulo if (id == NULL) 3516281806Srpaulo return -1; 3517281806Srpaulo *id++ = '\0'; 3518281806Srpaulo 3519281806Srpaulo name = os_strchr(id, ' '); 3520281806Srpaulo if (name == NULL) 3521281806Srpaulo return -1; 3522281806Srpaulo *name++ = '\0'; 3523281806Srpaulo 3524281806Srpaulo id_s = atoi(cmd); 3525281806Srpaulo id_d = atoi(id); 3526281806Srpaulo 3527289549Srpaulo wpa_printf(MSG_DEBUG, 3528289549Srpaulo "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'", 3529289549Srpaulo wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name); 3530289549Srpaulo 3531281806Srpaulo ssid_s = wpa_config_get_network(wpa_s->conf, id_s); 3532281806Srpaulo if (ssid_s == NULL) { 3533281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3534281806Srpaulo "network id=%d", id_s); 3535281806Srpaulo return -1; 3536281806Srpaulo } 3537281806Srpaulo 3538289549Srpaulo ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d); 3539281806Srpaulo if (ssid_d == NULL) { 3540281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3541281806Srpaulo "network id=%d", id_d); 3542281806Srpaulo return -1; 3543281806Srpaulo } 3544281806Srpaulo 3545281806Srpaulo value = wpa_config_get(ssid_s, name); 3546281806Srpaulo if (value == NULL) { 3547281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " 3548281806Srpaulo "variable '%s'", name); 3549281806Srpaulo return -1; 3550281806Srpaulo } 3551281806Srpaulo 3552289549Srpaulo ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name, 3553281806Srpaulo value); 3554281806Srpaulo 3555281806Srpaulo os_free(value); 3556281806Srpaulo 3557281806Srpaulo return ret; 3558281806Srpaulo} 3559281806Srpaulo 3560281806Srpaulo 3561252726Srpaulostatic int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s, 3562252726Srpaulo char *buf, size_t buflen) 3563252726Srpaulo{ 3564252726Srpaulo char *pos, *end; 3565252726Srpaulo struct wpa_cred *cred; 3566252726Srpaulo int ret; 3567252726Srpaulo 3568252726Srpaulo pos = buf; 3569252726Srpaulo end = buf + buflen; 3570252726Srpaulo ret = os_snprintf(pos, end - pos, 3571252726Srpaulo "cred id / realm / username / domain / imsi\n"); 3572281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3573252726Srpaulo return pos - buf; 3574252726Srpaulo pos += ret; 3575252726Srpaulo 3576252726Srpaulo cred = wpa_s->conf->cred; 3577252726Srpaulo while (cred) { 3578252726Srpaulo ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n", 3579252726Srpaulo cred->id, cred->realm ? cred->realm : "", 3580252726Srpaulo cred->username ? cred->username : "", 3581281806Srpaulo cred->domain ? cred->domain[0] : "", 3582252726Srpaulo cred->imsi ? cred->imsi : ""); 3583281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3584252726Srpaulo return pos - buf; 3585252726Srpaulo pos += ret; 3586252726Srpaulo 3587252726Srpaulo cred = cred->next; 3588252726Srpaulo } 3589252726Srpaulo 3590252726Srpaulo return pos - buf; 3591252726Srpaulo} 3592252726Srpaulo 3593252726Srpaulo 3594252726Srpaulostatic int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, 3595252726Srpaulo char *buf, size_t buflen) 3596252726Srpaulo{ 3597252726Srpaulo struct wpa_cred *cred; 3598252726Srpaulo int ret; 3599252726Srpaulo 3600252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED"); 3601252726Srpaulo 3602252726Srpaulo cred = wpa_config_add_cred(wpa_s->conf); 3603252726Srpaulo if (cred == NULL) 3604252726Srpaulo return -1; 3605252726Srpaulo 3606281806Srpaulo wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id); 3607281806Srpaulo 3608252726Srpaulo ret = os_snprintf(buf, buflen, "%d\n", cred->id); 3609281806Srpaulo if (os_snprintf_error(buflen, ret)) 3610252726Srpaulo return -1; 3611252726Srpaulo return ret; 3612252726Srpaulo} 3613252726Srpaulo 3614252726Srpaulo 3615252726Srpaulostatic int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s, 3616252726Srpaulo struct wpa_cred *cred) 3617252726Srpaulo{ 3618252726Srpaulo struct wpa_ssid *ssid; 3619252726Srpaulo char str[20]; 3620281806Srpaulo int id; 3621252726Srpaulo 3622281806Srpaulo if (cred == NULL) { 3623252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); 3624252726Srpaulo return -1; 3625252726Srpaulo } 3626252726Srpaulo 3627281806Srpaulo id = cred->id; 3628281806Srpaulo if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { 3629281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); 3630281806Srpaulo return -1; 3631281806Srpaulo } 3632281806Srpaulo 3633281806Srpaulo wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); 3634281806Srpaulo 3635252726Srpaulo /* Remove any network entry created based on the removed credential */ 3636252726Srpaulo ssid = wpa_s->conf->ssid; 3637252726Srpaulo while (ssid) { 3638252726Srpaulo if (ssid->parent_cred == cred) { 3639281806Srpaulo int res; 3640281806Srpaulo 3641252726Srpaulo wpa_printf(MSG_DEBUG, "Remove network id %d since it " 3642252726Srpaulo "used the removed credential", ssid->id); 3643281806Srpaulo res = os_snprintf(str, sizeof(str), "%d", ssid->id); 3644281806Srpaulo if (os_snprintf_error(sizeof(str), res)) 3645281806Srpaulo str[sizeof(str) - 1] = '\0'; 3646252726Srpaulo ssid = ssid->next; 3647252726Srpaulo wpa_supplicant_ctrl_iface_remove_network(wpa_s, str); 3648252726Srpaulo } else 3649252726Srpaulo ssid = ssid->next; 3650252726Srpaulo } 3651252726Srpaulo 3652252726Srpaulo return 0; 3653252726Srpaulo} 3654252726Srpaulo 3655252726Srpaulo 3656252726Srpaulostatic int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, 3657252726Srpaulo char *cmd) 3658252726Srpaulo{ 3659252726Srpaulo int id; 3660252726Srpaulo struct wpa_cred *cred, *prev; 3661252726Srpaulo 3662281806Srpaulo /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or 3663281806Srpaulo * "provisioning_sp=<FQDN> */ 3664252726Srpaulo if (os_strcmp(cmd, "all") == 0) { 3665252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); 3666252726Srpaulo cred = wpa_s->conf->cred; 3667252726Srpaulo while (cred) { 3668252726Srpaulo prev = cred; 3669252726Srpaulo cred = cred->next; 3670252726Srpaulo wpas_ctrl_remove_cred(wpa_s, prev); 3671252726Srpaulo } 3672252726Srpaulo return 0; 3673252726Srpaulo } 3674252726Srpaulo 3675252726Srpaulo if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) { 3676252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'", 3677252726Srpaulo cmd + 8); 3678252726Srpaulo cred = wpa_s->conf->cred; 3679252726Srpaulo while (cred) { 3680252726Srpaulo prev = cred; 3681252726Srpaulo cred = cred->next; 3682281806Srpaulo if (prev->domain) { 3683281806Srpaulo size_t i; 3684281806Srpaulo for (i = 0; i < prev->num_domain; i++) { 3685281806Srpaulo if (os_strcmp(prev->domain[i], cmd + 8) 3686281806Srpaulo != 0) 3687281806Srpaulo continue; 3688281806Srpaulo wpas_ctrl_remove_cred(wpa_s, prev); 3689281806Srpaulo break; 3690281806Srpaulo } 3691281806Srpaulo } 3692281806Srpaulo } 3693281806Srpaulo return 0; 3694281806Srpaulo } 3695281806Srpaulo 3696281806Srpaulo if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) { 3697281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'", 3698281806Srpaulo cmd + 16); 3699281806Srpaulo cred = wpa_s->conf->cred; 3700281806Srpaulo while (cred) { 3701281806Srpaulo prev = cred; 3702281806Srpaulo cred = cred->next; 3703281806Srpaulo if (prev->provisioning_sp && 3704281806Srpaulo os_strcmp(prev->provisioning_sp, cmd + 16) == 0) 3705252726Srpaulo wpas_ctrl_remove_cred(wpa_s, prev); 3706252726Srpaulo } 3707252726Srpaulo return 0; 3708252726Srpaulo } 3709252726Srpaulo 3710252726Srpaulo id = atoi(cmd); 3711252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); 3712252726Srpaulo 3713252726Srpaulo cred = wpa_config_get_cred(wpa_s->conf, id); 3714252726Srpaulo return wpas_ctrl_remove_cred(wpa_s, cred); 3715252726Srpaulo} 3716252726Srpaulo 3717252726Srpaulo 3718252726Srpaulostatic int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s, 3719252726Srpaulo char *cmd) 3720252726Srpaulo{ 3721252726Srpaulo int id; 3722252726Srpaulo struct wpa_cred *cred; 3723252726Srpaulo char *name, *value; 3724252726Srpaulo 3725252726Srpaulo /* cmd: "<cred id> <variable name> <value>" */ 3726252726Srpaulo name = os_strchr(cmd, ' '); 3727252726Srpaulo if (name == NULL) 3728252726Srpaulo return -1; 3729252726Srpaulo *name++ = '\0'; 3730252726Srpaulo 3731252726Srpaulo value = os_strchr(name, ' '); 3732252726Srpaulo if (value == NULL) 3733252726Srpaulo return -1; 3734252726Srpaulo *value++ = '\0'; 3735252726Srpaulo 3736252726Srpaulo id = atoi(cmd); 3737252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'", 3738252726Srpaulo id, name); 3739252726Srpaulo wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 3740252726Srpaulo (u8 *) value, os_strlen(value)); 3741252726Srpaulo 3742252726Srpaulo cred = wpa_config_get_cred(wpa_s->conf, id); 3743252726Srpaulo if (cred == NULL) { 3744252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", 3745252726Srpaulo id); 3746252726Srpaulo return -1; 3747252726Srpaulo } 3748252726Srpaulo 3749252726Srpaulo if (wpa_config_set_cred(cred, name, value, 0) < 0) { 3750252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred " 3751252726Srpaulo "variable '%s'", name); 3752252726Srpaulo return -1; 3753252726Srpaulo } 3754252726Srpaulo 3755281806Srpaulo wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name); 3756281806Srpaulo 3757252726Srpaulo return 0; 3758252726Srpaulo} 3759252726Srpaulo 3760252726Srpaulo 3761281806Srpaulostatic int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s, 3762281806Srpaulo char *cmd, char *buf, 3763281806Srpaulo size_t buflen) 3764281806Srpaulo{ 3765281806Srpaulo int id; 3766281806Srpaulo size_t res; 3767281806Srpaulo struct wpa_cred *cred; 3768281806Srpaulo char *name, *value; 3769281806Srpaulo 3770281806Srpaulo /* cmd: "<cred id> <variable name>" */ 3771281806Srpaulo name = os_strchr(cmd, ' '); 3772281806Srpaulo if (name == NULL) 3773281806Srpaulo return -1; 3774281806Srpaulo *name++ = '\0'; 3775281806Srpaulo 3776281806Srpaulo id = atoi(cmd); 3777281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'", 3778281806Srpaulo id, name); 3779281806Srpaulo 3780281806Srpaulo cred = wpa_config_get_cred(wpa_s->conf, id); 3781281806Srpaulo if (cred == NULL) { 3782281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", 3783281806Srpaulo id); 3784281806Srpaulo return -1; 3785281806Srpaulo } 3786281806Srpaulo 3787281806Srpaulo value = wpa_config_get_cred_no_key(cred, name); 3788281806Srpaulo if (value == NULL) { 3789281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'", 3790281806Srpaulo name); 3791281806Srpaulo return -1; 3792281806Srpaulo } 3793281806Srpaulo 3794281806Srpaulo res = os_strlcpy(buf, value, buflen); 3795281806Srpaulo if (res >= buflen) { 3796281806Srpaulo os_free(value); 3797281806Srpaulo return -1; 3798281806Srpaulo } 3799281806Srpaulo 3800281806Srpaulo os_free(value); 3801281806Srpaulo 3802281806Srpaulo return res; 3803281806Srpaulo} 3804281806Srpaulo 3805281806Srpaulo 3806189251Ssam#ifndef CONFIG_NO_CONFIG_WRITE 3807189251Ssamstatic int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) 3808189251Ssam{ 3809189251Ssam int ret; 3810189251Ssam 3811189251Ssam if (!wpa_s->conf->update_config) { 3812189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed " 3813189251Ssam "to update configuration (update_config=0)"); 3814189251Ssam return -1; 3815189251Ssam } 3816189251Ssam 3817189251Ssam ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 3818189251Ssam if (ret) { 3819189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to " 3820189251Ssam "update configuration"); 3821189251Ssam } else { 3822189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration" 3823189251Ssam " updated"); 3824189251Ssam } 3825189251Ssam 3826189251Ssam return ret; 3827189251Ssam} 3828189251Ssam#endif /* CONFIG_NO_CONFIG_WRITE */ 3829189251Ssam 3830189251Ssam 3831281806Srpaulostruct cipher_info { 3832281806Srpaulo unsigned int capa; 3833281806Srpaulo const char *name; 3834281806Srpaulo int group_only; 3835281806Srpaulo}; 3836281806Srpaulo 3837281806Srpaulostatic const struct cipher_info ciphers[] = { 3838281806Srpaulo { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 }, 3839281806Srpaulo { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 }, 3840281806Srpaulo { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 }, 3841281806Srpaulo { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, 3842281806Srpaulo { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, 3843281806Srpaulo { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, 3844281806Srpaulo { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, 3845281806Srpaulo { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } 3846281806Srpaulo}; 3847281806Srpaulo 3848281806Srpaulostatic const struct cipher_info ciphers_group_mgmt[] = { 3849281806Srpaulo { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 }, 3850281806Srpaulo { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 }, 3851281806Srpaulo { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 }, 3852281806Srpaulo { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 }, 3853281806Srpaulo}; 3854281806Srpaulo 3855281806Srpaulo 3856189251Ssamstatic int ctrl_iface_get_capability_pairwise(int res, char *strict, 3857189251Ssam struct wpa_driver_capa *capa, 3858189251Ssam char *buf, size_t buflen) 3859189251Ssam{ 3860281806Srpaulo int ret; 3861189251Ssam char *pos, *end; 3862189251Ssam size_t len; 3863281806Srpaulo unsigned int i; 3864189251Ssam 3865189251Ssam pos = buf; 3866189251Ssam end = pos + buflen; 3867189251Ssam 3868189251Ssam if (res < 0) { 3869189251Ssam if (strict) 3870189251Ssam return 0; 3871189251Ssam len = os_strlcpy(buf, "CCMP TKIP NONE", buflen); 3872189251Ssam if (len >= buflen) 3873189251Ssam return -1; 3874189251Ssam return len; 3875189251Ssam } 3876189251Ssam 3877281806Srpaulo for (i = 0; i < ARRAY_SIZE(ciphers); i++) { 3878281806Srpaulo if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) { 3879281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3880281806Srpaulo pos == buf ? "" : " ", 3881281806Srpaulo ciphers[i].name); 3882281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3883281806Srpaulo return pos - buf; 3884281806Srpaulo pos += ret; 3885281806Srpaulo } 3886189251Ssam } 3887189251Ssam 3888189251Ssam return pos - buf; 3889189251Ssam} 3890189251Ssam 3891189251Ssam 3892189251Ssamstatic int ctrl_iface_get_capability_group(int res, char *strict, 3893189251Ssam struct wpa_driver_capa *capa, 3894189251Ssam char *buf, size_t buflen) 3895189251Ssam{ 3896281806Srpaulo int ret; 3897189251Ssam char *pos, *end; 3898189251Ssam size_t len; 3899281806Srpaulo unsigned int i; 3900189251Ssam 3901189251Ssam pos = buf; 3902189251Ssam end = pos + buflen; 3903189251Ssam 3904189251Ssam if (res < 0) { 3905189251Ssam if (strict) 3906189251Ssam return 0; 3907189251Ssam len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen); 3908189251Ssam if (len >= buflen) 3909189251Ssam return -1; 3910189251Ssam return len; 3911189251Ssam } 3912189251Ssam 3913281806Srpaulo for (i = 0; i < ARRAY_SIZE(ciphers); i++) { 3914281806Srpaulo if (capa->enc & ciphers[i].capa) { 3915281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3916281806Srpaulo pos == buf ? "" : " ", 3917281806Srpaulo ciphers[i].name); 3918281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3919281806Srpaulo return pos - buf; 3920281806Srpaulo pos += ret; 3921281806Srpaulo } 3922189251Ssam } 3923189251Ssam 3924281806Srpaulo return pos - buf; 3925281806Srpaulo} 3926252726Srpaulo 3927189251Ssam 3928281806Srpaulostatic int ctrl_iface_get_capability_group_mgmt(int res, char *strict, 3929281806Srpaulo struct wpa_driver_capa *capa, 3930281806Srpaulo char *buf, size_t buflen) 3931281806Srpaulo{ 3932281806Srpaulo int ret; 3933281806Srpaulo char *pos, *end; 3934281806Srpaulo unsigned int i; 3935189251Ssam 3936281806Srpaulo pos = buf; 3937281806Srpaulo end = pos + buflen; 3938281806Srpaulo 3939281806Srpaulo if (res < 0) 3940281806Srpaulo return 0; 3941281806Srpaulo 3942281806Srpaulo for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) { 3943281806Srpaulo if (capa->enc & ciphers_group_mgmt[i].capa) { 3944281806Srpaulo ret = os_snprintf(pos, end - pos, "%s%s", 3945281806Srpaulo pos == buf ? "" : " ", 3946281806Srpaulo ciphers_group_mgmt[i].name); 3947281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3948281806Srpaulo return pos - buf; 3949281806Srpaulo pos += ret; 3950281806Srpaulo } 3951189251Ssam } 3952189251Ssam 3953189251Ssam return pos - buf; 3954189251Ssam} 3955189251Ssam 3956189251Ssam 3957189251Ssamstatic int ctrl_iface_get_capability_key_mgmt(int res, char *strict, 3958189251Ssam struct wpa_driver_capa *capa, 3959189251Ssam char *buf, size_t buflen) 3960189251Ssam{ 3961189251Ssam int ret; 3962189251Ssam char *pos, *end; 3963189251Ssam size_t len; 3964189251Ssam 3965189251Ssam pos = buf; 3966189251Ssam end = pos + buflen; 3967189251Ssam 3968189251Ssam if (res < 0) { 3969189251Ssam if (strict) 3970189251Ssam return 0; 3971189251Ssam len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE " 3972189251Ssam "NONE", buflen); 3973189251Ssam if (len >= buflen) 3974189251Ssam return -1; 3975189251Ssam return len; 3976189251Ssam } 3977189251Ssam 3978189251Ssam ret = os_snprintf(pos, end - pos, "NONE IEEE8021X"); 3979281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3980189251Ssam return pos - buf; 3981189251Ssam pos += ret; 3982189251Ssam 3983189251Ssam if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 3984189251Ssam WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { 3985189251Ssam ret = os_snprintf(pos, end - pos, " WPA-EAP"); 3986281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3987189251Ssam return pos - buf; 3988189251Ssam pos += ret; 3989189251Ssam } 3990189251Ssam 3991189251Ssam if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 3992189251Ssam WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 3993189251Ssam ret = os_snprintf(pos, end - pos, " WPA-PSK"); 3994281806Srpaulo if (os_snprintf_error(end - pos, ret)) 3995189251Ssam return pos - buf; 3996189251Ssam pos += ret; 3997189251Ssam } 3998189251Ssam 3999189251Ssam if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { 4000189251Ssam ret = os_snprintf(pos, end - pos, " WPA-NONE"); 4001281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4002189251Ssam return pos - buf; 4003189251Ssam pos += ret; 4004189251Ssam } 4005189251Ssam 4006281806Srpaulo#ifdef CONFIG_SUITEB 4007281806Srpaulo if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) { 4008281806Srpaulo ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B"); 4009281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4010281806Srpaulo return pos - buf; 4011281806Srpaulo pos += ret; 4012281806Srpaulo } 4013281806Srpaulo#endif /* CONFIG_SUITEB */ 4014281806Srpaulo#ifdef CONFIG_SUITEB192 4015281806Srpaulo if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) { 4016281806Srpaulo ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192"); 4017281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4018281806Srpaulo return pos - buf; 4019281806Srpaulo pos += ret; 4020281806Srpaulo } 4021281806Srpaulo#endif /* CONFIG_SUITEB192 */ 4022346981Scy#ifdef CONFIG_OWE 4023346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) { 4024346981Scy ret = os_snprintf(pos, end - pos, " OWE"); 4025346981Scy if (os_snprintf_error(end - pos, ret)) 4026346981Scy return pos - buf; 4027346981Scy pos += ret; 4028346981Scy } 4029346981Scy#endif /* CONFIG_OWE */ 4030346981Scy#ifdef CONFIG_DPP 4031346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) { 4032346981Scy ret = os_snprintf(pos, end - pos, " DPP"); 4033346981Scy if (os_snprintf_error(end - pos, ret)) 4034346981Scy return pos - buf; 4035346981Scy pos += ret; 4036346981Scy } 4037346981Scy#endif /* CONFIG_DPP */ 4038346981Scy#ifdef CONFIG_FILS 4039346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) { 4040346981Scy ret = os_snprintf(pos, end - pos, " FILS-SHA256"); 4041346981Scy if (os_snprintf_error(end - pos, ret)) 4042346981Scy return pos - buf; 4043346981Scy pos += ret; 4044346981Scy } 4045346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) { 4046346981Scy ret = os_snprintf(pos, end - pos, " FILS-SHA384"); 4047346981Scy if (os_snprintf_error(end - pos, ret)) 4048346981Scy return pos - buf; 4049346981Scy pos += ret; 4050346981Scy } 4051346981Scy#ifdef CONFIG_IEEE80211R 4052346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) { 4053346981Scy ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256"); 4054346981Scy if (os_snprintf_error(end - pos, ret)) 4055346981Scy return pos - buf; 4056346981Scy pos += ret; 4057346981Scy } 4058346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) { 4059346981Scy ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384"); 4060346981Scy if (os_snprintf_error(end - pos, ret)) 4061346981Scy return pos - buf; 4062346981Scy pos += ret; 4063346981Scy } 4064346981Scy#endif /* CONFIG_IEEE80211R */ 4065346981Scy#endif /* CONFIG_FILS */ 4066346981Scy#ifdef CONFIG_IEEE80211R 4067346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) { 4068346981Scy ret = os_snprintf(pos, end - pos, " FT-PSK"); 4069346981Scy if (os_snprintf_error(end - pos, ret)) 4070346981Scy return pos - buf; 4071346981Scy pos += ret; 4072346981Scy } 4073346981Scy#endif /* CONFIG_IEEE80211R */ 4074346981Scy#ifdef CONFIG_SAE 4075346981Scy if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) { 4076346981Scy ret = os_snprintf(pos, end - pos, " SAE"); 4077346981Scy if (os_snprintf_error(end - pos, ret)) 4078346981Scy return pos - buf; 4079346981Scy pos += ret; 4080346981Scy } 4081346981Scy#endif /* CONFIG_SAE */ 4082281806Srpaulo 4083189251Ssam return pos - buf; 4084189251Ssam} 4085189251Ssam 4086189251Ssam 4087189251Ssamstatic int ctrl_iface_get_capability_proto(int res, char *strict, 4088189251Ssam struct wpa_driver_capa *capa, 4089189251Ssam char *buf, size_t buflen) 4090189251Ssam{ 4091281806Srpaulo int ret; 4092189251Ssam char *pos, *end; 4093189251Ssam size_t len; 4094189251Ssam 4095189251Ssam pos = buf; 4096189251Ssam end = pos + buflen; 4097189251Ssam 4098189251Ssam if (res < 0) { 4099189251Ssam if (strict) 4100189251Ssam return 0; 4101189251Ssam len = os_strlcpy(buf, "RSN WPA", buflen); 4102189251Ssam if (len >= buflen) 4103189251Ssam return -1; 4104189251Ssam return len; 4105189251Ssam } 4106189251Ssam 4107189251Ssam if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 4108189251Ssam WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 4109281806Srpaulo ret = os_snprintf(pos, end - pos, "%sRSN", 4110281806Srpaulo pos == buf ? "" : " "); 4111281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4112189251Ssam return pos - buf; 4113189251Ssam pos += ret; 4114189251Ssam } 4115189251Ssam 4116189251Ssam if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 4117189251Ssam WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { 4118281806Srpaulo ret = os_snprintf(pos, end - pos, "%sWPA", 4119281806Srpaulo pos == buf ? "" : " "); 4120281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4121189251Ssam return pos - buf; 4122189251Ssam pos += ret; 4123189251Ssam } 4124189251Ssam 4125189251Ssam return pos - buf; 4126189251Ssam} 4127189251Ssam 4128189251Ssam 4129281806Srpaulostatic int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s, 4130281806Srpaulo int res, char *strict, 4131189251Ssam struct wpa_driver_capa *capa, 4132189251Ssam char *buf, size_t buflen) 4133189251Ssam{ 4134281806Srpaulo int ret; 4135189251Ssam char *pos, *end; 4136189251Ssam size_t len; 4137189251Ssam 4138189251Ssam pos = buf; 4139189251Ssam end = pos + buflen; 4140189251Ssam 4141189251Ssam if (res < 0) { 4142189251Ssam if (strict) 4143189251Ssam return 0; 4144189251Ssam len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen); 4145189251Ssam if (len >= buflen) 4146189251Ssam return -1; 4147189251Ssam return len; 4148189251Ssam } 4149189251Ssam 4150189251Ssam if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) { 4151281806Srpaulo ret = os_snprintf(pos, end - pos, "%sOPEN", 4152281806Srpaulo pos == buf ? "" : " "); 4153281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4154189251Ssam return pos - buf; 4155189251Ssam pos += ret; 4156189251Ssam } 4157189251Ssam 4158189251Ssam if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) { 4159189251Ssam ret = os_snprintf(pos, end - pos, "%sSHARED", 4160281806Srpaulo pos == buf ? "" : " "); 4161281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4162189251Ssam return pos - buf; 4163189251Ssam pos += ret; 4164189251Ssam } 4165189251Ssam 4166189251Ssam if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) { 4167281806Srpaulo ret = os_snprintf(pos, end - pos, "%sLEAP", 4168281806Srpaulo pos == buf ? "" : " "); 4169281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4170189251Ssam return pos - buf; 4171189251Ssam pos += ret; 4172189251Ssam } 4173189251Ssam 4174281806Srpaulo#ifdef CONFIG_SAE 4175281806Srpaulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) { 4176281806Srpaulo ret = os_snprintf(pos, end - pos, "%sSAE", 4177281806Srpaulo pos == buf ? "" : " "); 4178281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4179281806Srpaulo return pos - buf; 4180281806Srpaulo pos += ret; 4181281806Srpaulo } 4182281806Srpaulo#endif /* CONFIG_SAE */ 4183281806Srpaulo 4184346981Scy#ifdef CONFIG_FILS 4185346981Scy if (wpa_is_fils_supported(wpa_s)) { 4186346981Scy ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITHOUT_PFS", 4187346981Scy pos == buf ? "" : " "); 4188346981Scy if (os_snprintf_error(end - pos, ret)) 4189346981Scy return pos - buf; 4190346981Scy pos += ret; 4191346981Scy } 4192346981Scy 4193346981Scy#ifdef CONFIG_FILS_SK_PFS 4194346981Scy if (wpa_is_fils_sk_pfs_supported(wpa_s)) { 4195346981Scy ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITH_PFS", 4196346981Scy pos == buf ? "" : " "); 4197346981Scy if (os_snprintf_error(end - pos, ret)) 4198346981Scy return pos - buf; 4199346981Scy pos += ret; 4200346981Scy } 4201346981Scy#endif /* CONFIG_FILS_SK_PFS */ 4202346981Scy#endif /* CONFIG_FILS */ 4203346981Scy 4204189251Ssam return pos - buf; 4205189251Ssam} 4206189251Ssam 4207189251Ssam 4208281806Srpaulostatic int ctrl_iface_get_capability_modes(int res, char *strict, 4209281806Srpaulo struct wpa_driver_capa *capa, 4210281806Srpaulo char *buf, size_t buflen) 4211281806Srpaulo{ 4212281806Srpaulo int ret; 4213281806Srpaulo char *pos, *end; 4214281806Srpaulo size_t len; 4215281806Srpaulo 4216281806Srpaulo pos = buf; 4217281806Srpaulo end = pos + buflen; 4218281806Srpaulo 4219281806Srpaulo if (res < 0) { 4220281806Srpaulo if (strict) 4221281806Srpaulo return 0; 4222281806Srpaulo len = os_strlcpy(buf, "IBSS AP", buflen); 4223281806Srpaulo if (len >= buflen) 4224281806Srpaulo return -1; 4225281806Srpaulo return len; 4226281806Srpaulo } 4227281806Srpaulo 4228281806Srpaulo if (capa->flags & WPA_DRIVER_FLAGS_IBSS) { 4229281806Srpaulo ret = os_snprintf(pos, end - pos, "%sIBSS", 4230281806Srpaulo pos == buf ? "" : " "); 4231281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4232281806Srpaulo return pos - buf; 4233281806Srpaulo pos += ret; 4234281806Srpaulo } 4235281806Srpaulo 4236281806Srpaulo if (capa->flags & WPA_DRIVER_FLAGS_AP) { 4237281806Srpaulo ret = os_snprintf(pos, end - pos, "%sAP", 4238281806Srpaulo pos == buf ? "" : " "); 4239281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4240281806Srpaulo return pos - buf; 4241281806Srpaulo pos += ret; 4242281806Srpaulo } 4243281806Srpaulo 4244281806Srpaulo#ifdef CONFIG_MESH 4245281806Srpaulo if (capa->flags & WPA_DRIVER_FLAGS_MESH) { 4246281806Srpaulo ret = os_snprintf(pos, end - pos, "%sMESH", 4247281806Srpaulo pos == buf ? "" : " "); 4248281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4249281806Srpaulo return pos - buf; 4250281806Srpaulo pos += ret; 4251281806Srpaulo } 4252281806Srpaulo#endif /* CONFIG_MESH */ 4253281806Srpaulo 4254281806Srpaulo return pos - buf; 4255281806Srpaulo} 4256281806Srpaulo 4257281806Srpaulo 4258252726Srpaulostatic int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, 4259252726Srpaulo char *buf, size_t buflen) 4260252726Srpaulo{ 4261252726Srpaulo struct hostapd_channel_data *chnl; 4262252726Srpaulo int ret, i, j; 4263252726Srpaulo char *pos, *end, *hmode; 4264252726Srpaulo 4265252726Srpaulo pos = buf; 4266252726Srpaulo end = pos + buflen; 4267252726Srpaulo 4268252726Srpaulo for (j = 0; j < wpa_s->hw.num_modes; j++) { 4269252726Srpaulo switch (wpa_s->hw.modes[j].mode) { 4270252726Srpaulo case HOSTAPD_MODE_IEEE80211B: 4271252726Srpaulo hmode = "B"; 4272252726Srpaulo break; 4273252726Srpaulo case HOSTAPD_MODE_IEEE80211G: 4274252726Srpaulo hmode = "G"; 4275252726Srpaulo break; 4276252726Srpaulo case HOSTAPD_MODE_IEEE80211A: 4277252726Srpaulo hmode = "A"; 4278252726Srpaulo break; 4279252726Srpaulo case HOSTAPD_MODE_IEEE80211AD: 4280252726Srpaulo hmode = "AD"; 4281252726Srpaulo break; 4282252726Srpaulo default: 4283252726Srpaulo continue; 4284252726Srpaulo } 4285252726Srpaulo ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode); 4286281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4287252726Srpaulo return pos - buf; 4288252726Srpaulo pos += ret; 4289252726Srpaulo chnl = wpa_s->hw.modes[j].channels; 4290252726Srpaulo for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { 4291252726Srpaulo if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) 4292252726Srpaulo continue; 4293252726Srpaulo ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan); 4294281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4295252726Srpaulo return pos - buf; 4296252726Srpaulo pos += ret; 4297252726Srpaulo } 4298252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4299281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4300252726Srpaulo return pos - buf; 4301252726Srpaulo pos += ret; 4302252726Srpaulo } 4303252726Srpaulo 4304252726Srpaulo return pos - buf; 4305252726Srpaulo} 4306252726Srpaulo 4307252726Srpaulo 4308281806Srpaulostatic int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s, 4309281806Srpaulo char *buf, size_t buflen) 4310281806Srpaulo{ 4311281806Srpaulo struct hostapd_channel_data *chnl; 4312281806Srpaulo int ret, i, j; 4313281806Srpaulo char *pos, *end, *hmode; 4314281806Srpaulo 4315281806Srpaulo pos = buf; 4316281806Srpaulo end = pos + buflen; 4317281806Srpaulo 4318281806Srpaulo for (j = 0; j < wpa_s->hw.num_modes; j++) { 4319281806Srpaulo switch (wpa_s->hw.modes[j].mode) { 4320281806Srpaulo case HOSTAPD_MODE_IEEE80211B: 4321281806Srpaulo hmode = "B"; 4322281806Srpaulo break; 4323281806Srpaulo case HOSTAPD_MODE_IEEE80211G: 4324281806Srpaulo hmode = "G"; 4325281806Srpaulo break; 4326281806Srpaulo case HOSTAPD_MODE_IEEE80211A: 4327281806Srpaulo hmode = "A"; 4328281806Srpaulo break; 4329281806Srpaulo case HOSTAPD_MODE_IEEE80211AD: 4330281806Srpaulo hmode = "AD"; 4331281806Srpaulo break; 4332281806Srpaulo default: 4333281806Srpaulo continue; 4334281806Srpaulo } 4335281806Srpaulo ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n", 4336281806Srpaulo hmode); 4337281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4338281806Srpaulo return pos - buf; 4339281806Srpaulo pos += ret; 4340281806Srpaulo chnl = wpa_s->hw.modes[j].channels; 4341281806Srpaulo for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { 4342281806Srpaulo if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) 4343281806Srpaulo continue; 4344281806Srpaulo ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n", 4345281806Srpaulo chnl[i].chan, chnl[i].freq, 4346281806Srpaulo chnl[i].flag & HOSTAPD_CHAN_NO_IR ? 4347281806Srpaulo " (NO_IR)" : "", 4348281806Srpaulo chnl[i].flag & HOSTAPD_CHAN_RADAR ? 4349281806Srpaulo " (DFS)" : ""); 4350281806Srpaulo 4351281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4352281806Srpaulo return pos - buf; 4353281806Srpaulo pos += ret; 4354281806Srpaulo } 4355281806Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4356281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4357281806Srpaulo return pos - buf; 4358281806Srpaulo pos += ret; 4359281806Srpaulo } 4360281806Srpaulo 4361281806Srpaulo return pos - buf; 4362281806Srpaulo} 4363281806Srpaulo 4364281806Srpaulo 4365189251Ssamstatic int wpa_supplicant_ctrl_iface_get_capability( 4366189251Ssam struct wpa_supplicant *wpa_s, const char *_field, char *buf, 4367189251Ssam size_t buflen) 4368189251Ssam{ 4369189251Ssam struct wpa_driver_capa capa; 4370189251Ssam int res; 4371189251Ssam char *strict; 4372189251Ssam char field[30]; 4373189251Ssam size_t len; 4374189251Ssam 4375189251Ssam /* Determine whether or not strict checking was requested */ 4376189251Ssam len = os_strlcpy(field, _field, sizeof(field)); 4377189251Ssam if (len >= sizeof(field)) 4378189251Ssam return -1; 4379189251Ssam strict = os_strchr(field, ' '); 4380189251Ssam if (strict != NULL) { 4381189251Ssam *strict++ = '\0'; 4382189251Ssam if (os_strcmp(strict, "strict") != 0) 4383189251Ssam return -1; 4384189251Ssam } 4385189251Ssam 4386189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s", 4387189251Ssam field, strict ? strict : ""); 4388189251Ssam 4389189251Ssam if (os_strcmp(field, "eap") == 0) { 4390189251Ssam return eap_get_names(buf, buflen); 4391189251Ssam } 4392189251Ssam 4393189251Ssam res = wpa_drv_get_capa(wpa_s, &capa); 4394189251Ssam 4395189251Ssam if (os_strcmp(field, "pairwise") == 0) 4396189251Ssam return ctrl_iface_get_capability_pairwise(res, strict, &capa, 4397189251Ssam buf, buflen); 4398189251Ssam 4399189251Ssam if (os_strcmp(field, "group") == 0) 4400189251Ssam return ctrl_iface_get_capability_group(res, strict, &capa, 4401189251Ssam buf, buflen); 4402189251Ssam 4403281806Srpaulo if (os_strcmp(field, "group_mgmt") == 0) 4404281806Srpaulo return ctrl_iface_get_capability_group_mgmt(res, strict, &capa, 4405281806Srpaulo buf, buflen); 4406281806Srpaulo 4407189251Ssam if (os_strcmp(field, "key_mgmt") == 0) 4408189251Ssam return ctrl_iface_get_capability_key_mgmt(res, strict, &capa, 4409189251Ssam buf, buflen); 4410189251Ssam 4411189251Ssam if (os_strcmp(field, "proto") == 0) 4412189251Ssam return ctrl_iface_get_capability_proto(res, strict, &capa, 4413189251Ssam buf, buflen); 4414189251Ssam 4415189251Ssam if (os_strcmp(field, "auth_alg") == 0) 4416281806Srpaulo return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict, 4417281806Srpaulo &capa, buf, buflen); 4418189251Ssam 4419281806Srpaulo if (os_strcmp(field, "modes") == 0) 4420281806Srpaulo return ctrl_iface_get_capability_modes(res, strict, &capa, 4421281806Srpaulo buf, buflen); 4422281806Srpaulo 4423252726Srpaulo if (os_strcmp(field, "channels") == 0) 4424252726Srpaulo return ctrl_iface_get_capability_channels(wpa_s, buf, buflen); 4425252726Srpaulo 4426281806Srpaulo if (os_strcmp(field, "freq") == 0) 4427281806Srpaulo return ctrl_iface_get_capability_freq(wpa_s, buf, buflen); 4428281806Srpaulo 4429281806Srpaulo#ifdef CONFIG_TDLS 4430281806Srpaulo if (os_strcmp(field, "tdls") == 0) 4431281806Srpaulo return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen); 4432281806Srpaulo#endif /* CONFIG_TDLS */ 4433281806Srpaulo 4434281806Srpaulo#ifdef CONFIG_ERP 4435281806Srpaulo if (os_strcmp(field, "erp") == 0) { 4436281806Srpaulo res = os_snprintf(buf, buflen, "ERP"); 4437281806Srpaulo if (os_snprintf_error(buflen, res)) 4438281806Srpaulo return -1; 4439281806Srpaulo return res; 4440281806Srpaulo } 4441281806Srpaulo#endif /* CONFIG_EPR */ 4442281806Srpaulo 4443289549Srpaulo#ifdef CONFIG_FIPS 4444289549Srpaulo if (os_strcmp(field, "fips") == 0) { 4445289549Srpaulo res = os_snprintf(buf, buflen, "FIPS"); 4446289549Srpaulo if (os_snprintf_error(buflen, res)) 4447289549Srpaulo return -1; 4448289549Srpaulo return res; 4449289549Srpaulo } 4450289549Srpaulo#endif /* CONFIG_FIPS */ 4451289549Srpaulo 4452337817Scy#ifdef CONFIG_ACS 4453337817Scy if (os_strcmp(field, "acs") == 0) { 4454337817Scy res = os_snprintf(buf, buflen, "ACS"); 4455337817Scy if (os_snprintf_error(buflen, res)) 4456337817Scy return -1; 4457337817Scy return res; 4458337817Scy } 4459337817Scy#endif /* CONFIG_ACS */ 4460337817Scy 4461346981Scy#ifdef CONFIG_FILS 4462346981Scy if (os_strcmp(field, "fils") == 0) { 4463346981Scy#ifdef CONFIG_FILS_SK_PFS 4464346981Scy if (wpa_is_fils_supported(wpa_s) && 4465346981Scy wpa_is_fils_sk_pfs_supported(wpa_s)) { 4466346981Scy res = os_snprintf(buf, buflen, "FILS FILS-SK-PFS"); 4467346981Scy if (os_snprintf_error(buflen, res)) 4468346981Scy return -1; 4469346981Scy return res; 4470346981Scy } 4471346981Scy#endif /* CONFIG_FILS_SK_PFS */ 4472346981Scy 4473346981Scy if (wpa_is_fils_supported(wpa_s)) { 4474346981Scy res = os_snprintf(buf, buflen, "FILS"); 4475346981Scy if (os_snprintf_error(buflen, res)) 4476346981Scy return -1; 4477346981Scy return res; 4478346981Scy } 4479346981Scy } 4480346981Scy#endif /* CONFIG_FILS */ 4481346981Scy 4482346981Scy if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) { 4483346981Scy res = os_snprintf(buf, buflen, "MULTIBSS-STA"); 4484346981Scy if (os_snprintf_error(buflen, res)) 4485346981Scy return -1; 4486346981Scy return res; 4487346981Scy } 4488346981Scy 4489346981Scy#ifdef CONFIG_DPP 4490346981Scy if (os_strcmp(field, "dpp") == 0) { 4491346981Scy#ifdef CONFIG_DPP2 4492346981Scy res = os_snprintf(buf, buflen, "DPP=2"); 4493346981Scy#else /* CONFIG_DPP2 */ 4494346981Scy res = os_snprintf(buf, buflen, "DPP=1"); 4495346981Scy#endif /* CONFIG_DPP2 */ 4496346981Scy if (os_snprintf_error(buflen, res)) 4497346981Scy return -1; 4498346981Scy return res; 4499346981Scy } 4500346981Scy#endif /* CONFIG_DPP */ 4501346981Scy 4502189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", 4503189251Ssam field); 4504189251Ssam 4505189251Ssam return -1; 4506189251Ssam} 4507189251Ssam 4508189251Ssam 4509252726Srpaulo#ifdef CONFIG_INTERWORKING 4510252726Srpaulostatic char * anqp_add_hex(char *pos, char *end, const char *title, 4511252726Srpaulo struct wpabuf *data) 4512252726Srpaulo{ 4513252726Srpaulo char *start = pos; 4514252726Srpaulo size_t i; 4515252726Srpaulo int ret; 4516252726Srpaulo const u8 *d; 4517252726Srpaulo 4518252726Srpaulo if (data == NULL) 4519252726Srpaulo return start; 4520252726Srpaulo 4521252726Srpaulo ret = os_snprintf(pos, end - pos, "%s=", title); 4522281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4523252726Srpaulo return start; 4524252726Srpaulo pos += ret; 4525252726Srpaulo 4526252726Srpaulo d = wpabuf_head_u8(data); 4527252726Srpaulo for (i = 0; i < wpabuf_len(data); i++) { 4528252726Srpaulo ret = os_snprintf(pos, end - pos, "%02x", *d++); 4529281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4530252726Srpaulo return start; 4531252726Srpaulo pos += ret; 4532252726Srpaulo } 4533252726Srpaulo 4534252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4535281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4536252726Srpaulo return start; 4537252726Srpaulo pos += ret; 4538252726Srpaulo 4539252726Srpaulo return pos; 4540252726Srpaulo} 4541252726Srpaulo#endif /* CONFIG_INTERWORKING */ 4542252726Srpaulo 4543252726Srpaulo 4544346981Scy#ifdef CONFIG_FILS 4545346981Scystatic int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) 4546346981Scy{ 4547346981Scy char *start = pos; 4548346981Scy const u8 *ie, *ie_end; 4549346981Scy u16 info, realms; 4550346981Scy int ret; 4551346981Scy 4552346981Scy ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); 4553346981Scy if (!ie) 4554346981Scy return 0; 4555346981Scy ie_end = ie + 2 + ie[1]; 4556346981Scy ie += 2; 4557346981Scy if (ie_end - ie < 2) 4558346981Scy return -1; 4559346981Scy 4560346981Scy info = WPA_GET_LE16(ie); 4561346981Scy ie += 2; 4562346981Scy ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info); 4563346981Scy if (os_snprintf_error(end - pos, ret)) 4564346981Scy return 0; 4565346981Scy pos += ret; 4566346981Scy 4567346981Scy if (info & BIT(7)) { 4568346981Scy /* Cache Identifier Included */ 4569346981Scy if (ie_end - ie < 2) 4570346981Scy return -1; 4571346981Scy ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n", 4572346981Scy ie[0], ie[1]); 4573346981Scy if (os_snprintf_error(end - pos, ret)) 4574346981Scy return 0; 4575346981Scy pos += ret; 4576346981Scy ie += 2; 4577346981Scy } 4578346981Scy 4579346981Scy if (info & BIT(8)) { 4580346981Scy /* HESSID Included */ 4581346981Scy if (ie_end - ie < ETH_ALEN) 4582346981Scy return -1; 4583346981Scy ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n", 4584346981Scy MAC2STR(ie)); 4585346981Scy if (os_snprintf_error(end - pos, ret)) 4586346981Scy return 0; 4587346981Scy pos += ret; 4588346981Scy ie += ETH_ALEN; 4589346981Scy } 4590346981Scy 4591346981Scy realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3; 4592346981Scy if (realms) { 4593346981Scy if (ie_end - ie < realms * 2) 4594346981Scy return -1; 4595346981Scy ret = os_snprintf(pos, end - pos, "fils_realms="); 4596346981Scy if (os_snprintf_error(end - pos, ret)) 4597346981Scy return 0; 4598346981Scy pos += ret; 4599346981Scy 4600346981Scy ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2); 4601346981Scy if (ret <= 0) 4602346981Scy return 0; 4603346981Scy pos += ret; 4604346981Scy ie += realms * 2; 4605346981Scy ret = os_snprintf(pos, end - pos, "\n"); 4606346981Scy if (os_snprintf_error(end - pos, ret)) 4607346981Scy return 0; 4608346981Scy pos += ret; 4609346981Scy } 4610346981Scy 4611346981Scy return pos - start; 4612346981Scy} 4613346981Scy#endif /* CONFIG_FILS */ 4614346981Scy 4615346981Scy 4616252726Srpaulostatic int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 4617252726Srpaulo unsigned long mask, char *buf, size_t buflen) 4618252726Srpaulo{ 4619252726Srpaulo size_t i; 4620252726Srpaulo int ret; 4621252726Srpaulo char *pos, *end; 4622346981Scy const u8 *ie, *ie2, *osen_ie, *mesh, *owe; 4623252726Srpaulo 4624252726Srpaulo pos = buf; 4625252726Srpaulo end = buf + buflen; 4626252726Srpaulo 4627252726Srpaulo if (mask & WPA_BSS_MASK_ID) { 4628252726Srpaulo ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id); 4629281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4630252726Srpaulo return 0; 4631252726Srpaulo pos += ret; 4632252726Srpaulo } 4633252726Srpaulo 4634252726Srpaulo if (mask & WPA_BSS_MASK_BSSID) { 4635252726Srpaulo ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", 4636252726Srpaulo MAC2STR(bss->bssid)); 4637281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4638252726Srpaulo return 0; 4639252726Srpaulo pos += ret; 4640252726Srpaulo } 4641252726Srpaulo 4642252726Srpaulo if (mask & WPA_BSS_MASK_FREQ) { 4643252726Srpaulo ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq); 4644281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4645252726Srpaulo return 0; 4646252726Srpaulo pos += ret; 4647252726Srpaulo } 4648252726Srpaulo 4649252726Srpaulo if (mask & WPA_BSS_MASK_BEACON_INT) { 4650252726Srpaulo ret = os_snprintf(pos, end - pos, "beacon_int=%d\n", 4651252726Srpaulo bss->beacon_int); 4652281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4653252726Srpaulo return 0; 4654252726Srpaulo pos += ret; 4655252726Srpaulo } 4656252726Srpaulo 4657252726Srpaulo if (mask & WPA_BSS_MASK_CAPABILITIES) { 4658252726Srpaulo ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n", 4659252726Srpaulo bss->caps); 4660281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4661252726Srpaulo return 0; 4662252726Srpaulo pos += ret; 4663252726Srpaulo } 4664252726Srpaulo 4665252726Srpaulo if (mask & WPA_BSS_MASK_QUAL) { 4666252726Srpaulo ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual); 4667281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4668252726Srpaulo return 0; 4669252726Srpaulo pos += ret; 4670252726Srpaulo } 4671252726Srpaulo 4672252726Srpaulo if (mask & WPA_BSS_MASK_NOISE) { 4673252726Srpaulo ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise); 4674281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4675252726Srpaulo return 0; 4676252726Srpaulo pos += ret; 4677252726Srpaulo } 4678252726Srpaulo 4679252726Srpaulo if (mask & WPA_BSS_MASK_LEVEL) { 4680252726Srpaulo ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level); 4681281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4682252726Srpaulo return 0; 4683252726Srpaulo pos += ret; 4684252726Srpaulo } 4685252726Srpaulo 4686252726Srpaulo if (mask & WPA_BSS_MASK_TSF) { 4687252726Srpaulo ret = os_snprintf(pos, end - pos, "tsf=%016llu\n", 4688252726Srpaulo (unsigned long long) bss->tsf); 4689281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4690252726Srpaulo return 0; 4691252726Srpaulo pos += ret; 4692252726Srpaulo } 4693252726Srpaulo 4694252726Srpaulo if (mask & WPA_BSS_MASK_AGE) { 4695281806Srpaulo struct os_reltime now; 4696252726Srpaulo 4697281806Srpaulo os_get_reltime(&now); 4698252726Srpaulo ret = os_snprintf(pos, end - pos, "age=%d\n", 4699252726Srpaulo (int) (now.sec - bss->last_update.sec)); 4700281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4701252726Srpaulo return 0; 4702252726Srpaulo pos += ret; 4703252726Srpaulo } 4704252726Srpaulo 4705252726Srpaulo if (mask & WPA_BSS_MASK_IE) { 4706252726Srpaulo ret = os_snprintf(pos, end - pos, "ie="); 4707281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4708252726Srpaulo return 0; 4709252726Srpaulo pos += ret; 4710252726Srpaulo 4711252726Srpaulo ie = (const u8 *) (bss + 1); 4712252726Srpaulo for (i = 0; i < bss->ie_len; i++) { 4713252726Srpaulo ret = os_snprintf(pos, end - pos, "%02x", *ie++); 4714281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4715252726Srpaulo return 0; 4716252726Srpaulo pos += ret; 4717252726Srpaulo } 4718252726Srpaulo 4719252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4720281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4721252726Srpaulo return 0; 4722252726Srpaulo pos += ret; 4723252726Srpaulo } 4724252726Srpaulo 4725252726Srpaulo if (mask & WPA_BSS_MASK_FLAGS) { 4726252726Srpaulo ret = os_snprintf(pos, end - pos, "flags="); 4727281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4728252726Srpaulo return 0; 4729252726Srpaulo pos += ret; 4730252726Srpaulo 4731346981Scy mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); 4732346981Scy 4733252726Srpaulo ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 4734252726Srpaulo if (ie) 4735252726Srpaulo pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 4736252726Srpaulo 2 + ie[1]); 4737252726Srpaulo ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); 4738252726Srpaulo if (ie2) 4739346981Scy pos = wpa_supplicant_ie_txt(pos, end, 4740346981Scy mesh ? "RSN" : "WPA2", ie2, 4741252726Srpaulo 2 + ie2[1]); 4742289549Srpaulo osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); 4743289549Srpaulo if (osen_ie) 4744289549Srpaulo pos = wpa_supplicant_ie_txt(pos, end, "OSEN", 4745289549Srpaulo osen_ie, 2 + osen_ie[1]); 4746346981Scy owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); 4747346981Scy if (owe) { 4748346981Scy ret = os_snprintf( 4749346981Scy pos, end - pos, 4750346981Scy ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]"); 4751346981Scy if (os_snprintf_error(end - pos, ret)) 4752346981Scy return 0; 4753346981Scy pos += ret; 4754346981Scy } 4755252726Srpaulo pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); 4756289549Srpaulo if (!ie && !ie2 && !osen_ie && 4757289549Srpaulo (bss->caps & IEEE80211_CAP_PRIVACY)) { 4758252726Srpaulo ret = os_snprintf(pos, end - pos, "[WEP]"); 4759281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4760252726Srpaulo return 0; 4761252726Srpaulo pos += ret; 4762252726Srpaulo } 4763346981Scy 4764346981Scy if (mesh) { 4765346981Scy ret = os_snprintf(pos, end - pos, "[MESH]"); 4766346981Scy if (os_snprintf_error(end - pos, ret)) 4767346981Scy return 0; 4768346981Scy pos += ret; 4769346981Scy } 4770346981Scy 4771281806Srpaulo if (bss_is_dmg(bss)) { 4772281806Srpaulo const char *s; 4773281806Srpaulo ret = os_snprintf(pos, end - pos, "[DMG]"); 4774281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4775252726Srpaulo return 0; 4776252726Srpaulo pos += ret; 4777281806Srpaulo switch (bss->caps & IEEE80211_CAP_DMG_MASK) { 4778281806Srpaulo case IEEE80211_CAP_DMG_IBSS: 4779281806Srpaulo s = "[IBSS]"; 4780281806Srpaulo break; 4781281806Srpaulo case IEEE80211_CAP_DMG_AP: 4782281806Srpaulo s = "[ESS]"; 4783281806Srpaulo break; 4784281806Srpaulo case IEEE80211_CAP_DMG_PBSS: 4785281806Srpaulo s = "[PBSS]"; 4786281806Srpaulo break; 4787281806Srpaulo default: 4788281806Srpaulo s = ""; 4789281806Srpaulo break; 4790281806Srpaulo } 4791281806Srpaulo ret = os_snprintf(pos, end - pos, "%s", s); 4792281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4793252726Srpaulo return 0; 4794252726Srpaulo pos += ret; 4795281806Srpaulo } else { 4796281806Srpaulo if (bss->caps & IEEE80211_CAP_IBSS) { 4797281806Srpaulo ret = os_snprintf(pos, end - pos, "[IBSS]"); 4798281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4799281806Srpaulo return 0; 4800281806Srpaulo pos += ret; 4801281806Srpaulo } 4802281806Srpaulo if (bss->caps & IEEE80211_CAP_ESS) { 4803281806Srpaulo ret = os_snprintf(pos, end - pos, "[ESS]"); 4804281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4805281806Srpaulo return 0; 4806281806Srpaulo pos += ret; 4807281806Srpaulo } 4808252726Srpaulo } 4809281806Srpaulo if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || 4810281806Srpaulo wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { 4811252726Srpaulo ret = os_snprintf(pos, end - pos, "[P2P]"); 4812281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4813252726Srpaulo return 0; 4814252726Srpaulo pos += ret; 4815252726Srpaulo } 4816252726Srpaulo#ifdef CONFIG_HS20 4817252726Srpaulo if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { 4818252726Srpaulo ret = os_snprintf(pos, end - pos, "[HS20]"); 4819281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4820281806Srpaulo return 0; 4821252726Srpaulo pos += ret; 4822252726Srpaulo } 4823252726Srpaulo#endif /* CONFIG_HS20 */ 4824346981Scy#ifdef CONFIG_FILS 4825346981Scy if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) { 4826346981Scy ret = os_snprintf(pos, end - pos, "[FILS]"); 4827346981Scy if (os_snprintf_error(end - pos, ret)) 4828346981Scy return 0; 4829346981Scy pos += ret; 4830346981Scy } 4831346981Scy#endif /* CONFIG_FILS */ 4832346981Scy#ifdef CONFIG_FST 4833346981Scy if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { 4834346981Scy ret = os_snprintf(pos, end - pos, "[FST]"); 4835346981Scy if (os_snprintf_error(end - pos, ret)) 4836346981Scy return 0; 4837346981Scy pos += ret; 4838346981Scy } 4839346981Scy#endif /* CONFIG_FST */ 4840346981Scy if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) { 4841346981Scy ret = os_snprintf(pos, end - pos, "[UTF-8]"); 4842346981Scy if (os_snprintf_error(end - pos, ret)) 4843346981Scy return 0; 4844346981Scy pos += ret; 4845346981Scy } 4846252726Srpaulo 4847252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4848281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4849252726Srpaulo return 0; 4850252726Srpaulo pos += ret; 4851252726Srpaulo } 4852252726Srpaulo 4853252726Srpaulo if (mask & WPA_BSS_MASK_SSID) { 4854252726Srpaulo ret = os_snprintf(pos, end - pos, "ssid=%s\n", 4855252726Srpaulo wpa_ssid_txt(bss->ssid, bss->ssid_len)); 4856281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4857252726Srpaulo return 0; 4858252726Srpaulo pos += ret; 4859252726Srpaulo } 4860252726Srpaulo 4861252726Srpaulo#ifdef CONFIG_WPS 4862252726Srpaulo if (mask & WPA_BSS_MASK_WPS_SCAN) { 4863252726Srpaulo ie = (const u8 *) (bss + 1); 4864252726Srpaulo ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end); 4865289549Srpaulo if (ret >= end - pos) 4866252726Srpaulo return 0; 4867289549Srpaulo if (ret > 0) 4868289549Srpaulo pos += ret; 4869252726Srpaulo } 4870252726Srpaulo#endif /* CONFIG_WPS */ 4871252726Srpaulo 4872252726Srpaulo#ifdef CONFIG_P2P 4873252726Srpaulo if (mask & WPA_BSS_MASK_P2P_SCAN) { 4874252726Srpaulo ie = (const u8 *) (bss + 1); 4875252726Srpaulo ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); 4876337817Scy if (ret >= end - pos) 4877252726Srpaulo return 0; 4878337817Scy if (ret > 0) 4879337817Scy pos += ret; 4880252726Srpaulo } 4881252726Srpaulo#endif /* CONFIG_P2P */ 4882252726Srpaulo 4883252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY 4884252726Srpaulo if (mask & WPA_BSS_MASK_WIFI_DISPLAY) { 4885252726Srpaulo struct wpabuf *wfd; 4886252726Srpaulo ie = (const u8 *) (bss + 1); 4887252726Srpaulo wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len, 4888252726Srpaulo WFD_IE_VENDOR_TYPE); 4889252726Srpaulo if (wfd) { 4890252726Srpaulo ret = os_snprintf(pos, end - pos, "wfd_subelems="); 4891281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 4892281806Srpaulo wpabuf_free(wfd); 4893281806Srpaulo return 0; 4894281806Srpaulo } 4895252726Srpaulo pos += ret; 4896252726Srpaulo 4897252726Srpaulo pos += wpa_snprintf_hex(pos, end - pos, 4898252726Srpaulo wpabuf_head(wfd), 4899252726Srpaulo wpabuf_len(wfd)); 4900252726Srpaulo wpabuf_free(wfd); 4901252726Srpaulo 4902252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 4903281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4904281806Srpaulo return 0; 4905252726Srpaulo pos += ret; 4906252726Srpaulo } 4907252726Srpaulo } 4908252726Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 4909252726Srpaulo 4910252726Srpaulo#ifdef CONFIG_INTERWORKING 4911252726Srpaulo if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { 4912252726Srpaulo struct wpa_bss_anqp *anqp = bss->anqp; 4913337817Scy struct wpa_bss_anqp_elem *elem; 4914337817Scy 4915281806Srpaulo pos = anqp_add_hex(pos, end, "anqp_capability_list", 4916281806Srpaulo anqp->capability_list); 4917252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_venue_name", 4918252726Srpaulo anqp->venue_name); 4919252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_network_auth_type", 4920252726Srpaulo anqp->network_auth_type); 4921252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_roaming_consortium", 4922252726Srpaulo anqp->roaming_consortium); 4923252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability", 4924252726Srpaulo anqp->ip_addr_type_availability); 4925252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_nai_realm", 4926252726Srpaulo anqp->nai_realm); 4927252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp); 4928252726Srpaulo pos = anqp_add_hex(pos, end, "anqp_domain_name", 4929252726Srpaulo anqp->domain_name); 4930346981Scy pos = anqp_add_hex(pos, end, "anqp_fils_realm_info", 4931346981Scy anqp->fils_realm_info); 4932252726Srpaulo#ifdef CONFIG_HS20 4933281806Srpaulo pos = anqp_add_hex(pos, end, "hs20_capability_list", 4934281806Srpaulo anqp->hs20_capability_list); 4935252726Srpaulo pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name", 4936252726Srpaulo anqp->hs20_operator_friendly_name); 4937252726Srpaulo pos = anqp_add_hex(pos, end, "hs20_wan_metrics", 4938252726Srpaulo anqp->hs20_wan_metrics); 4939252726Srpaulo pos = anqp_add_hex(pos, end, "hs20_connection_capability", 4940252726Srpaulo anqp->hs20_connection_capability); 4941281806Srpaulo pos = anqp_add_hex(pos, end, "hs20_operating_class", 4942281806Srpaulo anqp->hs20_operating_class); 4943281806Srpaulo pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", 4944281806Srpaulo anqp->hs20_osu_providers_list); 4945346981Scy pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata", 4946346981Scy anqp->hs20_operator_icon_metadata); 4947346981Scy pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list", 4948346981Scy anqp->hs20_osu_providers_nai_list); 4949252726Srpaulo#endif /* CONFIG_HS20 */ 4950337817Scy 4951337817Scy dl_list_for_each(elem, &anqp->anqp_elems, 4952337817Scy struct wpa_bss_anqp_elem, list) { 4953337817Scy char title[20]; 4954337817Scy 4955337817Scy os_snprintf(title, sizeof(title), "anqp[%u]", 4956337817Scy elem->infoid); 4957337817Scy pos = anqp_add_hex(pos, end, title, elem->payload); 4958337817Scy } 4959252726Srpaulo } 4960252726Srpaulo#endif /* CONFIG_INTERWORKING */ 4961252726Srpaulo 4962281806Srpaulo#ifdef CONFIG_MESH 4963281806Srpaulo if (mask & WPA_BSS_MASK_MESH_SCAN) { 4964281806Srpaulo ie = (const u8 *) (bss + 1); 4965281806Srpaulo ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end); 4966337817Scy if (ret >= end - pos) 4967281806Srpaulo return 0; 4968337817Scy if (ret > 0) 4969337817Scy pos += ret; 4970281806Srpaulo } 4971281806Srpaulo#endif /* CONFIG_MESH */ 4972281806Srpaulo 4973281806Srpaulo if (mask & WPA_BSS_MASK_SNR) { 4974281806Srpaulo ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr); 4975281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4976281806Srpaulo return 0; 4977281806Srpaulo pos += ret; 4978281806Srpaulo } 4979281806Srpaulo 4980281806Srpaulo if (mask & WPA_BSS_MASK_EST_THROUGHPUT) { 4981281806Srpaulo ret = os_snprintf(pos, end - pos, "est_throughput=%d\n", 4982281806Srpaulo bss->est_throughput); 4983281806Srpaulo if (os_snprintf_error(end - pos, ret)) 4984281806Srpaulo return 0; 4985281806Srpaulo pos += ret; 4986281806Srpaulo } 4987281806Srpaulo 4988289549Srpaulo#ifdef CONFIG_FST 4989289549Srpaulo if (mask & WPA_BSS_MASK_FST) { 4990289549Srpaulo ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos); 4991289549Srpaulo if (ret < 0 || ret >= end - pos) 4992289549Srpaulo return 0; 4993289549Srpaulo pos += ret; 4994289549Srpaulo } 4995289549Srpaulo#endif /* CONFIG_FST */ 4996289549Srpaulo 4997346981Scy if (mask & WPA_BSS_MASK_UPDATE_IDX) { 4998346981Scy ret = os_snprintf(pos, end - pos, "update_idx=%u\n", 4999346981Scy bss->last_update_idx); 5000346981Scy if (os_snprintf_error(end - pos, ret)) 5001346981Scy return 0; 5002346981Scy pos += ret; 5003346981Scy } 5004346981Scy 5005346981Scy if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) { 5006346981Scy ret = os_snprintf(pos, end - pos, "beacon_ie="); 5007346981Scy if (os_snprintf_error(end - pos, ret)) 5008346981Scy return 0; 5009346981Scy pos += ret; 5010346981Scy 5011346981Scy ie = (const u8 *) (bss + 1); 5012346981Scy ie += bss->ie_len; 5013346981Scy for (i = 0; i < bss->beacon_ie_len; i++) { 5014346981Scy ret = os_snprintf(pos, end - pos, "%02x", *ie++); 5015346981Scy if (os_snprintf_error(end - pos, ret)) 5016346981Scy return 0; 5017346981Scy pos += ret; 5018346981Scy } 5019346981Scy 5020346981Scy ret = os_snprintf(pos, end - pos, "\n"); 5021346981Scy if (os_snprintf_error(end - pos, ret)) 5022346981Scy return 0; 5023346981Scy pos += ret; 5024346981Scy } 5025346981Scy 5026346981Scy#ifdef CONFIG_FILS 5027346981Scy if (mask & WPA_BSS_MASK_FILS_INDICATION) { 5028346981Scy ret = print_fils_indication(bss, pos, end); 5029346981Scy if (ret < 0) 5030346981Scy return 0; 5031346981Scy pos += ret; 5032346981Scy } 5033346981Scy#endif /* CONFIG_FILS */ 5034346981Scy 5035281806Srpaulo if (mask & WPA_BSS_MASK_DELIM) { 5036281806Srpaulo ret = os_snprintf(pos, end - pos, "====\n"); 5037281806Srpaulo if (os_snprintf_error(end - pos, ret)) 5038281806Srpaulo return 0; 5039281806Srpaulo pos += ret; 5040281806Srpaulo } 5041281806Srpaulo 5042252726Srpaulo return pos - buf; 5043252726Srpaulo} 5044252726Srpaulo 5045252726Srpaulo 5046189251Ssamstatic int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, 5047189251Ssam const char *cmd, char *buf, 5048189251Ssam size_t buflen) 5049189251Ssam{ 5050189251Ssam u8 bssid[ETH_ALEN]; 5051189251Ssam size_t i; 5052214734Srpaulo struct wpa_bss *bss; 5053252726Srpaulo struct wpa_bss *bsslast = NULL; 5054252726Srpaulo struct dl_list *next; 5055252726Srpaulo int ret = 0; 5056252726Srpaulo int len; 5057281806Srpaulo char *ctmp, *end = buf + buflen; 5058252726Srpaulo unsigned long mask = WPA_BSS_MASK_ALL; 5059189251Ssam 5060252726Srpaulo if (os_strncmp(cmd, "RANGE=", 6) == 0) { 5061252726Srpaulo if (os_strncmp(cmd + 6, "ALL", 3) == 0) { 5062252726Srpaulo bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, 5063252726Srpaulo list_id); 5064252726Srpaulo bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss, 5065252726Srpaulo list_id); 5066252726Srpaulo } else { /* N1-N2 */ 5067252726Srpaulo unsigned int id1, id2; 5068252726Srpaulo 5069252726Srpaulo if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) { 5070252726Srpaulo wpa_printf(MSG_INFO, "Wrong BSS range " 5071252726Srpaulo "format"); 5072252726Srpaulo return 0; 5073252726Srpaulo } 5074252726Srpaulo 5075281806Srpaulo if (*(cmd + 6) == '-') 5076281806Srpaulo id1 = 0; 5077281806Srpaulo else 5078281806Srpaulo id1 = atoi(cmd + 6); 5079281806Srpaulo ctmp++; 5080281806Srpaulo if (*ctmp >= '0' && *ctmp <= '9') 5081281806Srpaulo id2 = atoi(ctmp); 5082281806Srpaulo else 5083281806Srpaulo id2 = (unsigned int) -1; 5084281806Srpaulo bss = wpa_bss_get_id_range(wpa_s, id1, id2); 5085281806Srpaulo if (id2 == (unsigned int) -1) 5086252726Srpaulo bsslast = dl_list_last(&wpa_s->bss_id, 5087252726Srpaulo struct wpa_bss, 5088252726Srpaulo list_id); 5089252726Srpaulo else { 5090252726Srpaulo bsslast = wpa_bss_get_id(wpa_s, id2); 5091252726Srpaulo if (bsslast == NULL && bss && id2 > id1) { 5092252726Srpaulo struct wpa_bss *tmp = bss; 5093252726Srpaulo for (;;) { 5094252726Srpaulo next = tmp->list_id.next; 5095252726Srpaulo if (next == &wpa_s->bss_id) 5096252726Srpaulo break; 5097252726Srpaulo tmp = dl_list_entry( 5098252726Srpaulo next, struct wpa_bss, 5099252726Srpaulo list_id); 5100252726Srpaulo if (tmp->id > id2) 5101252726Srpaulo break; 5102252726Srpaulo bsslast = tmp; 5103252726Srpaulo } 5104252726Srpaulo } 5105252726Srpaulo } 5106252726Srpaulo } 5107281806Srpaulo } else if (os_strncmp(cmd, "FIRST", 5) == 0) 5108252726Srpaulo bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id); 5109281806Srpaulo else if (os_strncmp(cmd, "LAST", 4) == 0) 5110281806Srpaulo bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id); 5111214734Srpaulo else if (os_strncmp(cmd, "ID-", 3) == 0) { 5112214734Srpaulo i = atoi(cmd + 3); 5113214734Srpaulo bss = wpa_bss_get_id(wpa_s, i); 5114214734Srpaulo } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { 5115214734Srpaulo i = atoi(cmd + 5); 5116214734Srpaulo bss = wpa_bss_get_id(wpa_s, i); 5117214734Srpaulo if (bss) { 5118252726Srpaulo next = bss->list_id.next; 5119214734Srpaulo if (next == &wpa_s->bss_id) 5120214734Srpaulo bss = NULL; 5121214734Srpaulo else 5122214734Srpaulo bss = dl_list_entry(next, struct wpa_bss, 5123214734Srpaulo list_id); 5124214734Srpaulo } 5125346981Scy } else if (os_strncmp(cmd, "CURRENT", 7) == 0) { 5126346981Scy bss = wpa_s->current_bss; 5127252726Srpaulo#ifdef CONFIG_P2P 5128252726Srpaulo } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { 5129252726Srpaulo if (hwaddr_aton(cmd + 13, bssid) == 0) 5130252726Srpaulo bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid); 5131252726Srpaulo else 5132252726Srpaulo bss = NULL; 5133252726Srpaulo#endif /* CONFIG_P2P */ 5134214734Srpaulo } else if (hwaddr_aton(cmd, bssid) == 0) 5135214734Srpaulo bss = wpa_bss_get_bssid(wpa_s, bssid); 5136214734Srpaulo else { 5137214734Srpaulo struct wpa_bss *tmp; 5138214734Srpaulo i = atoi(cmd); 5139214734Srpaulo bss = NULL; 5140214734Srpaulo dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id) 5141214734Srpaulo { 5142346981Scy if (i == 0) { 5143214734Srpaulo bss = tmp; 5144189251Ssam break; 5145214734Srpaulo } 5146346981Scy i--; 5147189251Ssam } 5148214734Srpaulo } 5149189251Ssam 5150252726Srpaulo if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) { 5151252726Srpaulo mask = strtoul(ctmp + 5, NULL, 0x10); 5152252726Srpaulo if (mask == 0) 5153252726Srpaulo mask = WPA_BSS_MASK_ALL; 5154252726Srpaulo } 5155252726Srpaulo 5156214734Srpaulo if (bss == NULL) 5157214734Srpaulo return 0; 5158189251Ssam 5159252726Srpaulo if (bsslast == NULL) 5160252726Srpaulo bsslast = bss; 5161252726Srpaulo do { 5162252726Srpaulo len = print_bss_info(wpa_s, bss, mask, buf, buflen); 5163252726Srpaulo ret += len; 5164252726Srpaulo buf += len; 5165252726Srpaulo buflen -= len; 5166281806Srpaulo if (bss == bsslast) { 5167281806Srpaulo if ((mask & WPA_BSS_MASK_DELIM) && len && 5168281806Srpaulo (bss == dl_list_last(&wpa_s->bss_id, 5169281806Srpaulo struct wpa_bss, list_id))) { 5170281806Srpaulo int res; 5171281806Srpaulo 5172281806Srpaulo res = os_snprintf(buf - 5, end - buf + 5, 5173281806Srpaulo "####\n"); 5174281806Srpaulo if (os_snprintf_error(end - buf + 5, res)) { 5175281806Srpaulo wpa_printf(MSG_DEBUG, 5176281806Srpaulo "Could not add end delim"); 5177281806Srpaulo } 5178281806Srpaulo } 5179252726Srpaulo break; 5180281806Srpaulo } 5181252726Srpaulo next = bss->list_id.next; 5182252726Srpaulo if (next == &wpa_s->bss_id) 5183252726Srpaulo break; 5184252726Srpaulo bss = dl_list_entry(next, struct wpa_bss, list_id); 5185252726Srpaulo } while (bss && len); 5186189251Ssam 5187252726Srpaulo return ret; 5188252726Srpaulo} 5189189251Ssam 5190189251Ssam 5191252726Srpaulostatic int wpa_supplicant_ctrl_iface_ap_scan( 5192252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 5193252726Srpaulo{ 5194252726Srpaulo int ap_scan = atoi(cmd); 5195252726Srpaulo return wpa_supplicant_set_ap_scan(wpa_s, ap_scan); 5196252726Srpaulo} 5197189251Ssam 5198189251Ssam 5199252726Srpaulostatic int wpa_supplicant_ctrl_iface_scan_interval( 5200252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 5201252726Srpaulo{ 5202252726Srpaulo int scan_int = atoi(cmd); 5203252726Srpaulo return wpa_supplicant_set_scan_interval(wpa_s, scan_int); 5204252726Srpaulo} 5205189251Ssam 5206189251Ssam 5207252726Srpaulostatic int wpa_supplicant_ctrl_iface_bss_expire_age( 5208252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 5209252726Srpaulo{ 5210252726Srpaulo int expire_age = atoi(cmd); 5211252726Srpaulo return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age); 5212252726Srpaulo} 5213214734Srpaulo 5214252726Srpaulo 5215252726Srpaulostatic int wpa_supplicant_ctrl_iface_bss_expire_count( 5216252726Srpaulo struct wpa_supplicant *wpa_s, char *cmd) 5217252726Srpaulo{ 5218252726Srpaulo int expire_count = atoi(cmd); 5219252726Srpaulo return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count); 5220189251Ssam} 5221189251Ssam 5222189251Ssam 5223281806Srpaulostatic void wpa_supplicant_ctrl_iface_bss_flush( 5224189251Ssam struct wpa_supplicant *wpa_s, char *cmd) 5225189251Ssam{ 5226252726Srpaulo int flush_age = atoi(cmd); 5227252726Srpaulo 5228252726Srpaulo if (flush_age == 0) 5229252726Srpaulo wpa_bss_flush(wpa_s); 5230252726Srpaulo else 5231252726Srpaulo wpa_bss_flush_by_age(wpa_s, flush_age); 5232214734Srpaulo} 5233189251Ssam 5234214734Srpaulo 5235281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 5236214734Srpaulostatic void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) 5237214734Srpaulo{ 5238214734Srpaulo wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); 5239214734Srpaulo /* MLME-DELETEKEYS.request */ 5240252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); 5241252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); 5242252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); 5243252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); 5244214734Srpaulo#ifdef CONFIG_IEEE80211W 5245252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); 5246252726Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); 5247214734Srpaulo#endif /* CONFIG_IEEE80211W */ 5248214734Srpaulo 5249214734Srpaulo wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, 5250214734Srpaulo 0); 5251214734Srpaulo /* MLME-SETPROTECTION.request(None) */ 5252214734Srpaulo wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, 5253214734Srpaulo MLME_SETPROTECTION_PROTECT_TYPE_NONE, 5254214734Srpaulo MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); 5255214734Srpaulo wpa_sm_drop_sa(wpa_s->wpa); 5256214734Srpaulo} 5257281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 5258214734Srpaulo 5259214734Srpaulo 5260214734Srpaulostatic int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s, 5261214734Srpaulo char *addr) 5262214734Srpaulo{ 5263252726Srpaulo#ifdef CONFIG_NO_SCAN_PROCESSING 5264252726Srpaulo return -1; 5265252726Srpaulo#else /* CONFIG_NO_SCAN_PROCESSING */ 5266214734Srpaulo u8 bssid[ETH_ALEN]; 5267214734Srpaulo struct wpa_bss *bss; 5268214734Srpaulo struct wpa_ssid *ssid = wpa_s->current_ssid; 5269214734Srpaulo 5270214734Srpaulo if (hwaddr_aton(addr, bssid)) { 5271214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid " 5272214734Srpaulo "address '%s'", addr); 5273189251Ssam return -1; 5274214734Srpaulo } 5275214734Srpaulo 5276214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid)); 5277214734Srpaulo 5278281806Srpaulo if (!ssid) { 5279281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network " 5280281806Srpaulo "configuration known for the target AP"); 5281281806Srpaulo return -1; 5282281806Srpaulo } 5283281806Srpaulo 5284281806Srpaulo bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); 5285214734Srpaulo if (!bss) { 5286214734Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found " 5287214734Srpaulo "from BSS table"); 5288214734Srpaulo return -1; 5289214734Srpaulo } 5290214734Srpaulo 5291214734Srpaulo /* 5292214734Srpaulo * TODO: Find best network configuration block from configuration to 5293214734Srpaulo * allow roaming to other networks 5294214734Srpaulo */ 5295214734Srpaulo 5296214734Srpaulo wpa_s->reassociate = 1; 5297214734Srpaulo wpa_supplicant_connect(wpa_s, bss, ssid); 5298214734Srpaulo 5299189251Ssam return 0; 5300252726Srpaulo#endif /* CONFIG_NO_SCAN_PROCESSING */ 5301189251Ssam} 5302189251Ssam 5303189251Ssam 5304252726Srpaulo#ifdef CONFIG_P2P 5305252726Srpaulostatic int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) 5306252726Srpaulo{ 5307252726Srpaulo unsigned int timeout = atoi(cmd); 5308252726Srpaulo enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; 5309252726Srpaulo u8 dev_id[ETH_ALEN], *_dev_id = NULL; 5310281806Srpaulo u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL; 5311252726Srpaulo char *pos; 5312252726Srpaulo unsigned int search_delay; 5313281806Srpaulo const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL; 5314281806Srpaulo u8 seek_count = 0; 5315281806Srpaulo int freq = 0; 5316252726Srpaulo 5317281806Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 5318281806Srpaulo wpa_dbg(wpa_s, MSG_INFO, 5319281806Srpaulo "Reject P2P_FIND since interface is disabled"); 5320281806Srpaulo return -1; 5321281806Srpaulo } 5322252726Srpaulo if (os_strstr(cmd, "type=social")) 5323252726Srpaulo type = P2P_FIND_ONLY_SOCIAL; 5324252726Srpaulo else if (os_strstr(cmd, "type=progressive")) 5325252726Srpaulo type = P2P_FIND_PROGRESSIVE; 5326252726Srpaulo 5327252726Srpaulo pos = os_strstr(cmd, "dev_id="); 5328252726Srpaulo if (pos) { 5329252726Srpaulo pos += 7; 5330252726Srpaulo if (hwaddr_aton(pos, dev_id)) 5331252726Srpaulo return -1; 5332252726Srpaulo _dev_id = dev_id; 5333252726Srpaulo } 5334252726Srpaulo 5335281806Srpaulo pos = os_strstr(cmd, "dev_type="); 5336281806Srpaulo if (pos) { 5337281806Srpaulo pos += 9; 5338281806Srpaulo if (wps_dev_type_str2bin(pos, dev_type) < 0) 5339281806Srpaulo return -1; 5340281806Srpaulo _dev_type = dev_type; 5341281806Srpaulo } 5342281806Srpaulo 5343252726Srpaulo pos = os_strstr(cmd, "delay="); 5344252726Srpaulo if (pos) { 5345252726Srpaulo pos += 6; 5346252726Srpaulo search_delay = atoi(pos); 5347252726Srpaulo } else 5348252726Srpaulo search_delay = wpas_p2p_search_delay(wpa_s); 5349252726Srpaulo 5350289549Srpaulo pos = os_strstr(cmd, "freq="); 5351289549Srpaulo if (pos) { 5352289549Srpaulo pos += 5; 5353289549Srpaulo freq = atoi(pos); 5354289549Srpaulo if (freq <= 0) 5355289549Srpaulo return -1; 5356289549Srpaulo } 5357289549Srpaulo 5358281806Srpaulo /* Must be searched for last, because it adds nul termination */ 5359281806Srpaulo pos = os_strstr(cmd, " seek="); 5360289549Srpaulo if (pos) 5361289549Srpaulo pos += 6; 5362281806Srpaulo while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) { 5363281806Srpaulo char *term; 5364281806Srpaulo 5365289549Srpaulo _seek[seek_count++] = pos; 5366281806Srpaulo seek = _seek; 5367289549Srpaulo term = os_strchr(pos, ' '); 5368289549Srpaulo if (!term) 5369289549Srpaulo break; 5370289549Srpaulo *term = '\0'; 5371289549Srpaulo pos = os_strstr(term + 1, "seek="); 5372289549Srpaulo if (pos) 5373289549Srpaulo pos += 5; 5374281806Srpaulo } 5375281806Srpaulo if (seek_count > P2P_MAX_QUERY_HASH) { 5376281806Srpaulo seek[0] = NULL; 5377281806Srpaulo seek_count = 1; 5378281806Srpaulo } 5379281806Srpaulo 5380281806Srpaulo return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type, 5381281806Srpaulo _dev_id, search_delay, seek_count, seek, freq); 5382252726Srpaulo} 5383252726Srpaulo 5384252726Srpaulo 5385289549Srpaulostatic int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt) 5386289549Srpaulo{ 5387289549Srpaulo const char *last = NULL; 5388289549Srpaulo const char *token; 5389289549Srpaulo long int token_len; 5390289549Srpaulo unsigned int i; 5391289549Srpaulo 5392289549Srpaulo /* Expected predefined CPT names delimited by ':' */ 5393289549Srpaulo for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) { 5394289549Srpaulo if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) { 5395289549Srpaulo wpa_printf(MSG_ERROR, 5396289549Srpaulo "P2PS: CPT name list is too long, expected up to %d names", 5397289549Srpaulo P2PS_FEATURE_CAPAB_CPT_MAX); 5398289549Srpaulo cpt[0] = 0; 5399289549Srpaulo return -1; 5400289549Srpaulo } 5401289549Srpaulo 5402289549Srpaulo token_len = last - token; 5403289549Srpaulo 5404289549Srpaulo if (token_len == 3 && 5405289549Srpaulo os_memcmp(token, "UDP", token_len) == 0) { 5406289549Srpaulo cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 5407289549Srpaulo } else if (token_len == 3 && 5408289549Srpaulo os_memcmp(token, "MAC", token_len) == 0) { 5409289549Srpaulo cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT; 5410289549Srpaulo } else { 5411289549Srpaulo wpa_printf(MSG_ERROR, 5412289549Srpaulo "P2PS: Unsupported CPT name '%s'", token); 5413289549Srpaulo cpt[0] = 0; 5414289549Srpaulo return -1; 5415289549Srpaulo } 5416289549Srpaulo 5417337817Scy if (isblank((unsigned char) *last)) { 5418289549Srpaulo i++; 5419289549Srpaulo break; 5420289549Srpaulo } 5421289549Srpaulo } 5422289549Srpaulo cpt[i] = 0; 5423289549Srpaulo return 0; 5424289549Srpaulo} 5425289549Srpaulo 5426289549Srpaulo 5427281806Srpaulostatic struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd) 5428281806Srpaulo{ 5429281806Srpaulo struct p2ps_provision *p2ps_prov; 5430281806Srpaulo char *pos; 5431281806Srpaulo size_t info_len = 0; 5432281806Srpaulo char *info = NULL; 5433281806Srpaulo u8 role = P2PS_SETUP_NONE; 5434281806Srpaulo long long unsigned val; 5435289549Srpaulo int i; 5436281806Srpaulo 5437281806Srpaulo pos = os_strstr(cmd, "info="); 5438281806Srpaulo if (pos) { 5439281806Srpaulo pos += 5; 5440281806Srpaulo info_len = os_strlen(pos); 5441281806Srpaulo 5442281806Srpaulo if (info_len) { 5443281806Srpaulo info = os_malloc(info_len + 1); 5444281806Srpaulo if (info) { 5445281806Srpaulo info_len = utf8_unescape(pos, info_len, 5446281806Srpaulo info, info_len + 1); 5447281806Srpaulo } else 5448281806Srpaulo info_len = 0; 5449281806Srpaulo } 5450281806Srpaulo } 5451281806Srpaulo 5452281806Srpaulo p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1); 5453281806Srpaulo if (p2ps_prov == NULL) { 5454281806Srpaulo os_free(info); 5455281806Srpaulo return NULL; 5456281806Srpaulo } 5457281806Srpaulo 5458281806Srpaulo if (info) { 5459281806Srpaulo os_memcpy(p2ps_prov->info, info, info_len); 5460281806Srpaulo p2ps_prov->info[info_len] = '\0'; 5461281806Srpaulo os_free(info); 5462281806Srpaulo } 5463281806Srpaulo 5464281806Srpaulo pos = os_strstr(cmd, "status="); 5465281806Srpaulo if (pos) 5466281806Srpaulo p2ps_prov->status = atoi(pos + 7); 5467281806Srpaulo else 5468281806Srpaulo p2ps_prov->status = -1; 5469281806Srpaulo 5470281806Srpaulo pos = os_strstr(cmd, "adv_id="); 5471281806Srpaulo if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL) 5472281806Srpaulo goto invalid_args; 5473281806Srpaulo p2ps_prov->adv_id = val; 5474281806Srpaulo 5475281806Srpaulo pos = os_strstr(cmd, "method="); 5476281806Srpaulo if (pos) 5477281806Srpaulo p2ps_prov->method = strtol(pos + 7, NULL, 16); 5478281806Srpaulo else 5479281806Srpaulo p2ps_prov->method = 0; 5480281806Srpaulo 5481281806Srpaulo pos = os_strstr(cmd, "session="); 5482281806Srpaulo if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL) 5483281806Srpaulo goto invalid_args; 5484281806Srpaulo p2ps_prov->session_id = val; 5485281806Srpaulo 5486281806Srpaulo pos = os_strstr(cmd, "adv_mac="); 5487281806Srpaulo if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac)) 5488281806Srpaulo goto invalid_args; 5489281806Srpaulo 5490281806Srpaulo pos = os_strstr(cmd, "session_mac="); 5491281806Srpaulo if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac)) 5492281806Srpaulo goto invalid_args; 5493281806Srpaulo 5494289549Srpaulo pos = os_strstr(cmd, "cpt="); 5495289549Srpaulo if (pos) { 5496289549Srpaulo if (p2ps_ctrl_parse_cpt_priority(pos + 4, 5497289549Srpaulo p2ps_prov->cpt_priority)) 5498289549Srpaulo goto invalid_args; 5499289549Srpaulo } else { 5500289549Srpaulo p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 5501289549Srpaulo } 5502289549Srpaulo 5503289549Srpaulo for (i = 0; p2ps_prov->cpt_priority[i]; i++) 5504289549Srpaulo p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i]; 5505289549Srpaulo 5506281806Srpaulo /* force conncap with tstCap (no sanity checks) */ 5507281806Srpaulo pos = os_strstr(cmd, "tstCap="); 5508281806Srpaulo if (pos) { 5509281806Srpaulo role = strtol(pos + 7, NULL, 16); 5510281806Srpaulo } else { 5511281806Srpaulo pos = os_strstr(cmd, "role="); 5512281806Srpaulo if (pos) { 5513281806Srpaulo role = strtol(pos + 5, NULL, 16); 5514281806Srpaulo if (role != P2PS_SETUP_CLIENT && 5515281806Srpaulo role != P2PS_SETUP_GROUP_OWNER) 5516281806Srpaulo role = P2PS_SETUP_NONE; 5517281806Srpaulo } 5518281806Srpaulo } 5519281806Srpaulo p2ps_prov->role = role; 5520281806Srpaulo 5521281806Srpaulo return p2ps_prov; 5522281806Srpaulo 5523281806Srpauloinvalid_args: 5524281806Srpaulo os_free(p2ps_prov); 5525281806Srpaulo return NULL; 5526281806Srpaulo} 5527281806Srpaulo 5528281806Srpaulo 5529281806Srpaulostatic int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd) 5530281806Srpaulo{ 5531281806Srpaulo u8 addr[ETH_ALEN]; 5532281806Srpaulo struct p2ps_provision *p2ps_prov; 5533281806Srpaulo char *pos; 5534281806Srpaulo 5535281806Srpaulo /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */ 5536281806Srpaulo 5537281806Srpaulo wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); 5538281806Srpaulo 5539281806Srpaulo if (hwaddr_aton(cmd, addr)) 5540281806Srpaulo return -1; 5541281806Srpaulo 5542281806Srpaulo pos = cmd + 17; 5543281806Srpaulo if (*pos != ' ') 5544281806Srpaulo return -1; 5545281806Srpaulo 5546281806Srpaulo p2ps_prov = p2p_parse_asp_provision_cmd(pos); 5547281806Srpaulo if (!p2ps_prov) 5548281806Srpaulo return -1; 5549281806Srpaulo 5550281806Srpaulo if (p2ps_prov->status < 0) { 5551281806Srpaulo os_free(p2ps_prov); 5552281806Srpaulo return -1; 5553281806Srpaulo } 5554281806Srpaulo 5555281806Srpaulo return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, 5556281806Srpaulo p2ps_prov); 5557281806Srpaulo} 5558281806Srpaulo 5559281806Srpaulo 5560281806Srpaulostatic int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd) 5561281806Srpaulo{ 5562281806Srpaulo u8 addr[ETH_ALEN]; 5563281806Srpaulo struct p2ps_provision *p2ps_prov; 5564281806Srpaulo char *pos; 5565281806Srpaulo 5566281806Srpaulo /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap> 5567281806Srpaulo * session=<ses_id> mac=<ses_mac> [info=<infodata>] 5568281806Srpaulo */ 5569281806Srpaulo 5570281806Srpaulo wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); 5571281806Srpaulo if (hwaddr_aton(cmd, addr)) 5572281806Srpaulo return -1; 5573281806Srpaulo 5574281806Srpaulo pos = cmd + 17; 5575281806Srpaulo if (*pos != ' ') 5576281806Srpaulo return -1; 5577281806Srpaulo 5578281806Srpaulo p2ps_prov = p2p_parse_asp_provision_cmd(pos); 5579281806Srpaulo if (!p2ps_prov) 5580281806Srpaulo return -1; 5581281806Srpaulo 5582289549Srpaulo p2ps_prov->pd_seeker = 1; 5583289549Srpaulo 5584281806Srpaulo return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, 5585281806Srpaulo p2ps_prov); 5586281806Srpaulo} 5587281806Srpaulo 5588281806Srpaulo 5589337817Scystatic int parse_freq(int chwidth, int freq2) 5590337817Scy{ 5591337817Scy if (freq2 < 0) 5592337817Scy return -1; 5593337817Scy if (freq2) 5594351611Scy return CHANWIDTH_80P80MHZ; 5595337817Scy 5596337817Scy switch (chwidth) { 5597337817Scy case 0: 5598337817Scy case 20: 5599337817Scy case 40: 5600351611Scy return CHANWIDTH_USE_HT; 5601337817Scy case 80: 5602351611Scy return CHANWIDTH_80MHZ; 5603337817Scy case 160: 5604351611Scy return CHANWIDTH_160MHZ; 5605337817Scy default: 5606337817Scy wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", 5607337817Scy chwidth); 5608337817Scy return -1; 5609337817Scy } 5610337817Scy} 5611337817Scy 5612337817Scy 5613252726Srpaulostatic int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, 5614252726Srpaulo char *buf, size_t buflen) 5615252726Srpaulo{ 5616252726Srpaulo u8 addr[ETH_ALEN]; 5617252726Srpaulo char *pos, *pos2; 5618252726Srpaulo char *pin = NULL; 5619252726Srpaulo enum p2p_wps_method wps_method; 5620252726Srpaulo int new_pin; 5621252726Srpaulo int ret; 5622252726Srpaulo int persistent_group, persistent_id = -1; 5623252726Srpaulo int join; 5624252726Srpaulo int auth; 5625252726Srpaulo int automatic; 5626252726Srpaulo int go_intent = -1; 5627252726Srpaulo int freq = 0; 5628252726Srpaulo int pd; 5629337817Scy int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; 5630337817Scy u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL; 5631337817Scy size_t group_ssid_len = 0; 5632346981Scy int he; 5633252726Srpaulo 5634281806Srpaulo if (!wpa_s->global->p2p_init_wpa_s) 5635281806Srpaulo return -1; 5636281806Srpaulo if (wpa_s->global->p2p_init_wpa_s != wpa_s) { 5637281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s", 5638281806Srpaulo wpa_s->global->p2p_init_wpa_s->ifname); 5639281806Srpaulo wpa_s = wpa_s->global->p2p_init_wpa_s; 5640281806Srpaulo } 5641281806Srpaulo 5642281806Srpaulo /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] 5643252726Srpaulo * [persistent|persistent=<network id>] 5644252726Srpaulo * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] 5645346981Scy * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */ 5646252726Srpaulo 5647252726Srpaulo if (hwaddr_aton(cmd, addr)) 5648252726Srpaulo return -1; 5649252726Srpaulo 5650252726Srpaulo pos = cmd + 17; 5651252726Srpaulo if (*pos != ' ') 5652252726Srpaulo return -1; 5653252726Srpaulo pos++; 5654252726Srpaulo 5655252726Srpaulo persistent_group = os_strstr(pos, " persistent") != NULL; 5656252726Srpaulo pos2 = os_strstr(pos, " persistent="); 5657252726Srpaulo if (pos2) { 5658252726Srpaulo struct wpa_ssid *ssid; 5659252726Srpaulo persistent_id = atoi(pos2 + 12); 5660252726Srpaulo ssid = wpa_config_get_network(wpa_s->conf, persistent_id); 5661252726Srpaulo if (ssid == NULL || ssid->disabled != 2 || 5662252726Srpaulo ssid->mode != WPAS_MODE_P2P_GO) { 5663252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 5664252726Srpaulo "SSID id=%d for persistent P2P group (GO)", 5665252726Srpaulo persistent_id); 5666252726Srpaulo return -1; 5667252726Srpaulo } 5668252726Srpaulo } 5669252726Srpaulo join = os_strstr(pos, " join") != NULL; 5670252726Srpaulo auth = os_strstr(pos, " auth") != NULL; 5671252726Srpaulo automatic = os_strstr(pos, " auto") != NULL; 5672252726Srpaulo pd = os_strstr(pos, " provdisc") != NULL; 5673281806Srpaulo vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; 5674281806Srpaulo ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || 5675281806Srpaulo vht; 5676346981Scy he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; 5677252726Srpaulo 5678252726Srpaulo pos2 = os_strstr(pos, " go_intent="); 5679252726Srpaulo if (pos2) { 5680252726Srpaulo pos2 += 11; 5681252726Srpaulo go_intent = atoi(pos2); 5682252726Srpaulo if (go_intent < 0 || go_intent > 15) 5683252726Srpaulo return -1; 5684252726Srpaulo } 5685252726Srpaulo 5686252726Srpaulo pos2 = os_strstr(pos, " freq="); 5687252726Srpaulo if (pos2) { 5688252726Srpaulo pos2 += 6; 5689252726Srpaulo freq = atoi(pos2); 5690252726Srpaulo if (freq <= 0) 5691252726Srpaulo return -1; 5692252726Srpaulo } 5693252726Srpaulo 5694337817Scy pos2 = os_strstr(pos, " freq2="); 5695337817Scy if (pos2) 5696337817Scy freq2 = atoi(pos2 + 7); 5697337817Scy 5698337817Scy pos2 = os_strstr(pos, " max_oper_chwidth="); 5699337817Scy if (pos2) 5700337817Scy chwidth = atoi(pos2 + 18); 5701337817Scy 5702337817Scy max_oper_chwidth = parse_freq(chwidth, freq2); 5703337817Scy if (max_oper_chwidth < 0) 5704337817Scy return -1; 5705337817Scy 5706337817Scy pos2 = os_strstr(pos, " ssid="); 5707337817Scy if (pos2) { 5708337817Scy char *end; 5709337817Scy 5710337817Scy pos2 += 6; 5711337817Scy end = os_strchr(pos2, ' '); 5712337817Scy if (!end) 5713337817Scy group_ssid_len = os_strlen(pos2) / 2; 5714337817Scy else 5715337817Scy group_ssid_len = (end - pos2) / 2; 5716337817Scy if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN || 5717337817Scy hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0) 5718337817Scy return -1; 5719337817Scy group_ssid = _group_ssid; 5720337817Scy } 5721337817Scy 5722252726Srpaulo if (os_strncmp(pos, "pin", 3) == 0) { 5723252726Srpaulo /* Request random PIN (to be displayed) and enable the PIN */ 5724252726Srpaulo wps_method = WPS_PIN_DISPLAY; 5725252726Srpaulo } else if (os_strncmp(pos, "pbc", 3) == 0) { 5726252726Srpaulo wps_method = WPS_PBC; 5727337817Scy } else if (os_strstr(pos, "p2ps") != NULL) { 5728337817Scy wps_method = WPS_P2PS; 5729252726Srpaulo } else { 5730252726Srpaulo pin = pos; 5731252726Srpaulo pos = os_strchr(pin, ' '); 5732252726Srpaulo wps_method = WPS_PIN_KEYPAD; 5733252726Srpaulo if (pos) { 5734252726Srpaulo *pos++ = '\0'; 5735252726Srpaulo if (os_strncmp(pos, "display", 7) == 0) 5736252726Srpaulo wps_method = WPS_PIN_DISPLAY; 5737252726Srpaulo } 5738252726Srpaulo if (!wps_pin_str_valid(pin)) { 5739252726Srpaulo os_memcpy(buf, "FAIL-INVALID-PIN\n", 17); 5740252726Srpaulo return 17; 5741252726Srpaulo } 5742252726Srpaulo } 5743252726Srpaulo 5744252726Srpaulo new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, 5745252726Srpaulo persistent_group, automatic, join, 5746337817Scy auth, go_intent, freq, freq2, persistent_id, 5747346981Scy pd, ht40, vht, max_oper_chwidth, he, 5748337817Scy group_ssid, group_ssid_len); 5749252726Srpaulo if (new_pin == -2) { 5750252726Srpaulo os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); 5751252726Srpaulo return 25; 5752252726Srpaulo } 5753252726Srpaulo if (new_pin == -3) { 5754252726Srpaulo os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25); 5755252726Srpaulo return 25; 5756252726Srpaulo } 5757252726Srpaulo if (new_pin < 0) 5758252726Srpaulo return -1; 5759252726Srpaulo if (wps_method == WPS_PIN_DISPLAY && pin == NULL) { 5760252726Srpaulo ret = os_snprintf(buf, buflen, "%08d", new_pin); 5761281806Srpaulo if (os_snprintf_error(buflen, ret)) 5762252726Srpaulo return -1; 5763252726Srpaulo return ret; 5764252726Srpaulo } 5765252726Srpaulo 5766252726Srpaulo os_memcpy(buf, "OK\n", 3); 5767252726Srpaulo return 3; 5768252726Srpaulo} 5769252726Srpaulo 5770252726Srpaulo 5771252726Srpaulostatic int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd) 5772252726Srpaulo{ 5773252726Srpaulo unsigned int timeout = atoi(cmd); 5774281806Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 5775281806Srpaulo wpa_dbg(wpa_s, MSG_INFO, 5776281806Srpaulo "Reject P2P_LISTEN since interface is disabled"); 5777281806Srpaulo return -1; 5778281806Srpaulo } 5779252726Srpaulo return wpas_p2p_listen(wpa_s, timeout); 5780252726Srpaulo} 5781252726Srpaulo 5782252726Srpaulo 5783252726Srpaulostatic int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) 5784252726Srpaulo{ 5785252726Srpaulo u8 addr[ETH_ALEN]; 5786252726Srpaulo char *pos; 5787252726Srpaulo enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG; 5788252726Srpaulo 5789252726Srpaulo /* <addr> <config method> [join|auto] */ 5790252726Srpaulo 5791252726Srpaulo if (hwaddr_aton(cmd, addr)) 5792252726Srpaulo return -1; 5793252726Srpaulo 5794252726Srpaulo pos = cmd + 17; 5795252726Srpaulo if (*pos != ' ') 5796252726Srpaulo return -1; 5797252726Srpaulo pos++; 5798252726Srpaulo 5799252726Srpaulo if (os_strstr(pos, " join") != NULL) 5800252726Srpaulo use = WPAS_P2P_PD_FOR_JOIN; 5801252726Srpaulo else if (os_strstr(pos, " auto") != NULL) 5802252726Srpaulo use = WPAS_P2P_PD_AUTO; 5803252726Srpaulo 5804281806Srpaulo return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL); 5805252726Srpaulo} 5806252726Srpaulo 5807252726Srpaulo 5808252726Srpaulostatic int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf, 5809252726Srpaulo size_t buflen) 5810252726Srpaulo{ 5811252726Srpaulo struct wpa_ssid *ssid = wpa_s->current_ssid; 5812252726Srpaulo 5813252726Srpaulo if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || 5814252726Srpaulo ssid->passphrase == NULL) 5815252726Srpaulo return -1; 5816252726Srpaulo 5817252726Srpaulo os_strlcpy(buf, ssid->passphrase, buflen); 5818252726Srpaulo return os_strlen(buf); 5819252726Srpaulo} 5820252726Srpaulo 5821252726Srpaulo 5822252726Srpaulostatic int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, 5823252726Srpaulo char *buf, size_t buflen) 5824252726Srpaulo{ 5825252726Srpaulo u64 ref; 5826252726Srpaulo int res; 5827252726Srpaulo u8 dst_buf[ETH_ALEN], *dst; 5828252726Srpaulo struct wpabuf *tlvs; 5829252726Srpaulo char *pos; 5830252726Srpaulo size_t len; 5831252726Srpaulo 5832252726Srpaulo if (hwaddr_aton(cmd, dst_buf)) 5833252726Srpaulo return -1; 5834252726Srpaulo dst = dst_buf; 5835252726Srpaulo if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && 5836252726Srpaulo dst[3] == 0 && dst[4] == 0 && dst[5] == 0) 5837252726Srpaulo dst = NULL; 5838252726Srpaulo pos = cmd + 17; 5839252726Srpaulo if (*pos != ' ') 5840252726Srpaulo return -1; 5841252726Srpaulo pos++; 5842252726Srpaulo 5843252726Srpaulo if (os_strncmp(pos, "upnp ", 5) == 0) { 5844252726Srpaulo u8 version; 5845252726Srpaulo pos += 5; 5846252726Srpaulo if (hexstr2bin(pos, &version, 1) < 0) 5847252726Srpaulo return -1; 5848252726Srpaulo pos += 2; 5849252726Srpaulo if (*pos != ' ') 5850252726Srpaulo return -1; 5851252726Srpaulo pos++; 5852252726Srpaulo ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); 5853252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY 5854252726Srpaulo } else if (os_strncmp(pos, "wifi-display ", 13) == 0) { 5855252726Srpaulo ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13); 5856252726Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 5857281806Srpaulo } else if (os_strncmp(pos, "asp ", 4) == 0) { 5858281806Srpaulo char *svc_str; 5859281806Srpaulo char *svc_info = NULL; 5860281806Srpaulo u32 id; 5861281806Srpaulo 5862281806Srpaulo pos += 4; 5863281806Srpaulo if (sscanf(pos, "%x", &id) != 1 || id > 0xff) 5864281806Srpaulo return -1; 5865281806Srpaulo 5866281806Srpaulo pos = os_strchr(pos, ' '); 5867281806Srpaulo if (pos == NULL || pos[1] == '\0' || pos[1] == ' ') 5868281806Srpaulo return -1; 5869281806Srpaulo 5870281806Srpaulo svc_str = pos + 1; 5871281806Srpaulo 5872281806Srpaulo pos = os_strchr(svc_str, ' '); 5873281806Srpaulo 5874281806Srpaulo if (pos) 5875281806Srpaulo *pos++ = '\0'; 5876281806Srpaulo 5877281806Srpaulo /* All remaining data is the svc_info string */ 5878281806Srpaulo if (pos && pos[0] && pos[0] != ' ') { 5879281806Srpaulo len = os_strlen(pos); 5880281806Srpaulo 5881281806Srpaulo /* Unescape in place */ 5882281806Srpaulo len = utf8_unescape(pos, len, pos, len); 5883281806Srpaulo if (len > 0xff) 5884281806Srpaulo return -1; 5885281806Srpaulo 5886281806Srpaulo svc_info = pos; 5887281806Srpaulo } 5888281806Srpaulo 5889281806Srpaulo ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id, 5890281806Srpaulo svc_str, svc_info); 5891252726Srpaulo } else { 5892252726Srpaulo len = os_strlen(pos); 5893252726Srpaulo if (len & 1) 5894252726Srpaulo return -1; 5895252726Srpaulo len /= 2; 5896252726Srpaulo tlvs = wpabuf_alloc(len); 5897252726Srpaulo if (tlvs == NULL) 5898252726Srpaulo return -1; 5899252726Srpaulo if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) { 5900252726Srpaulo wpabuf_free(tlvs); 5901252726Srpaulo return -1; 5902252726Srpaulo } 5903252726Srpaulo 5904252726Srpaulo ref = wpas_p2p_sd_request(wpa_s, dst, tlvs); 5905252726Srpaulo wpabuf_free(tlvs); 5906252726Srpaulo } 5907252726Srpaulo if (ref == 0) 5908252726Srpaulo return -1; 5909252726Srpaulo res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref); 5910281806Srpaulo if (os_snprintf_error(buflen, res)) 5911252726Srpaulo return -1; 5912252726Srpaulo return res; 5913252726Srpaulo} 5914252726Srpaulo 5915252726Srpaulo 5916252726Srpaulostatic int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s, 5917252726Srpaulo char *cmd) 5918252726Srpaulo{ 5919252726Srpaulo long long unsigned val; 5920252726Srpaulo u64 req; 5921252726Srpaulo if (sscanf(cmd, "%llx", &val) != 1) 5922252726Srpaulo return -1; 5923252726Srpaulo req = val; 5924252726Srpaulo return wpas_p2p_sd_cancel_request(wpa_s, req); 5925252726Srpaulo} 5926252726Srpaulo 5927252726Srpaulo 5928252726Srpaulostatic int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd) 5929252726Srpaulo{ 5930252726Srpaulo int freq; 5931252726Srpaulo u8 dst[ETH_ALEN]; 5932252726Srpaulo u8 dialog_token; 5933252726Srpaulo struct wpabuf *resp_tlvs; 5934252726Srpaulo char *pos, *pos2; 5935252726Srpaulo size_t len; 5936252726Srpaulo 5937252726Srpaulo pos = os_strchr(cmd, ' '); 5938252726Srpaulo if (pos == NULL) 5939252726Srpaulo return -1; 5940252726Srpaulo *pos++ = '\0'; 5941252726Srpaulo freq = atoi(cmd); 5942252726Srpaulo if (freq == 0) 5943252726Srpaulo return -1; 5944252726Srpaulo 5945252726Srpaulo if (hwaddr_aton(pos, dst)) 5946252726Srpaulo return -1; 5947252726Srpaulo pos += 17; 5948252726Srpaulo if (*pos != ' ') 5949252726Srpaulo return -1; 5950252726Srpaulo pos++; 5951252726Srpaulo 5952252726Srpaulo pos2 = os_strchr(pos, ' '); 5953252726Srpaulo if (pos2 == NULL) 5954252726Srpaulo return -1; 5955252726Srpaulo *pos2++ = '\0'; 5956252726Srpaulo dialog_token = atoi(pos); 5957252726Srpaulo 5958252726Srpaulo len = os_strlen(pos2); 5959252726Srpaulo if (len & 1) 5960252726Srpaulo return -1; 5961252726Srpaulo len /= 2; 5962252726Srpaulo resp_tlvs = wpabuf_alloc(len); 5963252726Srpaulo if (resp_tlvs == NULL) 5964252726Srpaulo return -1; 5965252726Srpaulo if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) { 5966252726Srpaulo wpabuf_free(resp_tlvs); 5967252726Srpaulo return -1; 5968252726Srpaulo } 5969252726Srpaulo 5970252726Srpaulo wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs); 5971252726Srpaulo wpabuf_free(resp_tlvs); 5972252726Srpaulo return 0; 5973252726Srpaulo} 5974252726Srpaulo 5975252726Srpaulo 5976252726Srpaulostatic int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s, 5977252726Srpaulo char *cmd) 5978252726Srpaulo{ 5979252726Srpaulo if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1")) 5980252726Srpaulo return -1; 5981252726Srpaulo wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd); 5982252726Srpaulo return 0; 5983252726Srpaulo} 5984252726Srpaulo 5985252726Srpaulo 5986252726Srpaulostatic int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, 5987252726Srpaulo char *cmd) 5988252726Srpaulo{ 5989252726Srpaulo char *pos; 5990252726Srpaulo size_t len; 5991252726Srpaulo struct wpabuf *query, *resp; 5992252726Srpaulo 5993252726Srpaulo pos = os_strchr(cmd, ' '); 5994252726Srpaulo if (pos == NULL) 5995252726Srpaulo return -1; 5996252726Srpaulo *pos++ = '\0'; 5997252726Srpaulo 5998252726Srpaulo len = os_strlen(cmd); 5999252726Srpaulo if (len & 1) 6000252726Srpaulo return -1; 6001252726Srpaulo len /= 2; 6002252726Srpaulo query = wpabuf_alloc(len); 6003252726Srpaulo if (query == NULL) 6004252726Srpaulo return -1; 6005252726Srpaulo if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { 6006252726Srpaulo wpabuf_free(query); 6007252726Srpaulo return -1; 6008252726Srpaulo } 6009252726Srpaulo 6010252726Srpaulo len = os_strlen(pos); 6011252726Srpaulo if (len & 1) { 6012252726Srpaulo wpabuf_free(query); 6013252726Srpaulo return -1; 6014252726Srpaulo } 6015252726Srpaulo len /= 2; 6016252726Srpaulo resp = wpabuf_alloc(len); 6017252726Srpaulo if (resp == NULL) { 6018252726Srpaulo wpabuf_free(query); 6019252726Srpaulo return -1; 6020252726Srpaulo } 6021252726Srpaulo if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { 6022252726Srpaulo wpabuf_free(query); 6023252726Srpaulo wpabuf_free(resp); 6024252726Srpaulo return -1; 6025252726Srpaulo } 6026252726Srpaulo 6027252726Srpaulo if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { 6028252726Srpaulo wpabuf_free(query); 6029252726Srpaulo wpabuf_free(resp); 6030252726Srpaulo return -1; 6031252726Srpaulo } 6032252726Srpaulo return 0; 6033252726Srpaulo} 6034252726Srpaulo 6035252726Srpaulo 6036252726Srpaulostatic int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd) 6037252726Srpaulo{ 6038252726Srpaulo char *pos; 6039252726Srpaulo u8 version; 6040252726Srpaulo 6041252726Srpaulo pos = os_strchr(cmd, ' '); 6042252726Srpaulo if (pos == NULL) 6043252726Srpaulo return -1; 6044252726Srpaulo *pos++ = '\0'; 6045252726Srpaulo 6046252726Srpaulo if (hexstr2bin(cmd, &version, 1) < 0) 6047252726Srpaulo return -1; 6048252726Srpaulo 6049252726Srpaulo return wpas_p2p_service_add_upnp(wpa_s, version, pos); 6050252726Srpaulo} 6051252726Srpaulo 6052252726Srpaulo 6053281806Srpaulostatic int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s, 6054281806Srpaulo u8 replace, char *cmd) 6055281806Srpaulo{ 6056281806Srpaulo char *pos; 6057281806Srpaulo char *adv_str; 6058281806Srpaulo u32 auto_accept, adv_id, svc_state, config_methods; 6059281806Srpaulo char *svc_info = NULL; 6060289549Srpaulo char *cpt_prio_str; 6061289549Srpaulo u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1]; 6062281806Srpaulo 6063281806Srpaulo pos = os_strchr(cmd, ' '); 6064281806Srpaulo if (pos == NULL) 6065281806Srpaulo return -1; 6066281806Srpaulo *pos++ = '\0'; 6067281806Srpaulo 6068281806Srpaulo /* Auto-Accept value is mandatory, and must be one of the 6069281806Srpaulo * single values (0, 1, 2, 4) */ 6070281806Srpaulo auto_accept = atoi(cmd); 6071281806Srpaulo switch (auto_accept) { 6072281806Srpaulo case P2PS_SETUP_NONE: /* No auto-accept */ 6073281806Srpaulo case P2PS_SETUP_NEW: 6074281806Srpaulo case P2PS_SETUP_CLIENT: 6075281806Srpaulo case P2PS_SETUP_GROUP_OWNER: 6076281806Srpaulo break; 6077281806Srpaulo default: 6078281806Srpaulo return -1; 6079281806Srpaulo } 6080281806Srpaulo 6081281806Srpaulo /* Advertisement ID is mandatory */ 6082281806Srpaulo cmd = pos; 6083281806Srpaulo pos = os_strchr(cmd, ' '); 6084281806Srpaulo if (pos == NULL) 6085281806Srpaulo return -1; 6086281806Srpaulo *pos++ = '\0'; 6087281806Srpaulo 6088281806Srpaulo /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */ 6089281806Srpaulo if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0) 6090281806Srpaulo return -1; 6091281806Srpaulo 6092281806Srpaulo /* Only allow replacements if exist, and adds if not */ 6093281806Srpaulo if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) { 6094281806Srpaulo if (!replace) 6095281806Srpaulo return -1; 6096281806Srpaulo } else { 6097281806Srpaulo if (replace) 6098281806Srpaulo return -1; 6099281806Srpaulo } 6100281806Srpaulo 6101281806Srpaulo /* svc_state between 0 - 0xff is mandatory */ 6102281806Srpaulo if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff) 6103281806Srpaulo return -1; 6104281806Srpaulo 6105281806Srpaulo pos = os_strchr(pos, ' '); 6106281806Srpaulo if (pos == NULL) 6107281806Srpaulo return -1; 6108281806Srpaulo 6109281806Srpaulo /* config_methods is mandatory */ 6110281806Srpaulo pos++; 6111281806Srpaulo if (sscanf(pos, "%x", &config_methods) != 1) 6112281806Srpaulo return -1; 6113281806Srpaulo 6114281806Srpaulo if (!(config_methods & 6115281806Srpaulo (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS))) 6116281806Srpaulo return -1; 6117281806Srpaulo 6118281806Srpaulo pos = os_strchr(pos, ' '); 6119281806Srpaulo if (pos == NULL) 6120281806Srpaulo return -1; 6121281806Srpaulo 6122281806Srpaulo pos++; 6123281806Srpaulo adv_str = pos; 6124281806Srpaulo 6125281806Srpaulo /* Advertisement string is mandatory */ 6126281806Srpaulo if (!pos[0] || pos[0] == ' ') 6127281806Srpaulo return -1; 6128281806Srpaulo 6129281806Srpaulo /* Terminate svc string */ 6130281806Srpaulo pos = os_strchr(pos, ' '); 6131281806Srpaulo if (pos != NULL) 6132281806Srpaulo *pos++ = '\0'; 6133281806Srpaulo 6134289549Srpaulo cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL; 6135289549Srpaulo if (cpt_prio_str) { 6136289549Srpaulo pos = os_strchr(pos, ' '); 6137289549Srpaulo if (pos != NULL) 6138289549Srpaulo *pos++ = '\0'; 6139289549Srpaulo 6140289549Srpaulo if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio)) 6141289549Srpaulo return -1; 6142289549Srpaulo } else { 6143289549Srpaulo cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 6144289549Srpaulo cpt_prio[1] = 0; 6145289549Srpaulo } 6146289549Srpaulo 6147281806Srpaulo /* Service and Response Information are optional */ 6148281806Srpaulo if (pos && pos[0]) { 6149281806Srpaulo size_t len; 6150281806Srpaulo 6151281806Srpaulo /* Note the bare ' included, which cannot exist legally 6152281806Srpaulo * in unescaped string. */ 6153281806Srpaulo svc_info = os_strstr(pos, "svc_info='"); 6154281806Srpaulo 6155281806Srpaulo if (svc_info) { 6156281806Srpaulo svc_info += 9; 6157281806Srpaulo len = os_strlen(svc_info); 6158281806Srpaulo utf8_unescape(svc_info, len, svc_info, len); 6159281806Srpaulo } 6160281806Srpaulo } 6161281806Srpaulo 6162281806Srpaulo return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str, 6163281806Srpaulo (u8) svc_state, (u16) config_methods, 6164289549Srpaulo svc_info, cpt_prio); 6165281806Srpaulo} 6166281806Srpaulo 6167281806Srpaulo 6168252726Srpaulostatic int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd) 6169252726Srpaulo{ 6170252726Srpaulo char *pos; 6171252726Srpaulo 6172252726Srpaulo pos = os_strchr(cmd, ' '); 6173252726Srpaulo if (pos == NULL) 6174252726Srpaulo return -1; 6175252726Srpaulo *pos++ = '\0'; 6176252726Srpaulo 6177252726Srpaulo if (os_strcmp(cmd, "bonjour") == 0) 6178252726Srpaulo return p2p_ctrl_service_add_bonjour(wpa_s, pos); 6179252726Srpaulo if (os_strcmp(cmd, "upnp") == 0) 6180252726Srpaulo return p2p_ctrl_service_add_upnp(wpa_s, pos); 6181281806Srpaulo if (os_strcmp(cmd, "asp") == 0) 6182281806Srpaulo return p2p_ctrl_service_add_asp(wpa_s, 0, pos); 6183252726Srpaulo wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 6184252726Srpaulo return -1; 6185252726Srpaulo} 6186252726Srpaulo 6187252726Srpaulo 6188252726Srpaulostatic int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s, 6189252726Srpaulo char *cmd) 6190252726Srpaulo{ 6191252726Srpaulo size_t len; 6192252726Srpaulo struct wpabuf *query; 6193252726Srpaulo int ret; 6194252726Srpaulo 6195252726Srpaulo len = os_strlen(cmd); 6196252726Srpaulo if (len & 1) 6197252726Srpaulo return -1; 6198252726Srpaulo len /= 2; 6199252726Srpaulo query = wpabuf_alloc(len); 6200252726Srpaulo if (query == NULL) 6201252726Srpaulo return -1; 6202252726Srpaulo if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { 6203252726Srpaulo wpabuf_free(query); 6204252726Srpaulo return -1; 6205252726Srpaulo } 6206252726Srpaulo 6207252726Srpaulo ret = wpas_p2p_service_del_bonjour(wpa_s, query); 6208252726Srpaulo wpabuf_free(query); 6209252726Srpaulo return ret; 6210252726Srpaulo} 6211252726Srpaulo 6212252726Srpaulo 6213252726Srpaulostatic int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd) 6214252726Srpaulo{ 6215252726Srpaulo char *pos; 6216252726Srpaulo u8 version; 6217252726Srpaulo 6218252726Srpaulo pos = os_strchr(cmd, ' '); 6219252726Srpaulo if (pos == NULL) 6220252726Srpaulo return -1; 6221252726Srpaulo *pos++ = '\0'; 6222252726Srpaulo 6223252726Srpaulo if (hexstr2bin(cmd, &version, 1) < 0) 6224252726Srpaulo return -1; 6225252726Srpaulo 6226252726Srpaulo return wpas_p2p_service_del_upnp(wpa_s, version, pos); 6227252726Srpaulo} 6228252726Srpaulo 6229252726Srpaulo 6230281806Srpaulostatic int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd) 6231281806Srpaulo{ 6232281806Srpaulo u32 adv_id; 6233281806Srpaulo 6234289549Srpaulo if (os_strcmp(cmd, "all") == 0) { 6235289549Srpaulo wpas_p2p_service_flush_asp(wpa_s); 6236289549Srpaulo return 0; 6237289549Srpaulo } 6238289549Srpaulo 6239281806Srpaulo if (sscanf(cmd, "%x", &adv_id) != 1) 6240281806Srpaulo return -1; 6241281806Srpaulo 6242281806Srpaulo return wpas_p2p_service_del_asp(wpa_s, adv_id); 6243281806Srpaulo} 6244281806Srpaulo 6245281806Srpaulo 6246252726Srpaulostatic int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd) 6247252726Srpaulo{ 6248252726Srpaulo char *pos; 6249252726Srpaulo 6250252726Srpaulo pos = os_strchr(cmd, ' '); 6251252726Srpaulo if (pos == NULL) 6252252726Srpaulo return -1; 6253252726Srpaulo *pos++ = '\0'; 6254252726Srpaulo 6255252726Srpaulo if (os_strcmp(cmd, "bonjour") == 0) 6256252726Srpaulo return p2p_ctrl_service_del_bonjour(wpa_s, pos); 6257252726Srpaulo if (os_strcmp(cmd, "upnp") == 0) 6258252726Srpaulo return p2p_ctrl_service_del_upnp(wpa_s, pos); 6259281806Srpaulo if (os_strcmp(cmd, "asp") == 0) 6260281806Srpaulo return p2p_ctrl_service_del_asp(wpa_s, pos); 6261252726Srpaulo wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 6262252726Srpaulo return -1; 6263252726Srpaulo} 6264252726Srpaulo 6265252726Srpaulo 6266281806Srpaulostatic int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd) 6267281806Srpaulo{ 6268281806Srpaulo char *pos; 6269281806Srpaulo 6270281806Srpaulo pos = os_strchr(cmd, ' '); 6271281806Srpaulo if (pos == NULL) 6272281806Srpaulo return -1; 6273281806Srpaulo *pos++ = '\0'; 6274281806Srpaulo 6275281806Srpaulo if (os_strcmp(cmd, "asp") == 0) 6276281806Srpaulo return p2p_ctrl_service_add_asp(wpa_s, 1, pos); 6277281806Srpaulo 6278281806Srpaulo wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 6279281806Srpaulo return -1; 6280281806Srpaulo} 6281281806Srpaulo 6282281806Srpaulo 6283252726Srpaulostatic int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd) 6284252726Srpaulo{ 6285252726Srpaulo u8 addr[ETH_ALEN]; 6286252726Srpaulo 6287252726Srpaulo /* <addr> */ 6288252726Srpaulo 6289252726Srpaulo if (hwaddr_aton(cmd, addr)) 6290252726Srpaulo return -1; 6291252726Srpaulo 6292252726Srpaulo return wpas_p2p_reject(wpa_s, addr); 6293252726Srpaulo} 6294252726Srpaulo 6295252726Srpaulo 6296252726Srpaulostatic int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) 6297252726Srpaulo{ 6298252726Srpaulo char *pos; 6299252726Srpaulo int id; 6300252726Srpaulo struct wpa_ssid *ssid; 6301252726Srpaulo u8 *_peer = NULL, peer[ETH_ALEN]; 6302281806Srpaulo int freq = 0, pref_freq = 0; 6303346981Scy int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0; 6304252726Srpaulo 6305252726Srpaulo id = atoi(cmd); 6306252726Srpaulo pos = os_strstr(cmd, " peer="); 6307252726Srpaulo if (pos) { 6308252726Srpaulo pos += 6; 6309252726Srpaulo if (hwaddr_aton(pos, peer)) 6310252726Srpaulo return -1; 6311252726Srpaulo _peer = peer; 6312252726Srpaulo } 6313252726Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 6314252726Srpaulo if (ssid == NULL || ssid->disabled != 2) { 6315252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 6316252726Srpaulo "for persistent P2P group", 6317252726Srpaulo id); 6318252726Srpaulo return -1; 6319252726Srpaulo } 6320252726Srpaulo 6321252726Srpaulo pos = os_strstr(cmd, " freq="); 6322252726Srpaulo if (pos) { 6323252726Srpaulo pos += 6; 6324252726Srpaulo freq = atoi(pos); 6325252726Srpaulo if (freq <= 0) 6326252726Srpaulo return -1; 6327252726Srpaulo } 6328252726Srpaulo 6329281806Srpaulo pos = os_strstr(cmd, " pref="); 6330281806Srpaulo if (pos) { 6331281806Srpaulo pos += 6; 6332281806Srpaulo pref_freq = atoi(pos); 6333281806Srpaulo if (pref_freq <= 0) 6334281806Srpaulo return -1; 6335281806Srpaulo } 6336252726Srpaulo 6337281806Srpaulo vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; 6338281806Srpaulo ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || 6339281806Srpaulo vht; 6340346981Scy he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; 6341281806Srpaulo 6342337817Scy pos = os_strstr(cmd, "freq2="); 6343337817Scy if (pos) 6344337817Scy freq2 = atoi(pos + 6); 6345337817Scy 6346337817Scy pos = os_strstr(cmd, " max_oper_chwidth="); 6347337817Scy if (pos) 6348337817Scy chwidth = atoi(pos + 18); 6349337817Scy 6350337817Scy max_oper_chwidth = parse_freq(chwidth, freq2); 6351337817Scy if (max_oper_chwidth < 0) 6352337817Scy return -1; 6353337817Scy 6354337817Scy return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, 6355346981Scy max_oper_chwidth, pref_freq, he); 6356252726Srpaulo} 6357252726Srpaulo 6358252726Srpaulo 6359252726Srpaulostatic int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) 6360252726Srpaulo{ 6361252726Srpaulo char *pos; 6362252726Srpaulo u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; 6363252726Srpaulo 6364252726Srpaulo pos = os_strstr(cmd, " peer="); 6365252726Srpaulo if (!pos) 6366252726Srpaulo return -1; 6367252726Srpaulo 6368252726Srpaulo *pos = '\0'; 6369252726Srpaulo pos += 6; 6370252726Srpaulo if (hwaddr_aton(pos, peer)) { 6371252726Srpaulo wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); 6372252726Srpaulo return -1; 6373252726Srpaulo } 6374252726Srpaulo 6375252726Srpaulo pos = os_strstr(pos, " go_dev_addr="); 6376252726Srpaulo if (pos) { 6377252726Srpaulo pos += 13; 6378252726Srpaulo if (hwaddr_aton(pos, go_dev_addr)) { 6379252726Srpaulo wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", 6380252726Srpaulo pos); 6381252726Srpaulo return -1; 6382252726Srpaulo } 6383252726Srpaulo go_dev = go_dev_addr; 6384252726Srpaulo } 6385252726Srpaulo 6386252726Srpaulo return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); 6387252726Srpaulo} 6388252726Srpaulo 6389252726Srpaulo 6390252726Srpaulostatic int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) 6391252726Srpaulo{ 6392252726Srpaulo if (os_strncmp(cmd, "persistent=", 11) == 0) 6393252726Srpaulo return p2p_ctrl_invite_persistent(wpa_s, cmd + 11); 6394252726Srpaulo if (os_strncmp(cmd, "group=", 6) == 0) 6395252726Srpaulo return p2p_ctrl_invite_group(wpa_s, cmd + 6); 6396252726Srpaulo 6397252726Srpaulo return -1; 6398252726Srpaulo} 6399252726Srpaulo 6400252726Srpaulo 6401252726Srpaulostatic int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, 6402337817Scy int id, int freq, int vht_center_freq2, 6403346981Scy int ht40, int vht, int vht_chwidth, 6404346981Scy int he) 6405252726Srpaulo{ 6406252726Srpaulo struct wpa_ssid *ssid; 6407252726Srpaulo 6408252726Srpaulo ssid = wpa_config_get_network(wpa_s->conf, id); 6409252726Srpaulo if (ssid == NULL || ssid->disabled != 2) { 6410252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 6411252726Srpaulo "for persistent P2P group", 6412252726Srpaulo id); 6413252726Srpaulo return -1; 6414252726Srpaulo } 6415252726Srpaulo 6416337817Scy return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 6417337817Scy vht_center_freq2, 0, ht40, vht, 6418346981Scy vht_chwidth, he, NULL, 0, 0); 6419252726Srpaulo} 6420252726Srpaulo 6421252726Srpaulo 6422252726Srpaulostatic int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) 6423252726Srpaulo{ 6424289549Srpaulo int freq = 0, persistent = 0, group_id = -1; 6425289549Srpaulo int vht = wpa_s->conf->p2p_go_vht; 6426289549Srpaulo int ht40 = wpa_s->conf->p2p_go_ht40 || vht; 6427346981Scy int he = wpa_s->conf->p2p_go_he; 6428337817Scy int max_oper_chwidth, chwidth = 0, freq2 = 0; 6429289549Srpaulo char *token, *context = NULL; 6430346981Scy#ifdef CONFIG_ACS 6431346981Scy int acs = 0; 6432346981Scy#endif /* CONFIG_ACS */ 6433252726Srpaulo 6434289549Srpaulo while ((token = str_token(cmd, " ", &context))) { 6435346981Scy if (sscanf(token, "freq2=%d", &freq2) == 1 || 6436337817Scy sscanf(token, "persistent=%d", &group_id) == 1 || 6437337817Scy sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) { 6438289549Srpaulo continue; 6439346981Scy#ifdef CONFIG_ACS 6440346981Scy } else if (os_strcmp(token, "freq=acs") == 0) { 6441346981Scy acs = 1; 6442346981Scy#endif /* CONFIG_ACS */ 6443346981Scy } else if (sscanf(token, "freq=%d", &freq) == 1) { 6444346981Scy continue; 6445289549Srpaulo } else if (os_strcmp(token, "ht40") == 0) { 6446289549Srpaulo ht40 = 1; 6447289549Srpaulo } else if (os_strcmp(token, "vht") == 0) { 6448289549Srpaulo vht = 1; 6449289549Srpaulo ht40 = 1; 6450346981Scy } else if (os_strcmp(token, "he") == 0) { 6451346981Scy he = 1; 6452289549Srpaulo } else if (os_strcmp(token, "persistent") == 0) { 6453289549Srpaulo persistent = 1; 6454289549Srpaulo } else { 6455289549Srpaulo wpa_printf(MSG_DEBUG, 6456289549Srpaulo "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'", 6457289549Srpaulo token); 6458289549Srpaulo return -1; 6459289549Srpaulo } 6460289549Srpaulo } 6461252726Srpaulo 6462346981Scy#ifdef CONFIG_ACS 6463346981Scy if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) && 6464346981Scy (acs || freq == 2 || freq == 5)) { 6465346981Scy if (freq == 2 && wpa_s->best_24_freq <= 0) { 6466346981Scy wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G; 6467346981Scy wpa_s->p2p_go_do_acs = 1; 6468346981Scy freq = 0; 6469346981Scy } else if (freq == 5 && wpa_s->best_5_freq <= 0) { 6470346981Scy wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A; 6471346981Scy wpa_s->p2p_go_do_acs = 1; 6472346981Scy freq = 0; 6473346981Scy } else { 6474346981Scy wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY; 6475346981Scy wpa_s->p2p_go_do_acs = 1; 6476346981Scy } 6477346981Scy } else { 6478346981Scy wpa_s->p2p_go_do_acs = 0; 6479346981Scy } 6480346981Scy#endif /* CONFIG_ACS */ 6481346981Scy 6482337817Scy max_oper_chwidth = parse_freq(chwidth, freq2); 6483337817Scy if (max_oper_chwidth < 0) 6484337817Scy return -1; 6485337817Scy 6486289549Srpaulo if (group_id >= 0) 6487289549Srpaulo return p2p_ctrl_group_add_persistent(wpa_s, group_id, 6488337817Scy freq, freq2, ht40, vht, 6489346981Scy max_oper_chwidth, he); 6490252726Srpaulo 6491337817Scy return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, 6492346981Scy max_oper_chwidth, he); 6493252726Srpaulo} 6494252726Srpaulo 6495252726Srpaulo 6496337817Scystatic int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, 6497337817Scy char *buf, size_t buflen) 6498337817Scy{ 6499337817Scy u8 dev_addr[ETH_ALEN]; 6500337817Scy struct wpa_ssid *ssid; 6501337817Scy int res; 6502337817Scy const u8 *iaddr; 6503337817Scy 6504337817Scy ssid = wpa_s->current_ssid; 6505337817Scy if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO || 6506337817Scy hwaddr_aton(cmd, dev_addr)) 6507337817Scy return -1; 6508337817Scy 6509337817Scy iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr); 6510337817Scy if (!iaddr) 6511337817Scy return -1; 6512337817Scy res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr)); 6513337817Scy if (os_snprintf_error(buflen, res)) 6514337817Scy return -1; 6515337817Scy return res; 6516337817Scy} 6517337817Scy 6518337817Scy 6519346981Scystatic int wpas_find_p2p_dev_addr_bss(struct wpa_global *global, 6520346981Scy const u8 *p2p_dev_addr) 6521346981Scy{ 6522346981Scy struct wpa_supplicant *wpa_s; 6523346981Scy 6524346981Scy for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 6525346981Scy if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr)) 6526346981Scy return 1; 6527346981Scy } 6528346981Scy 6529346981Scy return 0; 6530346981Scy} 6531346981Scy 6532346981Scy 6533252726Srpaulostatic int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, 6534252726Srpaulo char *buf, size_t buflen) 6535252726Srpaulo{ 6536346981Scy u8 addr[ETH_ALEN], *addr_ptr, group_capab; 6537252726Srpaulo int next, res; 6538252726Srpaulo const struct p2p_peer_info *info; 6539252726Srpaulo char *pos, *end; 6540252726Srpaulo char devtype[WPS_DEV_TYPE_BUFSIZE]; 6541252726Srpaulo struct wpa_ssid *ssid; 6542252726Srpaulo size_t i; 6543252726Srpaulo 6544252726Srpaulo if (!wpa_s->global->p2p) 6545252726Srpaulo return -1; 6546252726Srpaulo 6547252726Srpaulo if (os_strcmp(cmd, "FIRST") == 0) { 6548252726Srpaulo addr_ptr = NULL; 6549252726Srpaulo next = 0; 6550252726Srpaulo } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { 6551252726Srpaulo if (hwaddr_aton(cmd + 5, addr) < 0) 6552252726Srpaulo return -1; 6553252726Srpaulo addr_ptr = addr; 6554252726Srpaulo next = 1; 6555252726Srpaulo } else { 6556252726Srpaulo if (hwaddr_aton(cmd, addr) < 0) 6557252726Srpaulo return -1; 6558252726Srpaulo addr_ptr = addr; 6559252726Srpaulo next = 0; 6560252726Srpaulo } 6561252726Srpaulo 6562252726Srpaulo info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next); 6563252726Srpaulo if (info == NULL) 6564252726Srpaulo return -1; 6565346981Scy group_capab = info->group_capab; 6566252726Srpaulo 6567346981Scy if (group_capab && 6568346981Scy !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) { 6569346981Scy wpa_printf(MSG_DEBUG, 6570346981Scy "P2P: Could not find any BSS with p2p_dev_addr " 6571346981Scy MACSTR ", hence override group_capab from 0x%x to 0", 6572346981Scy MAC2STR(info->p2p_device_addr), group_capab); 6573346981Scy group_capab = 0; 6574346981Scy } 6575346981Scy 6576252726Srpaulo pos = buf; 6577252726Srpaulo end = buf + buflen; 6578252726Srpaulo 6579252726Srpaulo res = os_snprintf(pos, end - pos, MACSTR "\n" 6580252726Srpaulo "pri_dev_type=%s\n" 6581252726Srpaulo "device_name=%s\n" 6582252726Srpaulo "manufacturer=%s\n" 6583252726Srpaulo "model_name=%s\n" 6584252726Srpaulo "model_number=%s\n" 6585252726Srpaulo "serial_number=%s\n" 6586252726Srpaulo "config_methods=0x%x\n" 6587252726Srpaulo "dev_capab=0x%x\n" 6588252726Srpaulo "group_capab=0x%x\n" 6589252726Srpaulo "level=%d\n", 6590252726Srpaulo MAC2STR(info->p2p_device_addr), 6591252726Srpaulo wps_dev_type_bin2str(info->pri_dev_type, 6592252726Srpaulo devtype, sizeof(devtype)), 6593252726Srpaulo info->device_name, 6594252726Srpaulo info->manufacturer, 6595252726Srpaulo info->model_name, 6596252726Srpaulo info->model_number, 6597252726Srpaulo info->serial_number, 6598252726Srpaulo info->config_methods, 6599252726Srpaulo info->dev_capab, 6600346981Scy group_capab, 6601252726Srpaulo info->level); 6602281806Srpaulo if (os_snprintf_error(end - pos, res)) 6603252726Srpaulo return pos - buf; 6604252726Srpaulo pos += res; 6605252726Srpaulo 6606252726Srpaulo for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++) 6607252726Srpaulo { 6608252726Srpaulo const u8 *t; 6609252726Srpaulo t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN]; 6610252726Srpaulo res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n", 6611252726Srpaulo wps_dev_type_bin2str(t, devtype, 6612252726Srpaulo sizeof(devtype))); 6613281806Srpaulo if (os_snprintf_error(end - pos, res)) 6614252726Srpaulo return pos - buf; 6615252726Srpaulo pos += res; 6616252726Srpaulo } 6617252726Srpaulo 6618252726Srpaulo ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0); 6619252726Srpaulo if (ssid) { 6620252726Srpaulo res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id); 6621281806Srpaulo if (os_snprintf_error(end - pos, res)) 6622252726Srpaulo return pos - buf; 6623252726Srpaulo pos += res; 6624252726Srpaulo } 6625252726Srpaulo 6626252726Srpaulo res = p2p_get_peer_info_txt(info, pos, end - pos); 6627252726Srpaulo if (res < 0) 6628252726Srpaulo return pos - buf; 6629252726Srpaulo pos += res; 6630252726Srpaulo 6631281806Srpaulo if (info->vendor_elems) { 6632281806Srpaulo res = os_snprintf(pos, end - pos, "vendor_elems="); 6633281806Srpaulo if (os_snprintf_error(end - pos, res)) 6634281806Srpaulo return pos - buf; 6635281806Srpaulo pos += res; 6636281806Srpaulo 6637281806Srpaulo pos += wpa_snprintf_hex(pos, end - pos, 6638281806Srpaulo wpabuf_head(info->vendor_elems), 6639281806Srpaulo wpabuf_len(info->vendor_elems)); 6640281806Srpaulo 6641281806Srpaulo res = os_snprintf(pos, end - pos, "\n"); 6642281806Srpaulo if (os_snprintf_error(end - pos, res)) 6643281806Srpaulo return pos - buf; 6644281806Srpaulo pos += res; 6645281806Srpaulo } 6646281806Srpaulo 6647252726Srpaulo return pos - buf; 6648252726Srpaulo} 6649252726Srpaulo 6650252726Srpaulo 6651252726Srpaulostatic int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s, 6652252726Srpaulo const char *param) 6653252726Srpaulo{ 6654281806Srpaulo unsigned int i; 6655252726Srpaulo 6656252726Srpaulo if (wpa_s->global->p2p == NULL) 6657252726Srpaulo return -1; 6658252726Srpaulo 6659281806Srpaulo if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0) 6660281806Srpaulo return -1; 6661252726Srpaulo 6662281806Srpaulo for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) { 6663281806Srpaulo struct wpa_freq_range *freq; 6664281806Srpaulo freq = &wpa_s->global->p2p_disallow_freq.range[i]; 6665252726Srpaulo wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u", 6666281806Srpaulo freq->min, freq->max); 6667252726Srpaulo } 6668252726Srpaulo 6669289549Srpaulo wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW); 6670252726Srpaulo return 0; 6671252726Srpaulo} 6672252726Srpaulo 6673252726Srpaulo 6674252726Srpaulostatic int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) 6675252726Srpaulo{ 6676252726Srpaulo char *param; 6677252726Srpaulo 6678252726Srpaulo if (wpa_s->global->p2p == NULL) 6679252726Srpaulo return -1; 6680252726Srpaulo 6681252726Srpaulo param = os_strchr(cmd, ' '); 6682252726Srpaulo if (param == NULL) 6683252726Srpaulo return -1; 6684252726Srpaulo *param++ = '\0'; 6685252726Srpaulo 6686252726Srpaulo if (os_strcmp(cmd, "discoverability") == 0) { 6687252726Srpaulo p2p_set_client_discoverability(wpa_s->global->p2p, 6688252726Srpaulo atoi(param)); 6689252726Srpaulo return 0; 6690252726Srpaulo } 6691252726Srpaulo 6692252726Srpaulo if (os_strcmp(cmd, "managed") == 0) { 6693252726Srpaulo p2p_set_managed_oper(wpa_s->global->p2p, atoi(param)); 6694252726Srpaulo return 0; 6695252726Srpaulo } 6696252726Srpaulo 6697252726Srpaulo if (os_strcmp(cmd, "listen_channel") == 0) { 6698337817Scy char *pos; 6699337817Scy u8 channel, op_class; 6700337817Scy 6701337817Scy channel = atoi(param); 6702337817Scy pos = os_strchr(param, ' '); 6703337817Scy op_class = pos ? atoi(pos) : 81; 6704337817Scy 6705337817Scy return p2p_set_listen_channel(wpa_s->global->p2p, op_class, 6706337817Scy channel, 1); 6707252726Srpaulo } 6708252726Srpaulo 6709252726Srpaulo if (os_strcmp(cmd, "ssid_postfix") == 0) { 6710252726Srpaulo return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param, 6711252726Srpaulo os_strlen(param)); 6712252726Srpaulo } 6713252726Srpaulo 6714252726Srpaulo if (os_strcmp(cmd, "noa") == 0) { 6715252726Srpaulo char *pos; 6716252726Srpaulo int count, start, duration; 6717252726Srpaulo /* GO NoA parameters: count,start_offset(ms),duration(ms) */ 6718252726Srpaulo count = atoi(param); 6719252726Srpaulo pos = os_strchr(param, ','); 6720252726Srpaulo if (pos == NULL) 6721252726Srpaulo return -1; 6722252726Srpaulo pos++; 6723252726Srpaulo start = atoi(pos); 6724252726Srpaulo pos = os_strchr(pos, ','); 6725252726Srpaulo if (pos == NULL) 6726252726Srpaulo return -1; 6727252726Srpaulo pos++; 6728252726Srpaulo duration = atoi(pos); 6729252726Srpaulo if (count < 0 || count > 255 || start < 0 || duration < 0) 6730252726Srpaulo return -1; 6731252726Srpaulo if (count == 0 && duration > 0) 6732252726Srpaulo return -1; 6733252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " 6734252726Srpaulo "start=%d duration=%d", count, start, duration); 6735252726Srpaulo return wpas_p2p_set_noa(wpa_s, count, start, duration); 6736252726Srpaulo } 6737252726Srpaulo 6738252726Srpaulo if (os_strcmp(cmd, "ps") == 0) 6739252726Srpaulo return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1); 6740252726Srpaulo 6741252726Srpaulo if (os_strcmp(cmd, "oppps") == 0) 6742252726Srpaulo return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1); 6743252726Srpaulo 6744252726Srpaulo if (os_strcmp(cmd, "ctwindow") == 0) 6745252726Srpaulo return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param)); 6746252726Srpaulo 6747252726Srpaulo if (os_strcmp(cmd, "disabled") == 0) { 6748252726Srpaulo wpa_s->global->p2p_disabled = atoi(param); 6749252726Srpaulo wpa_printf(MSG_DEBUG, "P2P functionality %s", 6750252726Srpaulo wpa_s->global->p2p_disabled ? 6751252726Srpaulo "disabled" : "enabled"); 6752252726Srpaulo if (wpa_s->global->p2p_disabled) { 6753252726Srpaulo wpas_p2p_stop_find(wpa_s); 6754252726Srpaulo os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); 6755252726Srpaulo p2p_flush(wpa_s->global->p2p); 6756252726Srpaulo } 6757252726Srpaulo return 0; 6758252726Srpaulo } 6759252726Srpaulo 6760252726Srpaulo if (os_strcmp(cmd, "conc_pref") == 0) { 6761252726Srpaulo if (os_strcmp(param, "sta") == 0) 6762252726Srpaulo wpa_s->global->conc_pref = WPA_CONC_PREF_STA; 6763252726Srpaulo else if (os_strcmp(param, "p2p") == 0) 6764252726Srpaulo wpa_s->global->conc_pref = WPA_CONC_PREF_P2P; 6765252726Srpaulo else { 6766252726Srpaulo wpa_printf(MSG_INFO, "Invalid conc_pref value"); 6767252726Srpaulo return -1; 6768252726Srpaulo } 6769252726Srpaulo wpa_printf(MSG_DEBUG, "Single channel concurrency preference: " 6770252726Srpaulo "%s", param); 6771252726Srpaulo return 0; 6772252726Srpaulo } 6773252726Srpaulo 6774252726Srpaulo if (os_strcmp(cmd, "force_long_sd") == 0) { 6775252726Srpaulo wpa_s->force_long_sd = atoi(param); 6776252726Srpaulo return 0; 6777252726Srpaulo } 6778252726Srpaulo 6779252726Srpaulo if (os_strcmp(cmd, "peer_filter") == 0) { 6780252726Srpaulo u8 addr[ETH_ALEN]; 6781252726Srpaulo if (hwaddr_aton(param, addr)) 6782252726Srpaulo return -1; 6783252726Srpaulo p2p_set_peer_filter(wpa_s->global->p2p, addr); 6784252726Srpaulo return 0; 6785252726Srpaulo } 6786252726Srpaulo 6787252726Srpaulo if (os_strcmp(cmd, "cross_connect") == 0) 6788252726Srpaulo return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); 6789252726Srpaulo 6790252726Srpaulo if (os_strcmp(cmd, "go_apsd") == 0) { 6791252726Srpaulo if (os_strcmp(param, "disable") == 0) 6792252726Srpaulo wpa_s->set_ap_uapsd = 0; 6793252726Srpaulo else { 6794252726Srpaulo wpa_s->set_ap_uapsd = 1; 6795252726Srpaulo wpa_s->ap_uapsd = atoi(param); 6796252726Srpaulo } 6797252726Srpaulo return 0; 6798252726Srpaulo } 6799252726Srpaulo 6800252726Srpaulo if (os_strcmp(cmd, "client_apsd") == 0) { 6801252726Srpaulo if (os_strcmp(param, "disable") == 0) 6802252726Srpaulo wpa_s->set_sta_uapsd = 0; 6803252726Srpaulo else { 6804252726Srpaulo int be, bk, vi, vo; 6805252726Srpaulo char *pos; 6806252726Srpaulo /* format: BE,BK,VI,VO;max SP Length */ 6807252726Srpaulo be = atoi(param); 6808252726Srpaulo pos = os_strchr(param, ','); 6809252726Srpaulo if (pos == NULL) 6810252726Srpaulo return -1; 6811252726Srpaulo pos++; 6812252726Srpaulo bk = atoi(pos); 6813252726Srpaulo pos = os_strchr(pos, ','); 6814252726Srpaulo if (pos == NULL) 6815252726Srpaulo return -1; 6816252726Srpaulo pos++; 6817252726Srpaulo vi = atoi(pos); 6818252726Srpaulo pos = os_strchr(pos, ','); 6819252726Srpaulo if (pos == NULL) 6820252726Srpaulo return -1; 6821252726Srpaulo pos++; 6822252726Srpaulo vo = atoi(pos); 6823252726Srpaulo /* ignore max SP Length for now */ 6824252726Srpaulo 6825252726Srpaulo wpa_s->set_sta_uapsd = 1; 6826252726Srpaulo wpa_s->sta_uapsd = 0; 6827252726Srpaulo if (be) 6828252726Srpaulo wpa_s->sta_uapsd |= BIT(0); 6829252726Srpaulo if (bk) 6830252726Srpaulo wpa_s->sta_uapsd |= BIT(1); 6831252726Srpaulo if (vi) 6832252726Srpaulo wpa_s->sta_uapsd |= BIT(2); 6833252726Srpaulo if (vo) 6834252726Srpaulo wpa_s->sta_uapsd |= BIT(3); 6835252726Srpaulo } 6836252726Srpaulo return 0; 6837252726Srpaulo } 6838252726Srpaulo 6839252726Srpaulo if (os_strcmp(cmd, "disallow_freq") == 0) 6840252726Srpaulo return p2p_ctrl_disallow_freq(wpa_s, param); 6841252726Srpaulo 6842252726Srpaulo if (os_strcmp(cmd, "disc_int") == 0) { 6843252726Srpaulo int min_disc_int, max_disc_int, max_disc_tu; 6844252726Srpaulo char *pos; 6845252726Srpaulo 6846252726Srpaulo pos = param; 6847252726Srpaulo 6848252726Srpaulo min_disc_int = atoi(pos); 6849252726Srpaulo pos = os_strchr(pos, ' '); 6850252726Srpaulo if (pos == NULL) 6851252726Srpaulo return -1; 6852252726Srpaulo *pos++ = '\0'; 6853252726Srpaulo 6854252726Srpaulo max_disc_int = atoi(pos); 6855252726Srpaulo pos = os_strchr(pos, ' '); 6856252726Srpaulo if (pos == NULL) 6857252726Srpaulo return -1; 6858252726Srpaulo *pos++ = '\0'; 6859252726Srpaulo 6860252726Srpaulo max_disc_tu = atoi(pos); 6861252726Srpaulo 6862252726Srpaulo return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int, 6863252726Srpaulo max_disc_int, max_disc_tu); 6864252726Srpaulo } 6865252726Srpaulo 6866281806Srpaulo if (os_strcmp(cmd, "per_sta_psk") == 0) { 6867281806Srpaulo wpa_s->global->p2p_per_sta_psk = !!atoi(param); 6868281806Srpaulo return 0; 6869281806Srpaulo } 6870281806Srpaulo 6871281806Srpaulo#ifdef CONFIG_WPS_NFC 6872281806Srpaulo if (os_strcmp(cmd, "nfc_tag") == 0) 6873281806Srpaulo return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param)); 6874281806Srpaulo#endif /* CONFIG_WPS_NFC */ 6875281806Srpaulo 6876281806Srpaulo if (os_strcmp(cmd, "disable_ip_addr_req") == 0) { 6877281806Srpaulo wpa_s->p2p_disable_ip_addr_req = !!atoi(param); 6878281806Srpaulo return 0; 6879281806Srpaulo } 6880281806Srpaulo 6881346981Scy if (os_strcmp(cmd, "override_pref_op_chan") == 0) { 6882346981Scy int op_class, chan; 6883346981Scy 6884346981Scy op_class = atoi(param); 6885346981Scy param = os_strchr(param, ':'); 6886346981Scy if (!param) 6887346981Scy return -1; 6888346981Scy param++; 6889346981Scy chan = atoi(param); 6890346981Scy p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class, 6891346981Scy chan); 6892346981Scy return 0; 6893346981Scy } 6894346981Scy 6895252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", 6896252726Srpaulo cmd); 6897252726Srpaulo 6898252726Srpaulo return -1; 6899252726Srpaulo} 6900252726Srpaulo 6901252726Srpaulo 6902281806Srpaulostatic void p2p_ctrl_flush(struct wpa_supplicant *wpa_s) 6903281806Srpaulo{ 6904281806Srpaulo os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); 6905281806Srpaulo wpa_s->force_long_sd = 0; 6906346981Scy 6907346981Scy#ifdef CONFIG_TESTING_OPTIONS 6908346981Scy os_free(wpa_s->get_pref_freq_list_override); 6909346981Scy wpa_s->get_pref_freq_list_override = NULL; 6910346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 6911346981Scy 6912281806Srpaulo wpas_p2p_stop_find(wpa_s); 6913289549Srpaulo wpa_s->parent->p2ps_method_config_any = 0; 6914281806Srpaulo if (wpa_s->global->p2p) 6915281806Srpaulo p2p_flush(wpa_s->global->p2p); 6916281806Srpaulo} 6917281806Srpaulo 6918281806Srpaulo 6919252726Srpaulostatic int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd) 6920252726Srpaulo{ 6921252726Srpaulo char *pos, *pos2; 6922252726Srpaulo unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; 6923252726Srpaulo 6924252726Srpaulo if (cmd[0]) { 6925252726Srpaulo pos = os_strchr(cmd, ' '); 6926252726Srpaulo if (pos == NULL) 6927252726Srpaulo return -1; 6928252726Srpaulo *pos++ = '\0'; 6929252726Srpaulo dur1 = atoi(cmd); 6930252726Srpaulo 6931252726Srpaulo pos2 = os_strchr(pos, ' '); 6932252726Srpaulo if (pos2) 6933252726Srpaulo *pos2++ = '\0'; 6934252726Srpaulo int1 = atoi(pos); 6935252726Srpaulo } else 6936252726Srpaulo pos2 = NULL; 6937252726Srpaulo 6938252726Srpaulo if (pos2) { 6939252726Srpaulo pos = os_strchr(pos2, ' '); 6940252726Srpaulo if (pos == NULL) 6941252726Srpaulo return -1; 6942252726Srpaulo *pos++ = '\0'; 6943252726Srpaulo dur2 = atoi(pos2); 6944252726Srpaulo int2 = atoi(pos); 6945252726Srpaulo } 6946252726Srpaulo 6947252726Srpaulo return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2); 6948252726Srpaulo} 6949252726Srpaulo 6950252726Srpaulo 6951252726Srpaulostatic int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd) 6952252726Srpaulo{ 6953252726Srpaulo char *pos; 6954252726Srpaulo unsigned int period = 0, interval = 0; 6955252726Srpaulo 6956252726Srpaulo if (cmd[0]) { 6957252726Srpaulo pos = os_strchr(cmd, ' '); 6958252726Srpaulo if (pos == NULL) 6959252726Srpaulo return -1; 6960252726Srpaulo *pos++ = '\0'; 6961252726Srpaulo period = atoi(cmd); 6962252726Srpaulo interval = atoi(pos); 6963252726Srpaulo } 6964252726Srpaulo 6965252726Srpaulo return wpas_p2p_ext_listen(wpa_s, period, interval); 6966252726Srpaulo} 6967252726Srpaulo 6968281806Srpaulo 6969281806Srpaulostatic int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) 6970281806Srpaulo{ 6971281806Srpaulo const char *pos; 6972281806Srpaulo u8 peer[ETH_ALEN]; 6973281806Srpaulo int iface_addr = 0; 6974281806Srpaulo 6975281806Srpaulo pos = cmd; 6976281806Srpaulo if (os_strncmp(pos, "iface=", 6) == 0) { 6977281806Srpaulo iface_addr = 1; 6978281806Srpaulo pos += 6; 6979281806Srpaulo } 6980281806Srpaulo if (hwaddr_aton(pos, peer)) 6981281806Srpaulo return -1; 6982281806Srpaulo 6983281806Srpaulo wpas_p2p_remove_client(wpa_s, peer, iface_addr); 6984281806Srpaulo return 0; 6985281806Srpaulo} 6986281806Srpaulo 6987337817Scy 6988337817Scystatic int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd) 6989337817Scy{ 6990337817Scy int freq = 0, period = 0, interval = 0, count = 0; 6991337817Scy 6992337817Scy if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4) 6993337817Scy { 6994337817Scy wpa_printf(MSG_DEBUG, 6995337817Scy "CTRL: Invalid P2P LO Start parameter: '%s'", cmd); 6996337817Scy return -1; 6997337817Scy } 6998337817Scy 6999337817Scy return wpas_p2p_lo_start(wpa_s, freq, period, interval, count); 7000337817Scy} 7001337817Scy 7002252726Srpaulo#endif /* CONFIG_P2P */ 7003252726Srpaulo 7004252726Srpaulo 7005281806Srpaulostatic int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val) 7006281806Srpaulo{ 7007281806Srpaulo struct wpa_freq_range_list ranges; 7008281806Srpaulo int *freqs = NULL; 7009281806Srpaulo struct hostapd_hw_modes *mode; 7010281806Srpaulo u16 i; 7011281806Srpaulo 7012281806Srpaulo if (wpa_s->hw.modes == NULL) 7013281806Srpaulo return NULL; 7014281806Srpaulo 7015281806Srpaulo os_memset(&ranges, 0, sizeof(ranges)); 7016281806Srpaulo if (freq_range_list_parse(&ranges, val) < 0) 7017281806Srpaulo return NULL; 7018281806Srpaulo 7019281806Srpaulo for (i = 0; i < wpa_s->hw.num_modes; i++) { 7020281806Srpaulo int j; 7021281806Srpaulo 7022281806Srpaulo mode = &wpa_s->hw.modes[i]; 7023281806Srpaulo for (j = 0; j < mode->num_channels; j++) { 7024281806Srpaulo unsigned int freq; 7025281806Srpaulo 7026281806Srpaulo if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) 7027281806Srpaulo continue; 7028281806Srpaulo 7029281806Srpaulo freq = mode->channels[j].freq; 7030281806Srpaulo if (!freq_range_list_includes(&ranges, freq)) 7031281806Srpaulo continue; 7032281806Srpaulo 7033281806Srpaulo int_array_add_unique(&freqs, freq); 7034281806Srpaulo } 7035281806Srpaulo } 7036281806Srpaulo 7037281806Srpaulo os_free(ranges.range); 7038281806Srpaulo return freqs; 7039281806Srpaulo} 7040281806Srpaulo 7041281806Srpaulo 7042252726Srpaulo#ifdef CONFIG_INTERWORKING 7043281806Srpaulo 7044281806Srpaulostatic int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) 7045252726Srpaulo{ 7046281806Srpaulo int auto_sel = 0; 7047281806Srpaulo int *freqs = NULL; 7048281806Srpaulo 7049281806Srpaulo if (param) { 7050281806Srpaulo char *pos; 7051281806Srpaulo 7052281806Srpaulo auto_sel = os_strstr(param, "auto") != NULL; 7053281806Srpaulo 7054281806Srpaulo pos = os_strstr(param, "freq="); 7055281806Srpaulo if (pos) { 7056281806Srpaulo freqs = freq_range_to_channel_list(wpa_s, pos + 5); 7057281806Srpaulo if (freqs == NULL) 7058281806Srpaulo return -1; 7059281806Srpaulo } 7060281806Srpaulo 7061281806Srpaulo } 7062281806Srpaulo 7063281806Srpaulo return interworking_select(wpa_s, auto_sel, freqs); 7064281806Srpaulo} 7065281806Srpaulo 7066281806Srpaulo 7067281806Srpaulostatic int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst, 7068281806Srpaulo int only_add) 7069281806Srpaulo{ 7070252726Srpaulo u8 bssid[ETH_ALEN]; 7071252726Srpaulo struct wpa_bss *bss; 7072252726Srpaulo 7073252726Srpaulo if (hwaddr_aton(dst, bssid)) { 7074252726Srpaulo wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst); 7075252726Srpaulo return -1; 7076252726Srpaulo } 7077252726Srpaulo 7078252726Srpaulo bss = wpa_bss_get_bssid(wpa_s, bssid); 7079252726Srpaulo if (bss == NULL) { 7080252726Srpaulo wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR, 7081252726Srpaulo MAC2STR(bssid)); 7082252726Srpaulo return -1; 7083252726Srpaulo } 7084252726Srpaulo 7085281806Srpaulo if (bss->ssid_len == 0) { 7086281806Srpaulo int found = 0; 7087281806Srpaulo 7088281806Srpaulo wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR 7089281806Srpaulo " does not have SSID information", MAC2STR(bssid)); 7090281806Srpaulo 7091281806Srpaulo dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, 7092281806Srpaulo list) { 7093281806Srpaulo if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && 7094281806Srpaulo bss->ssid_len > 0) { 7095281806Srpaulo found = 1; 7096281806Srpaulo break; 7097281806Srpaulo } 7098281806Srpaulo } 7099281806Srpaulo 7100281806Srpaulo if (!found) 7101281806Srpaulo return -1; 7102281806Srpaulo wpa_printf(MSG_DEBUG, 7103281806Srpaulo "Found another matching BSS entry with SSID"); 7104281806Srpaulo } 7105281806Srpaulo 7106281806Srpaulo return interworking_connect(wpa_s, bss, only_add); 7107252726Srpaulo} 7108252726Srpaulo 7109252726Srpaulo 7110252726Srpaulostatic int get_anqp(struct wpa_supplicant *wpa_s, char *dst) 7111252726Srpaulo{ 7112252726Srpaulo u8 dst_addr[ETH_ALEN]; 7113252726Srpaulo int used; 7114252726Srpaulo char *pos; 7115252726Srpaulo#define MAX_ANQP_INFO_ID 100 7116252726Srpaulo u16 id[MAX_ANQP_INFO_ID]; 7117252726Srpaulo size_t num_id = 0; 7118281806Srpaulo u32 subtypes = 0; 7119346981Scy u32 mbo_subtypes = 0; 7120252726Srpaulo 7121252726Srpaulo used = hwaddr_aton2(dst, dst_addr); 7122252726Srpaulo if (used < 0) 7123252726Srpaulo return -1; 7124252726Srpaulo pos = dst + used; 7125281806Srpaulo if (*pos == ' ') 7126281806Srpaulo pos++; 7127252726Srpaulo while (num_id < MAX_ANQP_INFO_ID) { 7128281806Srpaulo if (os_strncmp(pos, "hs20:", 5) == 0) { 7129281806Srpaulo#ifdef CONFIG_HS20 7130281806Srpaulo int num = atoi(pos + 5); 7131281806Srpaulo if (num <= 0 || num > 31) 7132281806Srpaulo return -1; 7133281806Srpaulo subtypes |= BIT(num); 7134281806Srpaulo#else /* CONFIG_HS20 */ 7135281806Srpaulo return -1; 7136281806Srpaulo#endif /* CONFIG_HS20 */ 7137337817Scy } else if (os_strncmp(pos, "mbo:", 4) == 0) { 7138337817Scy#ifdef CONFIG_MBO 7139337817Scy int num = atoi(pos + 4); 7140346981Scy 7141346981Scy if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE) 7142337817Scy return -1; 7143346981Scy mbo_subtypes |= BIT(num); 7144337817Scy#else /* CONFIG_MBO */ 7145337817Scy return -1; 7146337817Scy#endif /* CONFIG_MBO */ 7147281806Srpaulo } else { 7148281806Srpaulo id[num_id] = atoi(pos); 7149281806Srpaulo if (id[num_id]) 7150281806Srpaulo num_id++; 7151281806Srpaulo } 7152252726Srpaulo pos = os_strchr(pos + 1, ','); 7153252726Srpaulo if (pos == NULL) 7154252726Srpaulo break; 7155252726Srpaulo pos++; 7156252726Srpaulo } 7157252726Srpaulo 7158346981Scy if (num_id == 0 && !subtypes && !mbo_subtypes) 7159252726Srpaulo return -1; 7160252726Srpaulo 7161337817Scy return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, 7162346981Scy mbo_subtypes); 7163252726Srpaulo} 7164252726Srpaulo 7165252726Srpaulo 7166252726Srpaulostatic int gas_request(struct wpa_supplicant *wpa_s, char *cmd) 7167252726Srpaulo{ 7168252726Srpaulo u8 dst_addr[ETH_ALEN]; 7169252726Srpaulo struct wpabuf *advproto, *query = NULL; 7170252726Srpaulo int used, ret = -1; 7171252726Srpaulo char *pos, *end; 7172252726Srpaulo size_t len; 7173252726Srpaulo 7174252726Srpaulo used = hwaddr_aton2(cmd, dst_addr); 7175252726Srpaulo if (used < 0) 7176252726Srpaulo return -1; 7177252726Srpaulo 7178252726Srpaulo pos = cmd + used; 7179252726Srpaulo while (*pos == ' ') 7180252726Srpaulo pos++; 7181252726Srpaulo 7182252726Srpaulo /* Advertisement Protocol ID */ 7183252726Srpaulo end = os_strchr(pos, ' '); 7184252726Srpaulo if (end) 7185252726Srpaulo len = end - pos; 7186252726Srpaulo else 7187252726Srpaulo len = os_strlen(pos); 7188252726Srpaulo if (len & 0x01) 7189252726Srpaulo return -1; 7190252726Srpaulo len /= 2; 7191252726Srpaulo if (len == 0) 7192252726Srpaulo return -1; 7193252726Srpaulo advproto = wpabuf_alloc(len); 7194252726Srpaulo if (advproto == NULL) 7195252726Srpaulo return -1; 7196252726Srpaulo if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0) 7197252726Srpaulo goto fail; 7198252726Srpaulo 7199252726Srpaulo if (end) { 7200252726Srpaulo /* Optional Query Request */ 7201252726Srpaulo pos = end + 1; 7202252726Srpaulo while (*pos == ' ') 7203252726Srpaulo pos++; 7204252726Srpaulo 7205252726Srpaulo len = os_strlen(pos); 7206252726Srpaulo if (len) { 7207252726Srpaulo if (len & 0x01) 7208252726Srpaulo goto fail; 7209252726Srpaulo len /= 2; 7210252726Srpaulo if (len == 0) 7211252726Srpaulo goto fail; 7212252726Srpaulo query = wpabuf_alloc(len); 7213252726Srpaulo if (query == NULL) 7214252726Srpaulo goto fail; 7215252726Srpaulo if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0) 7216252726Srpaulo goto fail; 7217252726Srpaulo } 7218252726Srpaulo } 7219252726Srpaulo 7220252726Srpaulo ret = gas_send_request(wpa_s, dst_addr, advproto, query); 7221252726Srpaulo 7222252726Srpaulofail: 7223252726Srpaulo wpabuf_free(advproto); 7224252726Srpaulo wpabuf_free(query); 7225252726Srpaulo 7226252726Srpaulo return ret; 7227252726Srpaulo} 7228252726Srpaulo 7229252726Srpaulo 7230252726Srpaulostatic int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, 7231252726Srpaulo size_t buflen) 7232252726Srpaulo{ 7233252726Srpaulo u8 addr[ETH_ALEN]; 7234252726Srpaulo int dialog_token; 7235252726Srpaulo int used; 7236252726Srpaulo char *pos; 7237252726Srpaulo size_t resp_len, start, requested_len; 7238281806Srpaulo struct wpabuf *resp; 7239281806Srpaulo int ret; 7240252726Srpaulo 7241252726Srpaulo used = hwaddr_aton2(cmd, addr); 7242252726Srpaulo if (used < 0) 7243252726Srpaulo return -1; 7244252726Srpaulo 7245252726Srpaulo pos = cmd + used; 7246252726Srpaulo while (*pos == ' ') 7247252726Srpaulo pos++; 7248252726Srpaulo dialog_token = atoi(pos); 7249252726Srpaulo 7250281806Srpaulo if (wpa_s->last_gas_resp && 7251281806Srpaulo os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && 7252281806Srpaulo dialog_token == wpa_s->last_gas_dialog_token) 7253281806Srpaulo resp = wpa_s->last_gas_resp; 7254281806Srpaulo else if (wpa_s->prev_gas_resp && 7255281806Srpaulo os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && 7256281806Srpaulo dialog_token == wpa_s->prev_gas_dialog_token) 7257281806Srpaulo resp = wpa_s->prev_gas_resp; 7258281806Srpaulo else 7259252726Srpaulo return -1; 7260252726Srpaulo 7261281806Srpaulo resp_len = wpabuf_len(resp); 7262252726Srpaulo start = 0; 7263252726Srpaulo requested_len = resp_len; 7264252726Srpaulo 7265252726Srpaulo pos = os_strchr(pos, ' '); 7266252726Srpaulo if (pos) { 7267252726Srpaulo start = atoi(pos); 7268252726Srpaulo if (start > resp_len) 7269252726Srpaulo return os_snprintf(buf, buflen, "FAIL-Invalid range"); 7270252726Srpaulo pos = os_strchr(pos, ','); 7271252726Srpaulo if (pos == NULL) 7272252726Srpaulo return -1; 7273252726Srpaulo pos++; 7274252726Srpaulo requested_len = atoi(pos); 7275252726Srpaulo if (start + requested_len > resp_len) 7276252726Srpaulo return os_snprintf(buf, buflen, "FAIL-Invalid range"); 7277252726Srpaulo } 7278252726Srpaulo 7279252726Srpaulo if (requested_len * 2 + 1 > buflen) 7280252726Srpaulo return os_snprintf(buf, buflen, "FAIL-Too long response"); 7281252726Srpaulo 7282281806Srpaulo ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, 7283281806Srpaulo requested_len); 7284281806Srpaulo 7285281806Srpaulo if (start + requested_len == resp_len) { 7286281806Srpaulo /* 7287281806Srpaulo * Free memory by dropping the response after it has been 7288281806Srpaulo * fetched. 7289281806Srpaulo */ 7290281806Srpaulo if (resp == wpa_s->prev_gas_resp) { 7291281806Srpaulo wpabuf_free(wpa_s->prev_gas_resp); 7292281806Srpaulo wpa_s->prev_gas_resp = NULL; 7293281806Srpaulo } else { 7294281806Srpaulo wpabuf_free(wpa_s->last_gas_resp); 7295281806Srpaulo wpa_s->last_gas_resp = NULL; 7296281806Srpaulo } 7297281806Srpaulo } 7298281806Srpaulo 7299281806Srpaulo return ret; 7300252726Srpaulo} 7301252726Srpaulo#endif /* CONFIG_INTERWORKING */ 7302252726Srpaulo 7303252726Srpaulo 7304252726Srpaulo#ifdef CONFIG_HS20 7305252726Srpaulo 7306252726Srpaulostatic int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) 7307252726Srpaulo{ 7308252726Srpaulo u8 dst_addr[ETH_ALEN]; 7309252726Srpaulo int used; 7310252726Srpaulo char *pos; 7311252726Srpaulo u32 subtypes = 0; 7312252726Srpaulo 7313252726Srpaulo used = hwaddr_aton2(dst, dst_addr); 7314252726Srpaulo if (used < 0) 7315252726Srpaulo return -1; 7316252726Srpaulo pos = dst + used; 7317281806Srpaulo if (*pos == ' ') 7318281806Srpaulo pos++; 7319252726Srpaulo for (;;) { 7320252726Srpaulo int num = atoi(pos); 7321252726Srpaulo if (num <= 0 || num > 31) 7322252726Srpaulo return -1; 7323252726Srpaulo subtypes |= BIT(num); 7324252726Srpaulo pos = os_strchr(pos + 1, ','); 7325252726Srpaulo if (pos == NULL) 7326252726Srpaulo break; 7327252726Srpaulo pos++; 7328252726Srpaulo } 7329252726Srpaulo 7330252726Srpaulo if (subtypes == 0) 7331252726Srpaulo return -1; 7332252726Srpaulo 7333337817Scy return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0); 7334252726Srpaulo} 7335252726Srpaulo 7336252726Srpaulo 7337252726Srpaulostatic int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, 7338252726Srpaulo const u8 *addr, const char *realm) 7339252726Srpaulo{ 7340252726Srpaulo u8 *buf; 7341252726Srpaulo size_t rlen, len; 7342252726Srpaulo int ret; 7343252726Srpaulo 7344252726Srpaulo rlen = os_strlen(realm); 7345252726Srpaulo len = 3 + rlen; 7346252726Srpaulo buf = os_malloc(len); 7347252726Srpaulo if (buf == NULL) 7348252726Srpaulo return -1; 7349252726Srpaulo buf[0] = 1; /* NAI Home Realm Count */ 7350252726Srpaulo buf[1] = 0; /* Formatted in accordance with RFC 4282 */ 7351252726Srpaulo buf[2] = rlen; 7352252726Srpaulo os_memcpy(buf + 3, realm, rlen); 7353252726Srpaulo 7354252726Srpaulo ret = hs20_anqp_send_req(wpa_s, addr, 7355252726Srpaulo BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), 7356337817Scy buf, len, 0); 7357252726Srpaulo 7358252726Srpaulo os_free(buf); 7359252726Srpaulo 7360252726Srpaulo return ret; 7361252726Srpaulo} 7362252726Srpaulo 7363252726Srpaulo 7364252726Srpaulostatic int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, 7365252726Srpaulo char *dst) 7366252726Srpaulo{ 7367252726Srpaulo struct wpa_cred *cred = wpa_s->conf->cred; 7368252726Srpaulo u8 dst_addr[ETH_ALEN]; 7369252726Srpaulo int used; 7370252726Srpaulo u8 *buf; 7371252726Srpaulo size_t len; 7372252726Srpaulo int ret; 7373252726Srpaulo 7374252726Srpaulo used = hwaddr_aton2(dst, dst_addr); 7375252726Srpaulo if (used < 0) 7376252726Srpaulo return -1; 7377252726Srpaulo 7378252726Srpaulo while (dst[used] == ' ') 7379252726Srpaulo used++; 7380252726Srpaulo if (os_strncmp(dst + used, "realm=", 6) == 0) 7381252726Srpaulo return hs20_nai_home_realm_list(wpa_s, dst_addr, 7382252726Srpaulo dst + used + 6); 7383252726Srpaulo 7384252726Srpaulo len = os_strlen(dst + used); 7385252726Srpaulo 7386252726Srpaulo if (len == 0 && cred && cred->realm) 7387252726Srpaulo return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm); 7388252726Srpaulo 7389281806Srpaulo if (len & 1) 7390252726Srpaulo return -1; 7391252726Srpaulo len /= 2; 7392252726Srpaulo buf = os_malloc(len); 7393252726Srpaulo if (buf == NULL) 7394252726Srpaulo return -1; 7395252726Srpaulo if (hexstr2bin(dst + used, buf, len) < 0) { 7396252726Srpaulo os_free(buf); 7397252726Srpaulo return -1; 7398252726Srpaulo } 7399252726Srpaulo 7400252726Srpaulo ret = hs20_anqp_send_req(wpa_s, dst_addr, 7401252726Srpaulo BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), 7402337817Scy buf, len, 0); 7403252726Srpaulo os_free(buf); 7404252726Srpaulo 7405252726Srpaulo return ret; 7406252726Srpaulo} 7407252726Srpaulo 7408252726Srpaulo 7409337817Scystatic int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply, 7410337817Scy int buflen) 7411281806Srpaulo{ 7412281806Srpaulo u8 dst_addr[ETH_ALEN]; 7413281806Srpaulo int used; 7414337817Scy char *ctx = NULL, *icon, *poffset, *psize; 7415337817Scy 7416337817Scy used = hwaddr_aton2(cmd, dst_addr); 7417337817Scy if (used < 0) 7418337817Scy return -1; 7419337817Scy cmd += used; 7420337817Scy 7421337817Scy icon = str_token(cmd, " ", &ctx); 7422337817Scy poffset = str_token(cmd, " ", &ctx); 7423337817Scy psize = str_token(cmd, " ", &ctx); 7424337817Scy if (!icon || !poffset || !psize) 7425337817Scy return -1; 7426337817Scy 7427337817Scy wpa_s->fetch_osu_icon_in_progress = 0; 7428337817Scy return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize), 7429337817Scy reply, buflen); 7430337817Scy} 7431337817Scy 7432337817Scy 7433337817Scystatic int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd) 7434337817Scy{ 7435337817Scy u8 dst_addr[ETH_ALEN]; 7436337817Scy int used; 7437281806Srpaulo char *icon; 7438252726Srpaulo 7439337817Scy if (!cmd[0]) 7440337817Scy return hs20_del_icon(wpa_s, NULL, NULL); 7441337817Scy 7442281806Srpaulo used = hwaddr_aton2(cmd, dst_addr); 7443281806Srpaulo if (used < 0) 7444281806Srpaulo return -1; 7445281806Srpaulo 7446281806Srpaulo while (cmd[used] == ' ') 7447281806Srpaulo used++; 7448337817Scy icon = cmd[used] ? &cmd[used] : NULL; 7449337817Scy 7450337817Scy return hs20_del_icon(wpa_s, dst_addr, icon); 7451337817Scy} 7452337817Scy 7453337817Scy 7454337817Scystatic int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem) 7455337817Scy{ 7456337817Scy u8 dst_addr[ETH_ALEN]; 7457337817Scy int used; 7458337817Scy char *icon; 7459337817Scy 7460337817Scy used = hwaddr_aton2(cmd, dst_addr); 7461337817Scy if (used < 0) 7462337817Scy return -1; 7463337817Scy 7464337817Scy while (cmd[used] == ' ') 7465337817Scy used++; 7466281806Srpaulo icon = &cmd[used]; 7467281806Srpaulo 7468281806Srpaulo wpa_s->fetch_osu_icon_in_progress = 0; 7469281806Srpaulo return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), 7470337817Scy (u8 *) icon, os_strlen(icon), inmem); 7471252726Srpaulo} 7472252726Srpaulo 7473281806Srpaulo#endif /* CONFIG_HS20 */ 7474252726Srpaulo 7475281806Srpaulo 7476252726Srpaulo#ifdef CONFIG_AUTOSCAN 7477252726Srpaulo 7478252726Srpaulostatic int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, 7479252726Srpaulo char *cmd) 7480252726Srpaulo{ 7481252726Srpaulo enum wpa_states state = wpa_s->wpa_state; 7482252726Srpaulo char *new_params = NULL; 7483252726Srpaulo 7484252726Srpaulo if (os_strlen(cmd) > 0) { 7485252726Srpaulo new_params = os_strdup(cmd); 7486252726Srpaulo if (new_params == NULL) 7487252726Srpaulo return -1; 7488252726Srpaulo } 7489252726Srpaulo 7490252726Srpaulo os_free(wpa_s->conf->autoscan); 7491252726Srpaulo wpa_s->conf->autoscan = new_params; 7492252726Srpaulo 7493252726Srpaulo if (wpa_s->conf->autoscan == NULL) 7494252726Srpaulo autoscan_deinit(wpa_s); 7495252726Srpaulo else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) 7496252726Srpaulo autoscan_init(wpa_s, 1); 7497252726Srpaulo else if (state == WPA_SCANNING) 7498252726Srpaulo wpa_supplicant_reinit_autoscan(wpa_s); 7499346981Scy else 7500346981Scy wpa_printf(MSG_DEBUG, "No autoscan update in state %s", 7501346981Scy wpa_supplicant_state_txt(state)); 7502252726Srpaulo 7503252726Srpaulo return 0; 7504252726Srpaulo} 7505252726Srpaulo 7506252726Srpaulo#endif /* CONFIG_AUTOSCAN */ 7507252726Srpaulo 7508252726Srpaulo 7509252726Srpaulo#ifdef CONFIG_WNM 7510252726Srpaulo 7511252726Srpaulostatic int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) 7512252726Srpaulo{ 7513252726Srpaulo int enter; 7514252726Srpaulo int intval = 0; 7515252726Srpaulo char *pos; 7516252726Srpaulo int ret; 7517252726Srpaulo struct wpabuf *tfs_req = NULL; 7518252726Srpaulo 7519252726Srpaulo if (os_strncmp(cmd, "enter", 5) == 0) 7520252726Srpaulo enter = 1; 7521252726Srpaulo else if (os_strncmp(cmd, "exit", 4) == 0) 7522252726Srpaulo enter = 0; 7523252726Srpaulo else 7524252726Srpaulo return -1; 7525252726Srpaulo 7526252726Srpaulo pos = os_strstr(cmd, " interval="); 7527252726Srpaulo if (pos) 7528252726Srpaulo intval = atoi(pos + 10); 7529252726Srpaulo 7530252726Srpaulo pos = os_strstr(cmd, " tfs_req="); 7531252726Srpaulo if (pos) { 7532252726Srpaulo char *end; 7533252726Srpaulo size_t len; 7534252726Srpaulo pos += 9; 7535252726Srpaulo end = os_strchr(pos, ' '); 7536252726Srpaulo if (end) 7537252726Srpaulo len = end - pos; 7538252726Srpaulo else 7539252726Srpaulo len = os_strlen(pos); 7540252726Srpaulo if (len & 1) 7541252726Srpaulo return -1; 7542252726Srpaulo len /= 2; 7543252726Srpaulo tfs_req = wpabuf_alloc(len); 7544252726Srpaulo if (tfs_req == NULL) 7545252726Srpaulo return -1; 7546252726Srpaulo if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) { 7547252726Srpaulo wpabuf_free(tfs_req); 7548252726Srpaulo return -1; 7549252726Srpaulo } 7550252726Srpaulo } 7551252726Srpaulo 7552252726Srpaulo ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER : 7553252726Srpaulo WNM_SLEEP_MODE_EXIT, intval, 7554252726Srpaulo tfs_req); 7555252726Srpaulo wpabuf_free(tfs_req); 7556252726Srpaulo 7557252726Srpaulo return ret; 7558252726Srpaulo} 7559252726Srpaulo 7560281806Srpaulo 7561281806Srpaulostatic int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) 7562281806Srpaulo{ 7563337817Scy int query_reason, list = 0; 7564346981Scy char *btm_candidates = NULL; 7565281806Srpaulo 7566281806Srpaulo query_reason = atoi(cmd); 7567281806Srpaulo 7568337817Scy cmd = os_strchr(cmd, ' '); 7569337817Scy if (cmd) { 7570346981Scy if (os_strncmp(cmd, " list", 5) == 0) 7571337817Scy list = 1; 7572346981Scy else 7573346981Scy btm_candidates = cmd; 7574337817Scy } 7575281806Srpaulo 7576337817Scy wpa_printf(MSG_DEBUG, 7577337817Scy "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s", 7578337817Scy query_reason, list ? " candidate list" : ""); 7579337817Scy 7580346981Scy return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, 7581346981Scy btm_candidates, 7582346981Scy list); 7583281806Srpaulo} 7584281806Srpaulo 7585346981Scy 7586346981Scystatic int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s, 7587346981Scy char *cmd) 7588346981Scy{ 7589346981Scy struct wpabuf *elems; 7590346981Scy int ret; 7591346981Scy 7592346981Scy elems = wpabuf_parse_bin(cmd); 7593346981Scy if (!elems) 7594346981Scy return -1; 7595346981Scy 7596346981Scy ret = wnm_send_coloc_intf_report(wpa_s, 0, elems); 7597346981Scy wpabuf_free(elems); 7598346981Scy return ret; 7599346981Scy} 7600346981Scy 7601252726Srpaulo#endif /* CONFIG_WNM */ 7602252726Srpaulo 7603252726Srpaulo 7604252726Srpaulostatic int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, 7605252726Srpaulo size_t buflen) 7606252726Srpaulo{ 7607252726Srpaulo struct wpa_signal_info si; 7608252726Srpaulo int ret; 7609281806Srpaulo char *pos, *end; 7610252726Srpaulo 7611252726Srpaulo ret = wpa_drv_signal_poll(wpa_s, &si); 7612252726Srpaulo if (ret) 7613252726Srpaulo return -1; 7614252726Srpaulo 7615281806Srpaulo pos = buf; 7616281806Srpaulo end = buf + buflen; 7617281806Srpaulo 7618281806Srpaulo ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n" 7619252726Srpaulo "NOISE=%d\nFREQUENCY=%u\n", 7620252726Srpaulo si.current_signal, si.current_txrate / 1000, 7621252726Srpaulo si.current_noise, si.frequency); 7622281806Srpaulo if (os_snprintf_error(end - pos, ret)) 7623252726Srpaulo return -1; 7624281806Srpaulo pos += ret; 7625281806Srpaulo 7626281806Srpaulo if (si.chanwidth != CHAN_WIDTH_UNKNOWN) { 7627281806Srpaulo ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", 7628281806Srpaulo channel_width_to_string(si.chanwidth)); 7629281806Srpaulo if (os_snprintf_error(end - pos, ret)) 7630281806Srpaulo return -1; 7631281806Srpaulo pos += ret; 7632281806Srpaulo } 7633281806Srpaulo 7634346981Scy if (si.center_frq1 > 0) { 7635346981Scy ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n", 7636346981Scy si.center_frq1); 7637281806Srpaulo if (os_snprintf_error(end - pos, ret)) 7638281806Srpaulo return -1; 7639281806Srpaulo pos += ret; 7640281806Srpaulo } 7641281806Srpaulo 7642346981Scy if (si.center_frq2 > 0) { 7643346981Scy ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n", 7644346981Scy si.center_frq2); 7645346981Scy if (os_snprintf_error(end - pos, ret)) 7646346981Scy return -1; 7647346981Scy pos += ret; 7648346981Scy } 7649346981Scy 7650281806Srpaulo if (si.avg_signal) { 7651281806Srpaulo ret = os_snprintf(pos, end - pos, 7652281806Srpaulo "AVG_RSSI=%d\n", si.avg_signal); 7653281806Srpaulo if (os_snprintf_error(end - pos, ret)) 7654281806Srpaulo return -1; 7655281806Srpaulo pos += ret; 7656281806Srpaulo } 7657281806Srpaulo 7658289549Srpaulo if (si.avg_beacon_signal) { 7659289549Srpaulo ret = os_snprintf(pos, end - pos, 7660289549Srpaulo "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal); 7661289549Srpaulo if (os_snprintf_error(end - pos, ret)) 7662289549Srpaulo return -1; 7663289549Srpaulo pos += ret; 7664289549Srpaulo } 7665289549Srpaulo 7666281806Srpaulo return pos - buf; 7667252726Srpaulo} 7668252726Srpaulo 7669252726Srpaulo 7670337817Scystatic int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, 7671337817Scy const char *cmd) 7672337817Scy{ 7673337817Scy const char *pos; 7674337817Scy int threshold = 0; 7675337817Scy int hysteresis = 0; 7676337817Scy 7677337817Scy if (wpa_s->bgscan && wpa_s->bgscan_priv) { 7678337817Scy wpa_printf(MSG_DEBUG, 7679337817Scy "Reject SIGNAL_MONITOR command - bgscan is active"); 7680337817Scy return -1; 7681337817Scy } 7682337817Scy pos = os_strstr(cmd, "THRESHOLD="); 7683337817Scy if (pos) 7684337817Scy threshold = atoi(pos + 10); 7685337817Scy pos = os_strstr(cmd, "HYSTERESIS="); 7686337817Scy if (pos) 7687337817Scy hysteresis = atoi(pos + 11); 7688337817Scy return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis); 7689337817Scy} 7690337817Scy 7691337817Scy 7692346981Scy#ifdef CONFIG_TESTING_OPTIONS 7693346981Scyint wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, 7694346981Scy enum wpa_driver_if_type if_type, 7695346981Scy unsigned int *num, 7696346981Scy unsigned int *freq_list) 7697346981Scy{ 7698346981Scy char *pos = wpa_s->get_pref_freq_list_override; 7699346981Scy char *end; 7700346981Scy unsigned int count = 0; 7701346981Scy 7702346981Scy /* Override string format: 7703346981Scy * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */ 7704346981Scy 7705346981Scy while (pos) { 7706346981Scy if (atoi(pos) == (int) if_type) 7707346981Scy break; 7708346981Scy pos = os_strchr(pos, ' '); 7709346981Scy if (pos) 7710346981Scy pos++; 7711346981Scy } 7712346981Scy if (!pos) 7713346981Scy return -1; 7714346981Scy pos = os_strchr(pos, ':'); 7715346981Scy if (!pos) 7716346981Scy return -1; 7717346981Scy pos++; 7718346981Scy end = os_strchr(pos, ' '); 7719346981Scy while (pos && (!end || pos < end) && count < *num) { 7720346981Scy freq_list[count++] = atoi(pos); 7721346981Scy pos = os_strchr(pos, ','); 7722346981Scy if (pos) 7723346981Scy pos++; 7724346981Scy } 7725346981Scy 7726346981Scy *num = count; 7727346981Scy return 0; 7728346981Scy} 7729346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 7730346981Scy 7731346981Scy 7732289549Srpaulostatic int wpas_ctrl_iface_get_pref_freq_list( 7733289549Srpaulo struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 7734289549Srpaulo{ 7735289549Srpaulo unsigned int freq_list[100], num = 100, i; 7736289549Srpaulo int ret; 7737289549Srpaulo enum wpa_driver_if_type iface_type; 7738289549Srpaulo char *pos, *end; 7739289549Srpaulo 7740289549Srpaulo pos = buf; 7741289549Srpaulo end = buf + buflen; 7742289549Srpaulo 7743289549Srpaulo /* buf: "<interface_type>" */ 7744289549Srpaulo if (os_strcmp(cmd, "STATION") == 0) 7745289549Srpaulo iface_type = WPA_IF_STATION; 7746289549Srpaulo else if (os_strcmp(cmd, "AP") == 0) 7747289549Srpaulo iface_type = WPA_IF_AP_BSS; 7748289549Srpaulo else if (os_strcmp(cmd, "P2P_GO") == 0) 7749289549Srpaulo iface_type = WPA_IF_P2P_GO; 7750289549Srpaulo else if (os_strcmp(cmd, "P2P_CLIENT") == 0) 7751289549Srpaulo iface_type = WPA_IF_P2P_CLIENT; 7752289549Srpaulo else if (os_strcmp(cmd, "IBSS") == 0) 7753289549Srpaulo iface_type = WPA_IF_IBSS; 7754289549Srpaulo else if (os_strcmp(cmd, "TDLS") == 0) 7755289549Srpaulo iface_type = WPA_IF_TDLS; 7756289549Srpaulo else 7757289549Srpaulo return -1; 7758289549Srpaulo 7759289549Srpaulo wpa_printf(MSG_DEBUG, 7760289549Srpaulo "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)", 7761346981Scy iface_type, cmd); 7762289549Srpaulo 7763289549Srpaulo ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list); 7764289549Srpaulo if (ret) 7765289549Srpaulo return -1; 7766289549Srpaulo 7767289549Srpaulo for (i = 0; i < num; i++) { 7768289549Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 7769289549Srpaulo i > 0 ? "," : "", freq_list[i]); 7770289549Srpaulo if (os_snprintf_error(end - pos, ret)) 7771289549Srpaulo return -1; 7772289549Srpaulo pos += ret; 7773289549Srpaulo } 7774289549Srpaulo 7775289549Srpaulo return pos - buf; 7776289549Srpaulo} 7777289549Srpaulo 7778289549Srpaulo 7779337817Scystatic int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s, 7780337817Scy char *buf, size_t buflen) 7781337817Scy{ 7782337817Scy int ret, i; 7783337817Scy char *pos, *end; 7784337817Scy 7785337817Scy ret = os_snprintf(buf, buflen, "%016llX:\n", 7786337817Scy (long long unsigned) wpa_s->drv_flags); 7787337817Scy if (os_snprintf_error(buflen, ret)) 7788337817Scy return -1; 7789337817Scy 7790337817Scy pos = buf + ret; 7791337817Scy end = buf + buflen; 7792337817Scy 7793337817Scy for (i = 0; i < 64; i++) { 7794337817Scy if (wpa_s->drv_flags & (1LLU << i)) { 7795337817Scy ret = os_snprintf(pos, end - pos, "%s\n", 7796337817Scy driver_flag_to_string(1LLU << i)); 7797337817Scy if (os_snprintf_error(end - pos, ret)) 7798337817Scy return -1; 7799337817Scy pos += ret; 7800337817Scy } 7801337817Scy } 7802337817Scy 7803337817Scy return pos - buf; 7804337817Scy} 7805337817Scy 7806337817Scy 7807252726Srpaulostatic int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, 7808252726Srpaulo size_t buflen) 7809252726Srpaulo{ 7810252726Srpaulo struct hostap_sta_driver_data sta; 7811252726Srpaulo int ret; 7812252726Srpaulo 7813252726Srpaulo ret = wpa_drv_pktcnt_poll(wpa_s, &sta); 7814252726Srpaulo if (ret) 7815252726Srpaulo return -1; 7816252726Srpaulo 7817252726Srpaulo ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n", 7818252726Srpaulo sta.tx_packets, sta.tx_retry_failed, sta.rx_packets); 7819281806Srpaulo if (os_snprintf_error(buflen, ret)) 7820252726Srpaulo return -1; 7821252726Srpaulo return ret; 7822252726Srpaulo} 7823252726Srpaulo 7824252726Srpaulo 7825281806Srpaulo#ifdef ANDROID 7826281806Srpaulostatic int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, 7827281806Srpaulo char *buf, size_t buflen) 7828281806Srpaulo{ 7829281806Srpaulo int ret; 7830281806Srpaulo 7831281806Srpaulo ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen); 7832281806Srpaulo if (ret == 0) { 7833281806Srpaulo if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { 7834281806Srpaulo struct p2p_data *p2p = wpa_s->global->p2p; 7835281806Srpaulo if (p2p) { 7836281806Srpaulo char country[3]; 7837281806Srpaulo country[0] = cmd[8]; 7838281806Srpaulo country[1] = cmd[9]; 7839281806Srpaulo country[2] = 0x04; 7840281806Srpaulo p2p_set_country(p2p, country); 7841281806Srpaulo } 7842281806Srpaulo } 7843281806Srpaulo ret = os_snprintf(buf, buflen, "%s\n", "OK"); 7844281806Srpaulo if (os_snprintf_error(buflen, ret)) 7845281806Srpaulo ret = -1; 7846281806Srpaulo } 7847281806Srpaulo return ret; 7848281806Srpaulo} 7849281806Srpaulo#endif /* ANDROID */ 7850281806Srpaulo 7851281806Srpaulo 7852281806Srpaulostatic int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, 7853281806Srpaulo char *buf, size_t buflen) 7854281806Srpaulo{ 7855281806Srpaulo int ret; 7856281806Srpaulo char *pos; 7857281806Srpaulo u8 *data = NULL; 7858281806Srpaulo unsigned int vendor_id, subcmd; 7859281806Srpaulo struct wpabuf *reply; 7860281806Srpaulo size_t data_len = 0; 7861281806Srpaulo 7862281806Srpaulo /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ 7863281806Srpaulo vendor_id = strtoul(cmd, &pos, 16); 7864337817Scy if (!isblank((unsigned char) *pos)) 7865281806Srpaulo return -EINVAL; 7866281806Srpaulo 7867281806Srpaulo subcmd = strtoul(pos, &pos, 10); 7868281806Srpaulo 7869281806Srpaulo if (*pos != '\0') { 7870337817Scy if (!isblank((unsigned char) *pos++)) 7871281806Srpaulo return -EINVAL; 7872281806Srpaulo data_len = os_strlen(pos); 7873281806Srpaulo } 7874281806Srpaulo 7875281806Srpaulo if (data_len) { 7876281806Srpaulo data_len /= 2; 7877281806Srpaulo data = os_malloc(data_len); 7878281806Srpaulo if (!data) 7879281806Srpaulo return -1; 7880281806Srpaulo 7881281806Srpaulo if (hexstr2bin(pos, data, data_len)) { 7882281806Srpaulo wpa_printf(MSG_DEBUG, 7883281806Srpaulo "Vendor command: wrong parameter format"); 7884281806Srpaulo os_free(data); 7885281806Srpaulo return -EINVAL; 7886281806Srpaulo } 7887281806Srpaulo } 7888281806Srpaulo 7889281806Srpaulo reply = wpabuf_alloc((buflen - 1) / 2); 7890281806Srpaulo if (!reply) { 7891281806Srpaulo os_free(data); 7892281806Srpaulo return -1; 7893281806Srpaulo } 7894281806Srpaulo 7895281806Srpaulo ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len, 7896281806Srpaulo reply); 7897281806Srpaulo 7898281806Srpaulo if (ret == 0) 7899281806Srpaulo ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), 7900281806Srpaulo wpabuf_len(reply)); 7901281806Srpaulo 7902281806Srpaulo wpabuf_free(reply); 7903281806Srpaulo os_free(data); 7904281806Srpaulo 7905281806Srpaulo return ret; 7906281806Srpaulo} 7907281806Srpaulo 7908281806Srpaulo 7909281806Srpaulostatic void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) 7910281806Srpaulo{ 7911281806Srpaulo#ifdef CONFIG_P2P 7912281806Srpaulo struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ? 7913281806Srpaulo wpa_s->global->p2p_init_wpa_s : wpa_s; 7914281806Srpaulo#endif /* CONFIG_P2P */ 7915281806Srpaulo 7916281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); 7917281806Srpaulo 7918346981Scy if (wpas_abort_ongoing_scan(wpa_s) == 0) 7919346981Scy wpa_s->ignore_post_flush_scan_res = 1; 7920337817Scy 7921337817Scy if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { 7922337817Scy /* 7923337817Scy * Avoid possible auto connect re-connection on getting 7924337817Scy * disconnected due to state flush. 7925337817Scy */ 7926337817Scy wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 7927337817Scy } 7928337817Scy 7929281806Srpaulo#ifdef CONFIG_P2P 7930337817Scy wpas_p2p_group_remove(p2p_wpa_s, "*"); 7931281806Srpaulo wpas_p2p_cancel(p2p_wpa_s); 7932281806Srpaulo p2p_ctrl_flush(p2p_wpa_s); 7933281806Srpaulo wpas_p2p_service_flush(p2p_wpa_s); 7934281806Srpaulo p2p_wpa_s->global->p2p_disabled = 0; 7935281806Srpaulo p2p_wpa_s->global->p2p_per_sta_psk = 0; 7936281806Srpaulo p2p_wpa_s->conf->num_sec_device_types = 0; 7937281806Srpaulo p2p_wpa_s->p2p_disable_ip_addr_req = 0; 7938281806Srpaulo os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range); 7939281806Srpaulo p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL; 7940289549Srpaulo p2p_wpa_s->global->p2p_go_avoid_freq.num = 0; 7941281806Srpaulo p2p_wpa_s->global->pending_p2ps_group = 0; 7942337817Scy p2p_wpa_s->global->pending_p2ps_group_freq = 0; 7943281806Srpaulo#endif /* CONFIG_P2P */ 7944281806Srpaulo 7945281806Srpaulo#ifdef CONFIG_WPS_TESTING 7946281806Srpaulo wps_version_number = 0x20; 7947281806Srpaulo wps_testing_dummy_cred = 0; 7948281806Srpaulo wps_corrupt_pkhash = 0; 7949337817Scy wps_force_auth_types_in_use = 0; 7950337817Scy wps_force_encr_types_in_use = 0; 7951281806Srpaulo#endif /* CONFIG_WPS_TESTING */ 7952281806Srpaulo#ifdef CONFIG_WPS 7953281806Srpaulo wpa_s->wps_fragment_size = 0; 7954281806Srpaulo wpas_wps_cancel(wpa_s); 7955281806Srpaulo wps_registrar_flush(wpa_s->wps->registrar); 7956281806Srpaulo#endif /* CONFIG_WPS */ 7957281806Srpaulo wpa_s->after_wps = 0; 7958281806Srpaulo wpa_s->known_wps_freq = 0; 7959281806Srpaulo 7960346981Scy#ifdef CONFIG_DPP 7961346981Scy wpas_dpp_deinit(wpa_s); 7962346981Scy wpa_s->dpp_init_max_tries = 0; 7963346981Scy wpa_s->dpp_init_retry_time = 0; 7964346981Scy wpa_s->dpp_resp_wait_time = 0; 7965346981Scy wpa_s->dpp_resp_max_tries = 0; 7966346981Scy wpa_s->dpp_resp_retry_time = 0; 7967346981Scy#ifdef CONFIG_TESTING_OPTIONS 7968346981Scy os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN); 7969346981Scy os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN); 7970346981Scy dpp_pkex_ephemeral_key_override_len = 0; 7971346981Scy dpp_protocol_key_override_len = 0; 7972346981Scy dpp_nonce_override_len = 0; 7973346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 7974346981Scy#endif /* CONFIG_DPP */ 7975346981Scy 7976281806Srpaulo#ifdef CONFIG_TDLS 7977281806Srpaulo#ifdef CONFIG_TDLS_TESTING 7978281806Srpaulo tdls_testing = 0; 7979281806Srpaulo#endif /* CONFIG_TDLS_TESTING */ 7980281806Srpaulo wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); 7981281806Srpaulo wpa_tdls_enable(wpa_s->wpa, 1); 7982281806Srpaulo#endif /* CONFIG_TDLS */ 7983281806Srpaulo 7984281806Srpaulo eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); 7985281806Srpaulo wpa_supplicant_stop_countermeasures(wpa_s, NULL); 7986281806Srpaulo 7987281806Srpaulo wpa_s->no_keep_alive = 0; 7988281806Srpaulo wpa_s->own_disconnect_req = 0; 7989281806Srpaulo 7990281806Srpaulo os_free(wpa_s->disallow_aps_bssid); 7991281806Srpaulo wpa_s->disallow_aps_bssid = NULL; 7992281806Srpaulo wpa_s->disallow_aps_bssid_count = 0; 7993281806Srpaulo os_free(wpa_s->disallow_aps_ssid); 7994281806Srpaulo wpa_s->disallow_aps_ssid = NULL; 7995281806Srpaulo wpa_s->disallow_aps_ssid_count = 0; 7996281806Srpaulo 7997281806Srpaulo wpa_s->set_sta_uapsd = 0; 7998281806Srpaulo wpa_s->sta_uapsd = 0; 7999281806Srpaulo 8000281806Srpaulo wpa_drv_radio_disable(wpa_s, 0); 8001281806Srpaulo wpa_blacklist_clear(wpa_s); 8002281806Srpaulo wpa_s->extra_blacklist_count = 0; 8003281806Srpaulo wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all"); 8004281806Srpaulo wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all"); 8005281806Srpaulo wpa_config_flush_blobs(wpa_s->conf); 8006281806Srpaulo wpa_s->conf->auto_interworking = 0; 8007281806Srpaulo wpa_s->conf->okc = 0; 8008281806Srpaulo 8009281806Srpaulo wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); 8010281806Srpaulo rsn_preauth_deinit(wpa_s->wpa); 8011281806Srpaulo 8012281806Srpaulo wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200); 8013281806Srpaulo wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70); 8014281806Srpaulo wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60); 8015281806Srpaulo eapol_sm_notify_logoff(wpa_s->eapol, FALSE); 8016281806Srpaulo 8017281806Srpaulo radio_remove_works(wpa_s, NULL, 1); 8018281806Srpaulo wpa_s->ext_work_in_progress = 0; 8019281806Srpaulo 8020281806Srpaulo wpa_s->next_ssid = NULL; 8021281806Srpaulo 8022281806Srpaulo#ifdef CONFIG_INTERWORKING 8023337817Scy#ifdef CONFIG_HS20 8024281806Srpaulo hs20_cancel_fetch_osu(wpa_s); 8025337817Scy hs20_del_icon(wpa_s, NULL, NULL); 8026337817Scy#endif /* CONFIG_HS20 */ 8027281806Srpaulo#endif /* CONFIG_INTERWORKING */ 8028281806Srpaulo 8029281806Srpaulo wpa_s->ext_mgmt_frame_handling = 0; 8030281806Srpaulo wpa_s->ext_eapol_frame_io = 0; 8031281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 8032281806Srpaulo wpa_s->extra_roc_dur = 0; 8033281806Srpaulo wpa_s->test_failure = WPAS_TEST_FAILURE_NONE; 8034337817Scy wpa_s->p2p_go_csa_on_inv = 0; 8035337817Scy wpa_s->ignore_auth_resp = 0; 8036337817Scy wpa_s->ignore_assoc_disallow = 0; 8037346981Scy wpa_s->testing_resend_assoc = 0; 8038337817Scy wpa_s->reject_btm_req_reason = 0; 8039337817Scy wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); 8040346981Scy os_free(wpa_s->get_pref_freq_list_override); 8041346981Scy wpa_s->get_pref_freq_list_override = NULL; 8042346981Scy wpabuf_free(wpa_s->sae_commit_override); 8043346981Scy wpa_s->sae_commit_override = NULL; 8044346981Scy#ifdef CONFIG_DPP 8045346981Scy os_free(wpa_s->dpp_config_obj_override); 8046346981Scy wpa_s->dpp_config_obj_override = NULL; 8047346981Scy os_free(wpa_s->dpp_discovery_override); 8048346981Scy wpa_s->dpp_discovery_override = NULL; 8049346981Scy os_free(wpa_s->dpp_groups_override); 8050346981Scy wpa_s->dpp_groups_override = NULL; 8051346981Scy dpp_test = DPP_TEST_DISABLED; 8052346981Scy#endif /* CONFIG_DPP */ 8053281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 8054281806Srpaulo 8055281806Srpaulo wpa_s->disconnected = 0; 8056281806Srpaulo os_free(wpa_s->next_scan_freqs); 8057281806Srpaulo wpa_s->next_scan_freqs = NULL; 8058346981Scy os_free(wpa_s->select_network_scan_freqs); 8059346981Scy wpa_s->select_network_scan_freqs = NULL; 8060281806Srpaulo 8061281806Srpaulo wpa_bss_flush(wpa_s); 8062281806Srpaulo if (!dl_list_empty(&wpa_s->bss)) { 8063281806Srpaulo wpa_printf(MSG_DEBUG, 8064281806Srpaulo "BSS table not empty after flush: %u entries, current_bss=%p bssid=" 8065281806Srpaulo MACSTR " pending_bssid=" MACSTR, 8066281806Srpaulo dl_list_len(&wpa_s->bss), wpa_s->current_bss, 8067281806Srpaulo MAC2STR(wpa_s->bssid), 8068281806Srpaulo MAC2STR(wpa_s->pending_bssid)); 8069281806Srpaulo } 8070289549Srpaulo 8071289549Srpaulo eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); 8072324697Sgordon wpa_s->wnmsleep_used = 0; 8073337817Scy 8074337817Scy#ifdef CONFIG_SME 8075337817Scy wpa_s->sme.last_unprot_disconnect.sec = 0; 8076337817Scy#endif /* CONFIG_SME */ 8077346981Scy 8078346981Scy wpabuf_free(wpa_s->ric_ies); 8079346981Scy wpa_s->ric_ies = NULL; 8080346981Scy 8081346981Scy wpa_supplicant_update_channel_list(wpa_s, NULL); 8082346981Scy 8083346981Scy free_bss_tmp_disallowed(wpa_s); 8084281806Srpaulo} 8085281806Srpaulo 8086281806Srpaulo 8087281806Srpaulostatic int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, 8088281806Srpaulo char *buf, size_t buflen) 8089281806Srpaulo{ 8090281806Srpaulo struct wpa_radio_work *work; 8091281806Srpaulo char *pos, *end; 8092281806Srpaulo struct os_reltime now, diff; 8093281806Srpaulo 8094281806Srpaulo pos = buf; 8095281806Srpaulo end = buf + buflen; 8096281806Srpaulo 8097281806Srpaulo os_get_reltime(&now); 8098281806Srpaulo 8099281806Srpaulo dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) 8100281806Srpaulo { 8101281806Srpaulo int ret; 8102281806Srpaulo 8103281806Srpaulo os_reltime_sub(&now, &work->time, &diff); 8104281806Srpaulo ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", 8105281806Srpaulo work->type, work->wpa_s->ifname, work->freq, 8106281806Srpaulo work->started, diff.sec, diff.usec); 8107281806Srpaulo if (os_snprintf_error(end - pos, ret)) 8108281806Srpaulo break; 8109281806Srpaulo pos += ret; 8110281806Srpaulo } 8111281806Srpaulo 8112281806Srpaulo return pos - buf; 8113281806Srpaulo} 8114281806Srpaulo 8115281806Srpaulo 8116281806Srpaulostatic void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx) 8117281806Srpaulo{ 8118281806Srpaulo struct wpa_radio_work *work = eloop_ctx; 8119281806Srpaulo struct wpa_external_work *ework = work->ctx; 8120281806Srpaulo 8121281806Srpaulo wpa_dbg(work->wpa_s, MSG_DEBUG, 8122281806Srpaulo "Timing out external radio work %u (%s)", 8123281806Srpaulo ework->id, work->type); 8124281806Srpaulo wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id); 8125281806Srpaulo work->wpa_s->ext_work_in_progress = 0; 8126281806Srpaulo radio_work_done(work); 8127281806Srpaulo os_free(ework); 8128281806Srpaulo} 8129281806Srpaulo 8130281806Srpaulo 8131281806Srpaulostatic void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) 8132281806Srpaulo{ 8133281806Srpaulo struct wpa_external_work *ework = work->ctx; 8134281806Srpaulo 8135281806Srpaulo if (deinit) { 8136281806Srpaulo if (work->started) 8137281806Srpaulo eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, 8138281806Srpaulo work, NULL); 8139281806Srpaulo 8140337817Scy /* 8141337817Scy * work->type points to a buffer in ework, so need to replace 8142337817Scy * that here with a fixed string to avoid use of freed memory 8143337817Scy * in debug prints. 8144337817Scy */ 8145337817Scy work->type = "freed-ext-work"; 8146337817Scy work->ctx = NULL; 8147281806Srpaulo os_free(ework); 8148281806Srpaulo return; 8149281806Srpaulo } 8150281806Srpaulo 8151281806Srpaulo wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)", 8152281806Srpaulo ework->id, ework->type); 8153281806Srpaulo wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id); 8154281806Srpaulo work->wpa_s->ext_work_in_progress = 1; 8155281806Srpaulo if (!ework->timeout) 8156281806Srpaulo ework->timeout = 10; 8157281806Srpaulo eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout, 8158281806Srpaulo work, NULL); 8159281806Srpaulo} 8160281806Srpaulo 8161281806Srpaulo 8162281806Srpaulostatic int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd, 8163281806Srpaulo char *buf, size_t buflen) 8164281806Srpaulo{ 8165281806Srpaulo struct wpa_external_work *ework; 8166281806Srpaulo char *pos, *pos2; 8167281806Srpaulo size_t type_len; 8168281806Srpaulo int ret; 8169281806Srpaulo unsigned int freq = 0; 8170281806Srpaulo 8171281806Srpaulo /* format: <name> [freq=<MHz>] [timeout=<seconds>] */ 8172281806Srpaulo 8173281806Srpaulo ework = os_zalloc(sizeof(*ework)); 8174281806Srpaulo if (ework == NULL) 8175281806Srpaulo return -1; 8176281806Srpaulo 8177281806Srpaulo pos = os_strchr(cmd, ' '); 8178281806Srpaulo if (pos) { 8179281806Srpaulo type_len = pos - cmd; 8180281806Srpaulo pos++; 8181281806Srpaulo 8182281806Srpaulo pos2 = os_strstr(pos, "freq="); 8183281806Srpaulo if (pos2) 8184281806Srpaulo freq = atoi(pos2 + 5); 8185281806Srpaulo 8186281806Srpaulo pos2 = os_strstr(pos, "timeout="); 8187281806Srpaulo if (pos2) 8188281806Srpaulo ework->timeout = atoi(pos2 + 8); 8189281806Srpaulo } else { 8190281806Srpaulo type_len = os_strlen(cmd); 8191281806Srpaulo } 8192281806Srpaulo if (4 + type_len >= sizeof(ework->type)) 8193281806Srpaulo type_len = sizeof(ework->type) - 4 - 1; 8194281806Srpaulo os_strlcpy(ework->type, "ext:", sizeof(ework->type)); 8195281806Srpaulo os_memcpy(ework->type + 4, cmd, type_len); 8196281806Srpaulo ework->type[4 + type_len] = '\0'; 8197281806Srpaulo 8198281806Srpaulo wpa_s->ext_work_id++; 8199281806Srpaulo if (wpa_s->ext_work_id == 0) 8200281806Srpaulo wpa_s->ext_work_id++; 8201281806Srpaulo ework->id = wpa_s->ext_work_id; 8202281806Srpaulo 8203281806Srpaulo if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb, 8204281806Srpaulo ework) < 0) { 8205281806Srpaulo os_free(ework); 8206281806Srpaulo return -1; 8207281806Srpaulo } 8208281806Srpaulo 8209281806Srpaulo ret = os_snprintf(buf, buflen, "%u", ework->id); 8210281806Srpaulo if (os_snprintf_error(buflen, ret)) 8211281806Srpaulo return -1; 8212281806Srpaulo return ret; 8213281806Srpaulo} 8214281806Srpaulo 8215281806Srpaulo 8216281806Srpaulostatic int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd) 8217281806Srpaulo{ 8218281806Srpaulo struct wpa_radio_work *work; 8219281806Srpaulo unsigned int id = atoi(cmd); 8220281806Srpaulo 8221281806Srpaulo dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) 8222281806Srpaulo { 8223281806Srpaulo struct wpa_external_work *ework; 8224281806Srpaulo 8225281806Srpaulo if (os_strncmp(work->type, "ext:", 4) != 0) 8226281806Srpaulo continue; 8227281806Srpaulo ework = work->ctx; 8228281806Srpaulo if (id && ework->id != id) 8229281806Srpaulo continue; 8230281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 8231281806Srpaulo "Completed external radio work %u (%s)", 8232281806Srpaulo ework->id, ework->type); 8233281806Srpaulo eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); 8234281806Srpaulo wpa_s->ext_work_in_progress = 0; 8235281806Srpaulo radio_work_done(work); 8236281806Srpaulo os_free(ework); 8237281806Srpaulo return 3; /* "OK\n" */ 8238281806Srpaulo } 8239281806Srpaulo 8240281806Srpaulo return -1; 8241281806Srpaulo} 8242281806Srpaulo 8243281806Srpaulo 8244281806Srpaulostatic int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd, 8245281806Srpaulo char *buf, size_t buflen) 8246281806Srpaulo{ 8247281806Srpaulo if (os_strcmp(cmd, "show") == 0) 8248281806Srpaulo return wpas_ctrl_radio_work_show(wpa_s, buf, buflen); 8249281806Srpaulo if (os_strncmp(cmd, "add ", 4) == 0) 8250281806Srpaulo return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen); 8251281806Srpaulo if (os_strncmp(cmd, "done ", 5) == 0) 8252281806Srpaulo return wpas_ctrl_radio_work_done(wpa_s, cmd + 4); 8253281806Srpaulo return -1; 8254281806Srpaulo} 8255281806Srpaulo 8256281806Srpaulo 8257281806Srpaulovoid wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) 8258281806Srpaulo{ 8259281806Srpaulo struct wpa_radio_work *work, *tmp; 8260281806Srpaulo 8261281806Srpaulo if (!wpa_s || !wpa_s->radio) 8262281806Srpaulo return; 8263281806Srpaulo 8264281806Srpaulo dl_list_for_each_safe(work, tmp, &wpa_s->radio->work, 8265281806Srpaulo struct wpa_radio_work, list) { 8266281806Srpaulo struct wpa_external_work *ework; 8267281806Srpaulo 8268281806Srpaulo if (os_strncmp(work->type, "ext:", 4) != 0) 8269281806Srpaulo continue; 8270281806Srpaulo ework = work->ctx; 8271281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 8272281806Srpaulo "Flushing%s external radio work %u (%s)", 8273281806Srpaulo work->started ? " started" : "", ework->id, 8274281806Srpaulo ework->type); 8275281806Srpaulo if (work->started) 8276281806Srpaulo eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, 8277281806Srpaulo work, NULL); 8278281806Srpaulo radio_work_done(work); 8279281806Srpaulo os_free(ework); 8280281806Srpaulo } 8281281806Srpaulo} 8282281806Srpaulo 8283281806Srpaulo 8284281806Srpaulostatic void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) 8285281806Srpaulo{ 8286281806Srpaulo struct wpa_supplicant *wpa_s = eloop_ctx; 8287281806Srpaulo eapol_sm_notify_ctrl_response(wpa_s->eapol); 8288281806Srpaulo} 8289281806Srpaulo 8290281806Srpaulo 8291281806Srpaulostatic int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value, 8292281806Srpaulo unsigned int *scan_id_count, int scan_id[]) 8293281806Srpaulo{ 8294281806Srpaulo const char *pos = value; 8295281806Srpaulo 8296281806Srpaulo while (pos) { 8297281806Srpaulo if (*pos == ' ' || *pos == '\0') 8298281806Srpaulo break; 8299281806Srpaulo if (*scan_id_count == MAX_SCAN_ID) 8300281806Srpaulo return -1; 8301281806Srpaulo scan_id[(*scan_id_count)++] = atoi(pos); 8302281806Srpaulo pos = os_strchr(pos, ','); 8303281806Srpaulo if (pos) 8304281806Srpaulo pos++; 8305281806Srpaulo } 8306281806Srpaulo 8307281806Srpaulo return 0; 8308281806Srpaulo} 8309281806Srpaulo 8310281806Srpaulo 8311281806Srpaulostatic void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, 8312281806Srpaulo char *reply, int reply_size, int *reply_len) 8313281806Srpaulo{ 8314281806Srpaulo char *pos; 8315281806Srpaulo unsigned int manual_scan_passive = 0; 8316281806Srpaulo unsigned int manual_scan_use_id = 0; 8317281806Srpaulo unsigned int manual_scan_only_new = 0; 8318281806Srpaulo unsigned int scan_only = 0; 8319281806Srpaulo unsigned int scan_id_count = 0; 8320281806Srpaulo int scan_id[MAX_SCAN_ID]; 8321281806Srpaulo void (*scan_res_handler)(struct wpa_supplicant *wpa_s, 8322281806Srpaulo struct wpa_scan_results *scan_res); 8323281806Srpaulo int *manual_scan_freqs = NULL; 8324289549Srpaulo struct wpa_ssid_value *ssid = NULL, *ns; 8325289549Srpaulo unsigned int ssid_count = 0; 8326281806Srpaulo 8327281806Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 8328281806Srpaulo *reply_len = -1; 8329281806Srpaulo return; 8330281806Srpaulo } 8331281806Srpaulo 8332281806Srpaulo if (radio_work_pending(wpa_s, "scan")) { 8333281806Srpaulo wpa_printf(MSG_DEBUG, 8334281806Srpaulo "Pending scan scheduled - reject new request"); 8335281806Srpaulo *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 8336281806Srpaulo return; 8337281806Srpaulo } 8338281806Srpaulo 8339289549Srpaulo#ifdef CONFIG_INTERWORKING 8340289549Srpaulo if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) { 8341289549Srpaulo wpa_printf(MSG_DEBUG, 8342289549Srpaulo "Interworking select in progress - reject new scan"); 8343289549Srpaulo *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 8344289549Srpaulo return; 8345289549Srpaulo } 8346289549Srpaulo#endif /* CONFIG_INTERWORKING */ 8347289549Srpaulo 8348281806Srpaulo if (params) { 8349281806Srpaulo if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) 8350281806Srpaulo scan_only = 1; 8351281806Srpaulo 8352281806Srpaulo pos = os_strstr(params, "freq="); 8353281806Srpaulo if (pos) { 8354281806Srpaulo manual_scan_freqs = freq_range_to_channel_list(wpa_s, 8355281806Srpaulo pos + 5); 8356281806Srpaulo if (manual_scan_freqs == NULL) { 8357281806Srpaulo *reply_len = -1; 8358281806Srpaulo goto done; 8359281806Srpaulo } 8360281806Srpaulo } 8361281806Srpaulo 8362281806Srpaulo pos = os_strstr(params, "passive="); 8363281806Srpaulo if (pos) 8364281806Srpaulo manual_scan_passive = !!atoi(pos + 8); 8365281806Srpaulo 8366281806Srpaulo pos = os_strstr(params, "use_id="); 8367281806Srpaulo if (pos) 8368281806Srpaulo manual_scan_use_id = atoi(pos + 7); 8369281806Srpaulo 8370281806Srpaulo pos = os_strstr(params, "only_new=1"); 8371281806Srpaulo if (pos) 8372281806Srpaulo manual_scan_only_new = 1; 8373281806Srpaulo 8374281806Srpaulo pos = os_strstr(params, "scan_id="); 8375281806Srpaulo if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count, 8376281806Srpaulo scan_id) < 0) { 8377281806Srpaulo *reply_len = -1; 8378281806Srpaulo goto done; 8379281806Srpaulo } 8380289549Srpaulo 8381346981Scy pos = os_strstr(params, "bssid="); 8382346981Scy if (pos) { 8383346981Scy u8 bssid[ETH_ALEN]; 8384346981Scy 8385346981Scy pos += 6; 8386346981Scy if (hwaddr_aton(pos, bssid)) { 8387346981Scy wpa_printf(MSG_ERROR, "Invalid BSSID %s", pos); 8388346981Scy *reply_len = -1; 8389346981Scy goto done; 8390346981Scy } 8391346981Scy os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN); 8392346981Scy } 8393346981Scy 8394289549Srpaulo pos = params; 8395289549Srpaulo while (pos && *pos != '\0') { 8396289549Srpaulo if (os_strncmp(pos, "ssid ", 5) == 0) { 8397289549Srpaulo char *end; 8398289549Srpaulo 8399289549Srpaulo pos += 5; 8400289549Srpaulo end = pos; 8401289549Srpaulo while (*end) { 8402289549Srpaulo if (*end == '\0' || *end == ' ') 8403289549Srpaulo break; 8404289549Srpaulo end++; 8405289549Srpaulo } 8406289549Srpaulo 8407289549Srpaulo ns = os_realloc_array( 8408289549Srpaulo ssid, ssid_count + 1, 8409289549Srpaulo sizeof(struct wpa_ssid_value)); 8410289549Srpaulo if (ns == NULL) { 8411289549Srpaulo *reply_len = -1; 8412289549Srpaulo goto done; 8413289549Srpaulo } 8414289549Srpaulo ssid = ns; 8415289549Srpaulo 8416289549Srpaulo if ((end - pos) & 0x01 || 8417289549Srpaulo end - pos > 2 * SSID_MAX_LEN || 8418289549Srpaulo hexstr2bin(pos, ssid[ssid_count].ssid, 8419289549Srpaulo (end - pos) / 2) < 0) { 8420289549Srpaulo wpa_printf(MSG_DEBUG, 8421289549Srpaulo "Invalid SSID value '%s'", 8422289549Srpaulo pos); 8423289549Srpaulo *reply_len = -1; 8424289549Srpaulo goto done; 8425289549Srpaulo } 8426289549Srpaulo ssid[ssid_count].ssid_len = (end - pos) / 2; 8427289549Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "scan SSID", 8428289549Srpaulo ssid[ssid_count].ssid, 8429289549Srpaulo ssid[ssid_count].ssid_len); 8430289549Srpaulo ssid_count++; 8431289549Srpaulo pos = end; 8432289549Srpaulo } 8433289549Srpaulo 8434289549Srpaulo pos = os_strchr(pos, ' '); 8435289549Srpaulo if (pos) 8436289549Srpaulo pos++; 8437289549Srpaulo } 8438281806Srpaulo } 8439281806Srpaulo 8440289549Srpaulo wpa_s->num_ssids_from_scan_req = ssid_count; 8441289549Srpaulo os_free(wpa_s->ssids_from_scan_req); 8442289549Srpaulo if (ssid_count) { 8443289549Srpaulo wpa_s->ssids_from_scan_req = ssid; 8444289549Srpaulo ssid = NULL; 8445289549Srpaulo } else { 8446289549Srpaulo wpa_s->ssids_from_scan_req = NULL; 8447289549Srpaulo } 8448289549Srpaulo 8449281806Srpaulo if (scan_only) 8450281806Srpaulo scan_res_handler = scan_only_handler; 8451281806Srpaulo else if (wpa_s->scan_res_handler == scan_only_handler) 8452281806Srpaulo scan_res_handler = NULL; 8453281806Srpaulo else 8454281806Srpaulo scan_res_handler = wpa_s->scan_res_handler; 8455281806Srpaulo 8456281806Srpaulo if (!wpa_s->sched_scanning && !wpa_s->scanning && 8457281806Srpaulo ((wpa_s->wpa_state <= WPA_SCANNING) || 8458281806Srpaulo (wpa_s->wpa_state == WPA_COMPLETED))) { 8459281806Srpaulo wpa_s->manual_scan_passive = manual_scan_passive; 8460281806Srpaulo wpa_s->manual_scan_use_id = manual_scan_use_id; 8461281806Srpaulo wpa_s->manual_scan_only_new = manual_scan_only_new; 8462281806Srpaulo wpa_s->scan_id_count = scan_id_count; 8463281806Srpaulo os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); 8464281806Srpaulo wpa_s->scan_res_handler = scan_res_handler; 8465281806Srpaulo os_free(wpa_s->manual_scan_freqs); 8466281806Srpaulo wpa_s->manual_scan_freqs = manual_scan_freqs; 8467281806Srpaulo manual_scan_freqs = NULL; 8468281806Srpaulo 8469281806Srpaulo wpa_s->normal_scans = 0; 8470281806Srpaulo wpa_s->scan_req = MANUAL_SCAN_REQ; 8471281806Srpaulo wpa_s->after_wps = 0; 8472281806Srpaulo wpa_s->known_wps_freq = 0; 8473281806Srpaulo wpa_supplicant_req_scan(wpa_s, 0, 0); 8474281806Srpaulo if (wpa_s->manual_scan_use_id) { 8475281806Srpaulo wpa_s->manual_scan_id++; 8476281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", 8477281806Srpaulo wpa_s->manual_scan_id); 8478281806Srpaulo *reply_len = os_snprintf(reply, reply_size, "%u\n", 8479281806Srpaulo wpa_s->manual_scan_id); 8480281806Srpaulo } 8481281806Srpaulo } else if (wpa_s->sched_scanning) { 8482281806Srpaulo wpa_s->manual_scan_passive = manual_scan_passive; 8483281806Srpaulo wpa_s->manual_scan_use_id = manual_scan_use_id; 8484281806Srpaulo wpa_s->manual_scan_only_new = manual_scan_only_new; 8485281806Srpaulo wpa_s->scan_id_count = scan_id_count; 8486281806Srpaulo os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); 8487281806Srpaulo wpa_s->scan_res_handler = scan_res_handler; 8488281806Srpaulo os_free(wpa_s->manual_scan_freqs); 8489281806Srpaulo wpa_s->manual_scan_freqs = manual_scan_freqs; 8490281806Srpaulo manual_scan_freqs = NULL; 8491281806Srpaulo 8492281806Srpaulo wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); 8493281806Srpaulo wpa_supplicant_cancel_sched_scan(wpa_s); 8494281806Srpaulo wpa_s->scan_req = MANUAL_SCAN_REQ; 8495281806Srpaulo wpa_supplicant_req_scan(wpa_s, 0, 0); 8496281806Srpaulo if (wpa_s->manual_scan_use_id) { 8497281806Srpaulo wpa_s->manual_scan_id++; 8498281806Srpaulo *reply_len = os_snprintf(reply, reply_size, "%u\n", 8499281806Srpaulo wpa_s->manual_scan_id); 8500281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", 8501281806Srpaulo wpa_s->manual_scan_id); 8502281806Srpaulo } 8503281806Srpaulo } else { 8504281806Srpaulo wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); 8505281806Srpaulo *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 8506281806Srpaulo } 8507281806Srpaulo 8508281806Srpaulodone: 8509281806Srpaulo os_free(manual_scan_freqs); 8510289549Srpaulo os_free(ssid); 8511281806Srpaulo} 8512281806Srpaulo 8513281806Srpaulo 8514281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 8515281806Srpaulo 8516281806Srpaulostatic void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s, 8517281806Srpaulo unsigned int freq, const u8 *dst, 8518281806Srpaulo const u8 *src, const u8 *bssid, 8519281806Srpaulo const u8 *data, size_t data_len, 8520281806Srpaulo enum offchannel_send_action_result 8521281806Srpaulo result) 8522281806Srpaulo{ 8523281806Srpaulo wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR 8524281806Srpaulo " src=" MACSTR " bssid=" MACSTR " result=%s", 8525281806Srpaulo freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), 8526281806Srpaulo result == OFFCHANNEL_SEND_ACTION_SUCCESS ? 8527281806Srpaulo "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? 8528281806Srpaulo "NO_ACK" : "FAILED")); 8529281806Srpaulo} 8530281806Srpaulo 8531281806Srpaulo 8532281806Srpaulostatic int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd) 8533281806Srpaulo{ 8534281806Srpaulo char *pos, *param; 8535281806Srpaulo size_t len; 8536281806Srpaulo u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN]; 8537281806Srpaulo int res, used; 8538281806Srpaulo int freq = 0, no_cck = 0, wait_time = 0; 8539281806Srpaulo 8540281806Srpaulo /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1] 8541281806Srpaulo * <action=Action frame payload> */ 8542281806Srpaulo 8543281806Srpaulo wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); 8544281806Srpaulo 8545281806Srpaulo pos = cmd; 8546281806Srpaulo used = hwaddr_aton2(pos, da); 8547281806Srpaulo if (used < 0) 8548281806Srpaulo return -1; 8549281806Srpaulo pos += used; 8550281806Srpaulo while (*pos == ' ') 8551281806Srpaulo pos++; 8552281806Srpaulo used = hwaddr_aton2(pos, bssid); 8553281806Srpaulo if (used < 0) 8554281806Srpaulo return -1; 8555281806Srpaulo pos += used; 8556281806Srpaulo 8557281806Srpaulo param = os_strstr(pos, " freq="); 8558281806Srpaulo if (param) { 8559281806Srpaulo param += 6; 8560281806Srpaulo freq = atoi(param); 8561281806Srpaulo } 8562281806Srpaulo 8563281806Srpaulo param = os_strstr(pos, " no_cck="); 8564281806Srpaulo if (param) { 8565281806Srpaulo param += 8; 8566281806Srpaulo no_cck = atoi(param); 8567281806Srpaulo } 8568281806Srpaulo 8569281806Srpaulo param = os_strstr(pos, " wait_time="); 8570281806Srpaulo if (param) { 8571281806Srpaulo param += 11; 8572281806Srpaulo wait_time = atoi(param); 8573281806Srpaulo } 8574281806Srpaulo 8575281806Srpaulo param = os_strstr(pos, " action="); 8576281806Srpaulo if (param == NULL) 8577281806Srpaulo return -1; 8578281806Srpaulo param += 8; 8579281806Srpaulo 8580281806Srpaulo len = os_strlen(param); 8581281806Srpaulo if (len & 1) 8582281806Srpaulo return -1; 8583281806Srpaulo len /= 2; 8584281806Srpaulo 8585281806Srpaulo buf = os_malloc(len); 8586281806Srpaulo if (buf == NULL) 8587281806Srpaulo return -1; 8588281806Srpaulo 8589281806Srpaulo if (hexstr2bin(param, buf, len) < 0) { 8590281806Srpaulo os_free(buf); 8591281806Srpaulo return -1; 8592281806Srpaulo } 8593281806Srpaulo 8594281806Srpaulo res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid, 8595281806Srpaulo buf, len, wait_time, 8596281806Srpaulo wpas_ctrl_iface_mgmt_tx_cb, no_cck); 8597281806Srpaulo os_free(buf); 8598281806Srpaulo return res; 8599281806Srpaulo} 8600281806Srpaulo 8601281806Srpaulo 8602281806Srpaulostatic void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) 8603281806Srpaulo{ 8604281806Srpaulo wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting"); 8605281806Srpaulo offchannel_send_action_done(wpa_s); 8606281806Srpaulo} 8607281806Srpaulo 8608281806Srpaulo 8609337817Scystatic int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, 8610337817Scy char *cmd) 8611337817Scy{ 8612337817Scy char *pos, *param; 8613337817Scy size_t len; 8614337817Scy u8 *buf; 8615337817Scy int freq = 0, datarate = 0, ssi_signal = 0; 8616337817Scy union wpa_event_data event; 8617337817Scy 8618337817Scy if (!wpa_s->ext_mgmt_frame_handling) 8619337817Scy return -1; 8620337817Scy 8621337817Scy /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */ 8622337817Scy 8623337817Scy wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd); 8624337817Scy 8625337817Scy pos = cmd; 8626337817Scy param = os_strstr(pos, "freq="); 8627337817Scy if (param) { 8628337817Scy param += 5; 8629337817Scy freq = atoi(param); 8630337817Scy } 8631337817Scy 8632337817Scy param = os_strstr(pos, " datarate="); 8633337817Scy if (param) { 8634337817Scy param += 10; 8635337817Scy datarate = atoi(param); 8636337817Scy } 8637337817Scy 8638337817Scy param = os_strstr(pos, " ssi_signal="); 8639337817Scy if (param) { 8640337817Scy param += 12; 8641337817Scy ssi_signal = atoi(param); 8642337817Scy } 8643337817Scy 8644337817Scy param = os_strstr(pos, " frame="); 8645337817Scy if (param == NULL) 8646337817Scy return -1; 8647337817Scy param += 7; 8648337817Scy 8649337817Scy len = os_strlen(param); 8650337817Scy if (len & 1) 8651337817Scy return -1; 8652337817Scy len /= 2; 8653337817Scy 8654337817Scy buf = os_malloc(len); 8655337817Scy if (buf == NULL) 8656337817Scy return -1; 8657337817Scy 8658337817Scy if (hexstr2bin(param, buf, len) < 0) { 8659337817Scy os_free(buf); 8660337817Scy return -1; 8661337817Scy } 8662337817Scy 8663337817Scy os_memset(&event, 0, sizeof(event)); 8664337817Scy event.rx_mgmt.freq = freq; 8665337817Scy event.rx_mgmt.frame = buf; 8666337817Scy event.rx_mgmt.frame_len = len; 8667337817Scy event.rx_mgmt.ssi_signal = ssi_signal; 8668337817Scy event.rx_mgmt.datarate = datarate; 8669337817Scy wpa_s->ext_mgmt_frame_handling = 0; 8670337817Scy wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event); 8671337817Scy wpa_s->ext_mgmt_frame_handling = 1; 8672337817Scy 8673337817Scy os_free(buf); 8674337817Scy 8675337817Scy return 0; 8676337817Scy} 8677337817Scy 8678337817Scy 8679346981Scystatic int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s, 8680346981Scy char *param) 8681346981Scy{ 8682346981Scy struct wpa_scan_res *res; 8683346981Scy struct os_reltime now; 8684346981Scy char *pos, *end; 8685346981Scy int ret = -1; 8686346981Scy 8687346981Scy if (!param) 8688346981Scy return -1; 8689346981Scy 8690346981Scy if (os_strcmp(param, "START") == 0) { 8691346981Scy wpa_bss_update_start(wpa_s); 8692346981Scy return 0; 8693346981Scy } 8694346981Scy 8695346981Scy if (os_strcmp(param, "END") == 0) { 8696346981Scy wpa_bss_update_end(wpa_s, NULL, 1); 8697346981Scy return 0; 8698346981Scy } 8699346981Scy 8700346981Scy if (os_strncmp(param, "BSS ", 4) != 0) 8701346981Scy return -1; 8702346981Scy param += 3; 8703346981Scy 8704346981Scy res = os_zalloc(sizeof(*res) + os_strlen(param) / 2); 8705346981Scy if (!res) 8706346981Scy return -1; 8707346981Scy 8708346981Scy pos = os_strstr(param, " flags="); 8709346981Scy if (pos) 8710346981Scy res->flags = strtol(pos + 7, NULL, 16); 8711346981Scy 8712346981Scy pos = os_strstr(param, " bssid="); 8713346981Scy if (pos && hwaddr_aton(pos + 7, res->bssid)) 8714346981Scy goto fail; 8715346981Scy 8716346981Scy pos = os_strstr(param, " freq="); 8717346981Scy if (pos) 8718346981Scy res->freq = atoi(pos + 6); 8719346981Scy 8720346981Scy pos = os_strstr(param, " beacon_int="); 8721346981Scy if (pos) 8722346981Scy res->beacon_int = atoi(pos + 12); 8723346981Scy 8724346981Scy pos = os_strstr(param, " caps="); 8725346981Scy if (pos) 8726346981Scy res->caps = strtol(pos + 6, NULL, 16); 8727346981Scy 8728346981Scy pos = os_strstr(param, " qual="); 8729346981Scy if (pos) 8730346981Scy res->qual = atoi(pos + 6); 8731346981Scy 8732346981Scy pos = os_strstr(param, " noise="); 8733346981Scy if (pos) 8734346981Scy res->noise = atoi(pos + 7); 8735346981Scy 8736346981Scy pos = os_strstr(param, " level="); 8737346981Scy if (pos) 8738346981Scy res->level = atoi(pos + 7); 8739346981Scy 8740346981Scy pos = os_strstr(param, " tsf="); 8741346981Scy if (pos) 8742346981Scy res->tsf = strtoll(pos + 5, NULL, 16); 8743346981Scy 8744346981Scy pos = os_strstr(param, " age="); 8745346981Scy if (pos) 8746346981Scy res->age = atoi(pos + 5); 8747346981Scy 8748346981Scy pos = os_strstr(param, " est_throughput="); 8749346981Scy if (pos) 8750346981Scy res->est_throughput = atoi(pos + 16); 8751346981Scy 8752346981Scy pos = os_strstr(param, " snr="); 8753346981Scy if (pos) 8754346981Scy res->snr = atoi(pos + 5); 8755346981Scy 8756346981Scy pos = os_strstr(param, " parent_tsf="); 8757346981Scy if (pos) 8758346981Scy res->parent_tsf = strtoll(pos + 7, NULL, 16); 8759346981Scy 8760346981Scy pos = os_strstr(param, " tsf_bssid="); 8761346981Scy if (pos && hwaddr_aton(pos + 11, res->tsf_bssid)) 8762346981Scy goto fail; 8763346981Scy 8764346981Scy pos = os_strstr(param, " ie="); 8765346981Scy if (pos) { 8766346981Scy pos += 4; 8767346981Scy end = os_strchr(pos, ' '); 8768346981Scy if (!end) 8769346981Scy end = pos + os_strlen(pos); 8770346981Scy res->ie_len = (end - pos) / 2; 8771346981Scy if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len)) 8772346981Scy goto fail; 8773346981Scy } 8774346981Scy 8775346981Scy pos = os_strstr(param, " beacon_ie="); 8776346981Scy if (pos) { 8777346981Scy pos += 11; 8778346981Scy end = os_strchr(pos, ' '); 8779346981Scy if (!end) 8780346981Scy end = pos + os_strlen(pos); 8781346981Scy res->beacon_ie_len = (end - pos) / 2; 8782346981Scy if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len, 8783346981Scy res->beacon_ie_len)) 8784346981Scy goto fail; 8785346981Scy } 8786346981Scy 8787346981Scy os_get_reltime(&now); 8788346981Scy wpa_bss_update_scan_res(wpa_s, res, &now); 8789346981Scy ret = 0; 8790346981Scyfail: 8791346981Scy os_free(res); 8792346981Scy 8793346981Scy return ret; 8794346981Scy} 8795346981Scy 8796346981Scy 8797281806Srpaulostatic int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) 8798281806Srpaulo{ 8799281806Srpaulo char *pos, *param; 8800281806Srpaulo union wpa_event_data event; 8801281806Srpaulo enum wpa_event_type ev; 8802281806Srpaulo 8803281806Srpaulo /* <event name> [parameters..] */ 8804281806Srpaulo 8805281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd); 8806281806Srpaulo 8807281806Srpaulo pos = cmd; 8808281806Srpaulo param = os_strchr(pos, ' '); 8809281806Srpaulo if (param) 8810281806Srpaulo *param++ = '\0'; 8811281806Srpaulo 8812281806Srpaulo os_memset(&event, 0, sizeof(event)); 8813281806Srpaulo 8814281806Srpaulo if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) { 8815281806Srpaulo ev = EVENT_INTERFACE_ENABLED; 8816281806Srpaulo } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) { 8817281806Srpaulo ev = EVENT_INTERFACE_DISABLED; 8818281806Srpaulo } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) { 8819281806Srpaulo ev = EVENT_AVOID_FREQUENCIES; 8820281806Srpaulo if (param == NULL) 8821281806Srpaulo param = ""; 8822281806Srpaulo if (freq_range_list_parse(&event.freq_range, param) < 0) 8823281806Srpaulo return -1; 8824281806Srpaulo wpa_supplicant_event(wpa_s, ev, &event); 8825281806Srpaulo os_free(event.freq_range.range); 8826281806Srpaulo return 0; 8827346981Scy } else if (os_strcmp(cmd, "SCAN_RES") == 0) { 8828346981Scy return wpas_ctrl_iface_driver_scan_res(wpa_s, param); 8829281806Srpaulo } else { 8830281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", 8831281806Srpaulo cmd); 8832281806Srpaulo return -1; 8833281806Srpaulo } 8834281806Srpaulo 8835281806Srpaulo wpa_supplicant_event(wpa_s, ev, &event); 8836281806Srpaulo 8837281806Srpaulo return 0; 8838281806Srpaulo} 8839281806Srpaulo 8840281806Srpaulo 8841281806Srpaulostatic int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd) 8842281806Srpaulo{ 8843281806Srpaulo char *pos; 8844281806Srpaulo u8 src[ETH_ALEN], *buf; 8845281806Srpaulo int used; 8846281806Srpaulo size_t len; 8847281806Srpaulo 8848281806Srpaulo wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); 8849281806Srpaulo 8850281806Srpaulo pos = cmd; 8851281806Srpaulo used = hwaddr_aton2(pos, src); 8852281806Srpaulo if (used < 0) 8853281806Srpaulo return -1; 8854281806Srpaulo pos += used; 8855281806Srpaulo while (*pos == ' ') 8856281806Srpaulo pos++; 8857281806Srpaulo 8858281806Srpaulo len = os_strlen(pos); 8859281806Srpaulo if (len & 1) 8860281806Srpaulo return -1; 8861281806Srpaulo len /= 2; 8862281806Srpaulo 8863281806Srpaulo buf = os_malloc(len); 8864281806Srpaulo if (buf == NULL) 8865281806Srpaulo return -1; 8866281806Srpaulo 8867281806Srpaulo if (hexstr2bin(pos, buf, len) < 0) { 8868281806Srpaulo os_free(buf); 8869281806Srpaulo return -1; 8870281806Srpaulo } 8871281806Srpaulo 8872281806Srpaulo wpa_supplicant_rx_eapol(wpa_s, src, buf, len); 8873281806Srpaulo os_free(buf); 8874281806Srpaulo 8875281806Srpaulo return 0; 8876281806Srpaulo} 8877281806Srpaulo 8878281806Srpaulo 8879281806Srpaulostatic u16 ipv4_hdr_checksum(const void *buf, size_t len) 8880281806Srpaulo{ 8881281806Srpaulo size_t i; 8882281806Srpaulo u32 sum = 0; 8883281806Srpaulo const u16 *pos = buf; 8884281806Srpaulo 8885281806Srpaulo for (i = 0; i < len / 2; i++) 8886281806Srpaulo sum += *pos++; 8887281806Srpaulo 8888281806Srpaulo while (sum >> 16) 8889281806Srpaulo sum = (sum & 0xffff) + (sum >> 16); 8890281806Srpaulo 8891281806Srpaulo return sum ^ 0xffff; 8892281806Srpaulo} 8893281806Srpaulo 8894281806Srpaulo 8895281806Srpaulo#define HWSIM_PACKETLEN 1500 8896281806Srpaulo#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) 8897281806Srpaulo 8898337817Scystatic void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, 8899337817Scy size_t len) 8900281806Srpaulo{ 8901281806Srpaulo struct wpa_supplicant *wpa_s = ctx; 8902281806Srpaulo const struct ether_header *eth; 8903289549Srpaulo struct iphdr ip; 8904281806Srpaulo const u8 *pos; 8905281806Srpaulo unsigned int i; 8906346981Scy char extra[30]; 8907281806Srpaulo 8908346981Scy if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) { 8909346981Scy wpa_printf(MSG_DEBUG, 8910346981Scy "test data: RX - ignore unexpected length %d", 8911346981Scy (int) len); 8912281806Srpaulo return; 8913346981Scy } 8914281806Srpaulo 8915281806Srpaulo eth = (const struct ether_header *) buf; 8916289549Srpaulo os_memcpy(&ip, eth + 1, sizeof(ip)); 8917289549Srpaulo pos = &buf[sizeof(*eth) + sizeof(ip)]; 8918281806Srpaulo 8919289549Srpaulo if (ip.ihl != 5 || ip.version != 4 || 8920346981Scy ntohs(ip.tot_len) > HWSIM_IP_LEN) { 8921346981Scy wpa_printf(MSG_DEBUG, 8922346981Scy "test data: RX - ignore unexpect IP header"); 8923281806Srpaulo return; 8924346981Scy } 8925281806Srpaulo 8926346981Scy for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) { 8927346981Scy if (*pos != (u8) i) { 8928346981Scy wpa_printf(MSG_DEBUG, 8929346981Scy "test data: RX - ignore mismatching payload"); 8930281806Srpaulo return; 8931346981Scy } 8932281806Srpaulo pos++; 8933281806Srpaulo } 8934346981Scy extra[0] = '\0'; 8935346981Scy if (ntohs(ip.tot_len) != HWSIM_IP_LEN) 8936346981Scy os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len)); 8937346981Scy wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s", 8938346981Scy MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra); 8939281806Srpaulo} 8940281806Srpaulo 8941281806Srpaulo 8942281806Srpaulostatic int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, 8943281806Srpaulo char *cmd) 8944281806Srpaulo{ 8945281806Srpaulo int enabled = atoi(cmd); 8946337817Scy char *pos; 8947337817Scy const char *ifname; 8948281806Srpaulo 8949281806Srpaulo if (!enabled) { 8950281806Srpaulo if (wpa_s->l2_test) { 8951281806Srpaulo l2_packet_deinit(wpa_s->l2_test); 8952281806Srpaulo wpa_s->l2_test = NULL; 8953281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled"); 8954281806Srpaulo } 8955281806Srpaulo return 0; 8956281806Srpaulo } 8957281806Srpaulo 8958281806Srpaulo if (wpa_s->l2_test) 8959281806Srpaulo return 0; 8960281806Srpaulo 8961337817Scy pos = os_strstr(cmd, " ifname="); 8962337817Scy if (pos) 8963337817Scy ifname = pos + 8; 8964337817Scy else 8965337817Scy ifname = wpa_s->ifname; 8966337817Scy 8967337817Scy wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr, 8968281806Srpaulo ETHERTYPE_IP, wpas_data_test_rx, 8969281806Srpaulo wpa_s, 1); 8970281806Srpaulo if (wpa_s->l2_test == NULL) 8971281806Srpaulo return -1; 8972281806Srpaulo 8973281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled"); 8974281806Srpaulo 8975281806Srpaulo return 0; 8976281806Srpaulo} 8977281806Srpaulo 8978281806Srpaulo 8979281806Srpaulostatic int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) 8980281806Srpaulo{ 8981281806Srpaulo u8 dst[ETH_ALEN], src[ETH_ALEN]; 8982346981Scy char *pos, *pos2; 8983281806Srpaulo int used; 8984281806Srpaulo long int val; 8985281806Srpaulo u8 tos; 8986289549Srpaulo u8 buf[2 + HWSIM_PACKETLEN]; 8987281806Srpaulo struct ether_header *eth; 8988281806Srpaulo struct iphdr *ip; 8989281806Srpaulo u8 *dpos; 8990281806Srpaulo unsigned int i; 8991346981Scy size_t send_len = HWSIM_IP_LEN; 8992281806Srpaulo 8993281806Srpaulo if (wpa_s->l2_test == NULL) 8994281806Srpaulo return -1; 8995281806Srpaulo 8996346981Scy /* format: <dst> <src> <tos> [len=<length>] */ 8997281806Srpaulo 8998281806Srpaulo pos = cmd; 8999281806Srpaulo used = hwaddr_aton2(pos, dst); 9000281806Srpaulo if (used < 0) 9001281806Srpaulo return -1; 9002281806Srpaulo pos += used; 9003281806Srpaulo while (*pos == ' ') 9004281806Srpaulo pos++; 9005281806Srpaulo used = hwaddr_aton2(pos, src); 9006281806Srpaulo if (used < 0) 9007281806Srpaulo return -1; 9008281806Srpaulo pos += used; 9009281806Srpaulo 9010346981Scy val = strtol(pos, &pos2, 0); 9011281806Srpaulo if (val < 0 || val > 0xff) 9012281806Srpaulo return -1; 9013281806Srpaulo tos = val; 9014281806Srpaulo 9015346981Scy pos = os_strstr(pos2, " len="); 9016346981Scy if (pos) { 9017346981Scy i = atoi(pos + 5); 9018346981Scy if (i < sizeof(*ip) || i > HWSIM_IP_LEN) 9019346981Scy return -1; 9020346981Scy send_len = i; 9021346981Scy } 9022346981Scy 9023289549Srpaulo eth = (struct ether_header *) &buf[2]; 9024281806Srpaulo os_memcpy(eth->ether_dhost, dst, ETH_ALEN); 9025281806Srpaulo os_memcpy(eth->ether_shost, src, ETH_ALEN); 9026281806Srpaulo eth->ether_type = htons(ETHERTYPE_IP); 9027281806Srpaulo ip = (struct iphdr *) (eth + 1); 9028281806Srpaulo os_memset(ip, 0, sizeof(*ip)); 9029281806Srpaulo ip->ihl = 5; 9030281806Srpaulo ip->version = 4; 9031281806Srpaulo ip->ttl = 64; 9032281806Srpaulo ip->tos = tos; 9033346981Scy ip->tot_len = htons(send_len); 9034281806Srpaulo ip->protocol = 1; 9035289549Srpaulo ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); 9036289549Srpaulo ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); 9037281806Srpaulo ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); 9038281806Srpaulo dpos = (u8 *) (ip + 1); 9039346981Scy for (i = 0; i < send_len - sizeof(*ip); i++) 9040281806Srpaulo *dpos++ = i; 9041281806Srpaulo 9042289549Srpaulo if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2], 9043346981Scy sizeof(struct ether_header) + send_len) < 0) 9044281806Srpaulo return -1; 9045281806Srpaulo 9046281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR 9047281806Srpaulo " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos); 9048281806Srpaulo 9049281806Srpaulo return 0; 9050281806Srpaulo} 9051281806Srpaulo 9052281806Srpaulo 9053281806Srpaulostatic int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s, 9054281806Srpaulo char *cmd) 9055281806Srpaulo{ 9056281806Srpaulo u8 *buf; 9057281806Srpaulo struct ether_header *eth; 9058281806Srpaulo struct l2_packet_data *l2 = NULL; 9059281806Srpaulo size_t len; 9060281806Srpaulo u16 ethertype; 9061281806Srpaulo int res = -1; 9062281806Srpaulo 9063281806Srpaulo len = os_strlen(cmd); 9064281806Srpaulo if (len & 1 || len < ETH_HLEN * 2) 9065281806Srpaulo return -1; 9066281806Srpaulo len /= 2; 9067281806Srpaulo 9068281806Srpaulo buf = os_malloc(len); 9069281806Srpaulo if (buf == NULL) 9070281806Srpaulo return -1; 9071281806Srpaulo 9072281806Srpaulo if (hexstr2bin(cmd, buf, len) < 0) 9073281806Srpaulo goto done; 9074281806Srpaulo 9075281806Srpaulo eth = (struct ether_header *) buf; 9076281806Srpaulo ethertype = ntohs(eth->ether_type); 9077281806Srpaulo 9078281806Srpaulo l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype, 9079281806Srpaulo wpas_data_test_rx, wpa_s, 1); 9080281806Srpaulo if (l2 == NULL) 9081281806Srpaulo goto done; 9082281806Srpaulo 9083281806Srpaulo res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len); 9084281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res); 9085281806Srpaulodone: 9086281806Srpaulo if (l2) 9087281806Srpaulo l2_packet_deinit(l2); 9088281806Srpaulo os_free(buf); 9089281806Srpaulo 9090281806Srpaulo return res < 0 ? -1 : 0; 9091281806Srpaulo} 9092281806Srpaulo 9093281806Srpaulo 9094281806Srpaulostatic int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd) 9095281806Srpaulo{ 9096281806Srpaulo#ifdef WPA_TRACE_BFD 9097281806Srpaulo char *pos; 9098281806Srpaulo 9099281806Srpaulo wpa_trace_fail_after = atoi(cmd); 9100281806Srpaulo pos = os_strchr(cmd, ':'); 9101281806Srpaulo if (pos) { 9102281806Srpaulo pos++; 9103281806Srpaulo os_strlcpy(wpa_trace_fail_func, pos, 9104281806Srpaulo sizeof(wpa_trace_fail_func)); 9105281806Srpaulo } else { 9106281806Srpaulo wpa_trace_fail_after = 0; 9107281806Srpaulo } 9108281806Srpaulo return 0; 9109281806Srpaulo#else /* WPA_TRACE_BFD */ 9110281806Srpaulo return -1; 9111281806Srpaulo#endif /* WPA_TRACE_BFD */ 9112281806Srpaulo} 9113281806Srpaulo 9114281806Srpaulo 9115281806Srpaulostatic int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, 9116281806Srpaulo char *buf, size_t buflen) 9117281806Srpaulo{ 9118281806Srpaulo#ifdef WPA_TRACE_BFD 9119281806Srpaulo return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, 9120281806Srpaulo wpa_trace_fail_func); 9121281806Srpaulo#else /* WPA_TRACE_BFD */ 9122281806Srpaulo return -1; 9123281806Srpaulo#endif /* WPA_TRACE_BFD */ 9124281806Srpaulo} 9125281806Srpaulo 9126289549Srpaulo 9127289549Srpaulostatic int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) 9128289549Srpaulo{ 9129289549Srpaulo#ifdef WPA_TRACE_BFD 9130289549Srpaulo char *pos; 9131289549Srpaulo 9132289549Srpaulo wpa_trace_test_fail_after = atoi(cmd); 9133289549Srpaulo pos = os_strchr(cmd, ':'); 9134289549Srpaulo if (pos) { 9135289549Srpaulo pos++; 9136289549Srpaulo os_strlcpy(wpa_trace_test_fail_func, pos, 9137289549Srpaulo sizeof(wpa_trace_test_fail_func)); 9138289549Srpaulo } else { 9139289549Srpaulo wpa_trace_test_fail_after = 0; 9140289549Srpaulo } 9141289549Srpaulo return 0; 9142289549Srpaulo#else /* WPA_TRACE_BFD */ 9143289549Srpaulo return -1; 9144289549Srpaulo#endif /* WPA_TRACE_BFD */ 9145289549Srpaulo} 9146289549Srpaulo 9147289549Srpaulo 9148289549Srpaulostatic int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, 9149289549Srpaulo char *buf, size_t buflen) 9150289549Srpaulo{ 9151289549Srpaulo#ifdef WPA_TRACE_BFD 9152289549Srpaulo return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, 9153289549Srpaulo wpa_trace_test_fail_func); 9154289549Srpaulo#else /* WPA_TRACE_BFD */ 9155289549Srpaulo return -1; 9156289549Srpaulo#endif /* WPA_TRACE_BFD */ 9157289549Srpaulo} 9158289549Srpaulo 9159281806Srpaulo 9160337817Scystatic void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx) 9161281806Srpaulo{ 9162337817Scy struct wpa_supplicant *wpa_s = eloop_ctx; 9163337817Scy int i, count = (intptr_t) timeout_ctx; 9164281806Srpaulo 9165337817Scy wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages", 9166337817Scy count); 9167337817Scy for (i = 0; i < count; i++) { 9168337817Scy wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d", 9169337817Scy i + 1, count); 9170337817Scy } 9171337817Scy} 9172281806Srpaulo 9173281806Srpaulo 9174337817Scystatic int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) 9175337817Scy{ 9176337817Scy int count; 9177281806Srpaulo 9178337817Scy count = atoi(cmd); 9179337817Scy if (count <= 0) 9180337817Scy return -1; 9181337817Scy 9182337817Scy return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s, 9183337817Scy (void *) (intptr_t) count); 9184281806Srpaulo} 9185281806Srpaulo 9186281806Srpaulo 9187337817Scystatic int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, 9188337817Scy const char *cmd) 9189281806Srpaulo{ 9190337817Scy struct wpabuf *buf; 9191337817Scy size_t len; 9192337817Scy 9193337817Scy len = os_strlen(cmd); 9194337817Scy if (len & 1) 9195337817Scy return -1; 9196337817Scy len /= 2; 9197337817Scy 9198337817Scy if (len == 0) { 9199337817Scy buf = NULL; 9200337817Scy } else { 9201337817Scy buf = wpabuf_alloc(len); 9202337817Scy if (buf == NULL) 9203337817Scy return -1; 9204337817Scy 9205337817Scy if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { 9206337817Scy wpabuf_free(buf); 9207337817Scy return -1; 9208337817Scy } 9209281806Srpaulo } 9210337817Scy 9211337817Scy wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); 9212337817Scy return 0; 9213281806Srpaulo} 9214281806Srpaulo 9215346981Scy 9216346981Scystatic int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) 9217346981Scy{ 9218346981Scy u8 zero[WPA_TK_MAX_LEN]; 9219346981Scy 9220346981Scy if (wpa_s->last_tk_alg == WPA_ALG_NONE) 9221346981Scy return -1; 9222346981Scy 9223346981Scy wpa_printf(MSG_INFO, "TESTING: Reset PN"); 9224346981Scy os_memset(zero, 0, sizeof(zero)); 9225346981Scy 9226346981Scy /* First, use a zero key to avoid any possible duplicate key avoidance 9227346981Scy * in the driver. */ 9228346981Scy if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, 9229346981Scy wpa_s->last_tk_key_idx, 1, zero, 6, 9230346981Scy zero, wpa_s->last_tk_len) < 0) 9231346981Scy return -1; 9232346981Scy 9233346981Scy /* Set the previously configured key to reset its TSC/RSC */ 9234346981Scy return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, 9235346981Scy wpa_s->last_tk_key_idx, 1, zero, 6, 9236346981Scy wpa_s->last_tk, wpa_s->last_tk_len); 9237346981Scy} 9238346981Scy 9239346981Scy 9240346981Scystatic int wpas_ctrl_key_request(struct wpa_supplicant *wpa_s, const char *cmd) 9241346981Scy{ 9242346981Scy const char *pos = cmd; 9243346981Scy int error, pairwise; 9244346981Scy 9245346981Scy error = atoi(pos); 9246346981Scy pos = os_strchr(pos, ' '); 9247346981Scy if (!pos) 9248346981Scy return -1; 9249346981Scy pairwise = atoi(pos); 9250346981Scy wpa_sm_key_request(wpa_s->wpa, error, pairwise); 9251346981Scy return 0; 9252346981Scy} 9253346981Scy 9254346981Scy 9255346981Scystatic int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s) 9256346981Scy{ 9257346981Scy#ifdef CONFIG_SME 9258346981Scy struct wpa_driver_associate_params params; 9259346981Scy int ret; 9260346981Scy 9261346981Scy os_memset(¶ms, 0, sizeof(params)); 9262346981Scy params.bssid = wpa_s->bssid; 9263346981Scy params.ssid = wpa_s->sme.ssid; 9264346981Scy params.ssid_len = wpa_s->sme.ssid_len; 9265346981Scy params.freq.freq = wpa_s->sme.freq; 9266346981Scy if (wpa_s->last_assoc_req_wpa_ie) { 9267346981Scy params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie); 9268346981Scy params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie); 9269346981Scy } 9270346981Scy params.pairwise_suite = wpa_s->pairwise_cipher; 9271346981Scy params.group_suite = wpa_s->group_cipher; 9272346981Scy params.mgmt_group_suite = wpa_s->mgmt_group_cipher; 9273346981Scy params.key_mgmt_suite = wpa_s->key_mgmt; 9274346981Scy params.wpa_proto = wpa_s->wpa_proto; 9275346981Scy params.mgmt_frame_protection = wpa_s->sme.mfp; 9276346981Scy params.rrm_used = wpa_s->rrm.rrm_used; 9277346981Scy if (wpa_s->sme.prev_bssid_set) 9278346981Scy params.prev_bssid = wpa_s->sme.prev_bssid; 9279346981Scy wpa_printf(MSG_INFO, "TESTING: Resend association request"); 9280346981Scy ret = wpa_drv_associate(wpa_s, ¶ms); 9281346981Scy wpa_s->testing_resend_assoc = 1; 9282346981Scy return ret; 9283346981Scy#else /* CONFIG_SME */ 9284346981Scy return -1; 9285346981Scy#endif /* CONFIG_SME */ 9286346981Scy} 9287346981Scy 9288337817Scy#endif /* CONFIG_TESTING_OPTIONS */ 9289281806Srpaulo 9290337817Scy 9291281806Srpaulostatic int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) 9292281806Srpaulo{ 9293281806Srpaulo char *pos = cmd; 9294281806Srpaulo int frame; 9295281806Srpaulo size_t len; 9296281806Srpaulo struct wpabuf *buf; 9297281806Srpaulo struct ieee802_11_elems elems; 9298281806Srpaulo 9299281806Srpaulo frame = atoi(pos); 9300281806Srpaulo if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 9301281806Srpaulo return -1; 9302337817Scy wpa_s = wpas_vendor_elem(wpa_s, frame); 9303281806Srpaulo 9304281806Srpaulo pos = os_strchr(pos, ' '); 9305281806Srpaulo if (pos == NULL) 9306281806Srpaulo return -1; 9307281806Srpaulo pos++; 9308281806Srpaulo 9309281806Srpaulo len = os_strlen(pos); 9310281806Srpaulo if (len == 0) 9311281806Srpaulo return 0; 9312281806Srpaulo if (len & 1) 9313281806Srpaulo return -1; 9314281806Srpaulo len /= 2; 9315281806Srpaulo 9316281806Srpaulo buf = wpabuf_alloc(len); 9317281806Srpaulo if (buf == NULL) 9318281806Srpaulo return -1; 9319281806Srpaulo 9320281806Srpaulo if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 9321281806Srpaulo wpabuf_free(buf); 9322281806Srpaulo return -1; 9323281806Srpaulo } 9324281806Srpaulo 9325281806Srpaulo if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) == 9326281806Srpaulo ParseFailed) { 9327281806Srpaulo wpabuf_free(buf); 9328281806Srpaulo return -1; 9329281806Srpaulo } 9330281806Srpaulo 9331281806Srpaulo if (wpa_s->vendor_elem[frame] == NULL) { 9332281806Srpaulo wpa_s->vendor_elem[frame] = buf; 9333337817Scy wpas_vendor_elem_update(wpa_s); 9334281806Srpaulo return 0; 9335281806Srpaulo } 9336281806Srpaulo 9337281806Srpaulo if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) { 9338281806Srpaulo wpabuf_free(buf); 9339281806Srpaulo return -1; 9340281806Srpaulo } 9341281806Srpaulo 9342281806Srpaulo wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); 9343281806Srpaulo wpabuf_free(buf); 9344337817Scy wpas_vendor_elem_update(wpa_s); 9345281806Srpaulo 9346281806Srpaulo return 0; 9347281806Srpaulo} 9348281806Srpaulo 9349281806Srpaulo 9350281806Srpaulostatic int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, 9351281806Srpaulo char *buf, size_t buflen) 9352281806Srpaulo{ 9353281806Srpaulo int frame = atoi(cmd); 9354281806Srpaulo 9355281806Srpaulo if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 9356281806Srpaulo return -1; 9357337817Scy wpa_s = wpas_vendor_elem(wpa_s, frame); 9358281806Srpaulo 9359281806Srpaulo if (wpa_s->vendor_elem[frame] == NULL) 9360281806Srpaulo return 0; 9361281806Srpaulo 9362281806Srpaulo return wpa_snprintf_hex(buf, buflen, 9363281806Srpaulo wpabuf_head_u8(wpa_s->vendor_elem[frame]), 9364281806Srpaulo wpabuf_len(wpa_s->vendor_elem[frame])); 9365281806Srpaulo} 9366281806Srpaulo 9367281806Srpaulo 9368281806Srpaulostatic int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) 9369281806Srpaulo{ 9370281806Srpaulo char *pos = cmd; 9371281806Srpaulo int frame; 9372281806Srpaulo size_t len; 9373281806Srpaulo u8 *buf; 9374281806Srpaulo struct ieee802_11_elems elems; 9375337817Scy int res; 9376281806Srpaulo 9377281806Srpaulo frame = atoi(pos); 9378281806Srpaulo if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 9379281806Srpaulo return -1; 9380337817Scy wpa_s = wpas_vendor_elem(wpa_s, frame); 9381281806Srpaulo 9382281806Srpaulo pos = os_strchr(pos, ' '); 9383281806Srpaulo if (pos == NULL) 9384281806Srpaulo return -1; 9385281806Srpaulo pos++; 9386281806Srpaulo 9387281806Srpaulo if (*pos == '*') { 9388281806Srpaulo wpabuf_free(wpa_s->vendor_elem[frame]); 9389281806Srpaulo wpa_s->vendor_elem[frame] = NULL; 9390337817Scy wpas_vendor_elem_update(wpa_s); 9391281806Srpaulo return 0; 9392281806Srpaulo } 9393281806Srpaulo 9394281806Srpaulo if (wpa_s->vendor_elem[frame] == NULL) 9395281806Srpaulo return -1; 9396281806Srpaulo 9397281806Srpaulo len = os_strlen(pos); 9398281806Srpaulo if (len == 0) 9399281806Srpaulo return 0; 9400281806Srpaulo if (len & 1) 9401281806Srpaulo return -1; 9402281806Srpaulo len /= 2; 9403281806Srpaulo 9404281806Srpaulo buf = os_malloc(len); 9405281806Srpaulo if (buf == NULL) 9406281806Srpaulo return -1; 9407281806Srpaulo 9408281806Srpaulo if (hexstr2bin(pos, buf, len) < 0) { 9409281806Srpaulo os_free(buf); 9410281806Srpaulo return -1; 9411281806Srpaulo } 9412281806Srpaulo 9413281806Srpaulo if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) { 9414281806Srpaulo os_free(buf); 9415281806Srpaulo return -1; 9416281806Srpaulo } 9417281806Srpaulo 9418337817Scy res = wpas_vendor_elem_remove(wpa_s, frame, buf, len); 9419281806Srpaulo os_free(buf); 9420337817Scy return res; 9421281806Srpaulo} 9422281806Srpaulo 9423281806Srpaulo 9424281806Srpaulostatic void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) 9425281806Srpaulo{ 9426281806Srpaulo struct wpa_supplicant *wpa_s = ctx; 9427337817Scy size_t len; 9428337817Scy const u8 *data; 9429281806Srpaulo 9430337817Scy /* 9431337817Scy * Neighbor Report element (IEEE P802.11-REVmc/D5.0) 9432337817Scy * BSSID[6] 9433337817Scy * BSSID Information[4] 9434337817Scy * Operating Class[1] 9435337817Scy * Channel Number[1] 9436337817Scy * PHY Type[1] 9437337817Scy * Optional Subelements[variable] 9438337817Scy */ 9439337817Scy#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1) 9440337817Scy 9441337817Scy if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) { 9442281806Srpaulo wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED); 9443337817Scy goto out; 9444281806Srpaulo } 9445337817Scy 9446337817Scy data = wpabuf_head_u8(neighbor_rep); 9447337817Scy len = wpabuf_len(neighbor_rep); 9448337817Scy 9449337817Scy while (len >= 2 + NR_IE_MIN_LEN) { 9450337817Scy const u8 *nr; 9451337817Scy char lci[256 * 2 + 1]; 9452337817Scy char civic[256 * 2 + 1]; 9453337817Scy u8 nr_len = data[1]; 9454337817Scy const u8 *pos = data, *end; 9455337817Scy 9456337817Scy if (pos[0] != WLAN_EID_NEIGHBOR_REPORT || 9457337817Scy nr_len < NR_IE_MIN_LEN) { 9458337817Scy wpa_printf(MSG_DEBUG, 9459337817Scy "CTRL: Invalid Neighbor Report element: id=%u len=%u", 9460337817Scy data[0], nr_len); 9461337817Scy goto out; 9462337817Scy } 9463337817Scy 9464337817Scy if (2U + nr_len > len) { 9465337817Scy wpa_printf(MSG_DEBUG, 9466337817Scy "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u", 9467337817Scy data[0], len, nr_len); 9468337817Scy goto out; 9469337817Scy } 9470337817Scy pos += 2; 9471337817Scy end = pos + nr_len; 9472337817Scy 9473337817Scy nr = pos; 9474337817Scy pos += NR_IE_MIN_LEN; 9475337817Scy 9476337817Scy lci[0] = '\0'; 9477337817Scy civic[0] = '\0'; 9478337817Scy while (end - pos > 2) { 9479337817Scy u8 s_id, s_len; 9480337817Scy 9481337817Scy s_id = *pos++; 9482337817Scy s_len = *pos++; 9483337817Scy if (s_len > end - pos) 9484337817Scy goto out; 9485337817Scy if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) { 9486337817Scy /* Measurement Token[1] */ 9487337817Scy /* Measurement Report Mode[1] */ 9488337817Scy /* Measurement Type[1] */ 9489337817Scy /* Measurement Report[variable] */ 9490337817Scy switch (pos[2]) { 9491337817Scy case MEASURE_TYPE_LCI: 9492337817Scy if (lci[0]) 9493337817Scy break; 9494337817Scy wpa_snprintf_hex(lci, sizeof(lci), 9495337817Scy pos, s_len); 9496337817Scy break; 9497337817Scy case MEASURE_TYPE_LOCATION_CIVIC: 9498337817Scy if (civic[0]) 9499337817Scy break; 9500337817Scy wpa_snprintf_hex(civic, sizeof(civic), 9501337817Scy pos, s_len); 9502337817Scy break; 9503337817Scy } 9504337817Scy } 9505337817Scy 9506337817Scy pos += s_len; 9507337817Scy } 9508337817Scy 9509337817Scy wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED 9510337817Scy "bssid=" MACSTR 9511337817Scy " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s", 9512337817Scy MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN), 9513337817Scy nr[ETH_ALEN + 4], nr[ETH_ALEN + 5], 9514337817Scy nr[ETH_ALEN + 6], 9515337817Scy lci[0] ? " lci=" : "", lci, 9516337817Scy civic[0] ? " civic=" : "", civic); 9517337817Scy 9518337817Scy data = end; 9519337817Scy len -= 2 + nr_len; 9520337817Scy } 9521337817Scy 9522337817Scyout: 9523337817Scy wpabuf_free(neighbor_rep); 9524281806Srpaulo} 9525281806Srpaulo 9526281806Srpaulo 9527337817Scystatic int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s, 9528337817Scy char *cmd) 9529281806Srpaulo{ 9530337817Scy struct wpa_ssid_value ssid, *ssid_p = NULL; 9531337817Scy int ret, lci = 0, civic = 0; 9532337817Scy char *ssid_s; 9533281806Srpaulo 9534337817Scy ssid_s = os_strstr(cmd, "ssid="); 9535337817Scy if (ssid_s) { 9536337817Scy if (ssid_parse(ssid_s + 5, &ssid)) { 9537337817Scy wpa_printf(MSG_ERROR, 9538337817Scy "CTRL: Send Neighbor Report: bad SSID"); 9539281806Srpaulo return -1; 9540337817Scy } 9541337817Scy 9542281806Srpaulo ssid_p = &ssid; 9543337817Scy 9544337817Scy /* 9545337817Scy * Move cmd after the SSID text that may include "lci" or 9546337817Scy * "civic". 9547337817Scy */ 9548337817Scy cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' '); 9549337817Scy if (cmd) 9550337817Scy cmd++; 9551337817Scy 9552281806Srpaulo } 9553281806Srpaulo 9554337817Scy if (cmd && os_strstr(cmd, "lci")) 9555337817Scy lci = 1; 9556337817Scy 9557337817Scy if (cmd && os_strstr(cmd, "civic")) 9558337817Scy civic = 1; 9559337817Scy 9560337817Scy ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic, 9561281806Srpaulo wpas_ctrl_neighbor_rep_cb, 9562281806Srpaulo wpa_s); 9563281806Srpaulo 9564281806Srpaulo return ret; 9565281806Srpaulo} 9566281806Srpaulo 9567281806Srpaulo 9568281806Srpaulostatic int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s) 9569281806Srpaulo{ 9570281806Srpaulo eapol_sm_erp_flush(wpa_s->eapol); 9571281806Srpaulo return 0; 9572281806Srpaulo} 9573281806Srpaulo 9574281806Srpaulo 9575281806Srpaulostatic int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, 9576281806Srpaulo char *cmd) 9577281806Srpaulo{ 9578281806Srpaulo char *token, *context = NULL; 9579281806Srpaulo unsigned int enable = ~0, type = 0; 9580281806Srpaulo u8 _addr[ETH_ALEN], _mask[ETH_ALEN]; 9581281806Srpaulo u8 *addr = NULL, *mask = NULL; 9582281806Srpaulo 9583281806Srpaulo while ((token = str_token(cmd, " ", &context))) { 9584281806Srpaulo if (os_strcasecmp(token, "scan") == 0) { 9585281806Srpaulo type |= MAC_ADDR_RAND_SCAN; 9586281806Srpaulo } else if (os_strcasecmp(token, "sched") == 0) { 9587281806Srpaulo type |= MAC_ADDR_RAND_SCHED_SCAN; 9588281806Srpaulo } else if (os_strcasecmp(token, "pno") == 0) { 9589281806Srpaulo type |= MAC_ADDR_RAND_PNO; 9590281806Srpaulo } else if (os_strcasecmp(token, "all") == 0) { 9591281806Srpaulo type = wpa_s->mac_addr_rand_supported; 9592281806Srpaulo } else if (os_strncasecmp(token, "enable=", 7) == 0) { 9593281806Srpaulo enable = atoi(token + 7); 9594281806Srpaulo } else if (os_strncasecmp(token, "addr=", 5) == 0) { 9595281806Srpaulo addr = _addr; 9596281806Srpaulo if (hwaddr_aton(token + 5, addr)) { 9597281806Srpaulo wpa_printf(MSG_INFO, 9598281806Srpaulo "CTRL: Invalid MAC address: %s", 9599281806Srpaulo token); 9600281806Srpaulo return -1; 9601281806Srpaulo } 9602281806Srpaulo } else if (os_strncasecmp(token, "mask=", 5) == 0) { 9603281806Srpaulo mask = _mask; 9604281806Srpaulo if (hwaddr_aton(token + 5, mask)) { 9605281806Srpaulo wpa_printf(MSG_INFO, 9606281806Srpaulo "CTRL: Invalid MAC address mask: %s", 9607281806Srpaulo token); 9608281806Srpaulo return -1; 9609281806Srpaulo } 9610281806Srpaulo } else { 9611281806Srpaulo wpa_printf(MSG_INFO, 9612281806Srpaulo "CTRL: Invalid MAC_RAND_SCAN parameter: %s", 9613281806Srpaulo token); 9614281806Srpaulo return -1; 9615281806Srpaulo } 9616281806Srpaulo } 9617281806Srpaulo 9618281806Srpaulo if (!type) { 9619281806Srpaulo wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified"); 9620281806Srpaulo return -1; 9621281806Srpaulo } 9622281806Srpaulo 9623281806Srpaulo if (enable > 1) { 9624281806Srpaulo wpa_printf(MSG_INFO, 9625281806Srpaulo "CTRL: MAC_RAND_SCAN enable=<0/1> not specified"); 9626281806Srpaulo return -1; 9627281806Srpaulo } 9628281806Srpaulo 9629351611Scy if (!enable) 9630351611Scy return wpas_disable_mac_addr_randomization(wpa_s, type); 9631281806Srpaulo 9632351611Scy return wpas_enable_mac_addr_randomization(wpa_s, type, addr, mask); 9633281806Srpaulo} 9634281806Srpaulo 9635281806Srpaulo 9636337817Scystatic int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s, 9637337817Scy char *buf, size_t buflen) 9638337817Scy{ 9639337817Scy size_t reply_len; 9640337817Scy 9641337817Scy reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen); 9642337817Scy#ifdef CONFIG_AP 9643337817Scy reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len], 9644337817Scy buflen - reply_len); 9645337817Scy#endif /* CONFIG_AP */ 9646337817Scy return reply_len; 9647337817Scy} 9648337817Scy 9649337817Scy 9650337817Scystatic void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) 9651337817Scy{ 9652337817Scy wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); 9653337817Scy#ifdef CONFIG_AP 9654337817Scy wpas_ap_pmksa_cache_flush(wpa_s); 9655337817Scy#endif /* CONFIG_AP */ 9656337817Scy} 9657337817Scy 9658337817Scy 9659346981Scy#ifdef CONFIG_PMKSA_CACHE_EXTERNAL 9660346981Scy 9661346981Scystatic int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s, 9662346981Scy const char *cmd, char *buf, size_t buflen) 9663346981Scy{ 9664346981Scy struct rsn_pmksa_cache_entry *entry; 9665346981Scy struct wpa_ssid *ssid; 9666346981Scy char *pos, *pos2, *end; 9667346981Scy int ret; 9668346981Scy struct os_reltime now; 9669346981Scy 9670346981Scy ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd)); 9671346981Scy if (!ssid) 9672346981Scy return -1; 9673346981Scy 9674346981Scy pos = buf; 9675346981Scy end = buf + buflen; 9676346981Scy 9677346981Scy os_get_reltime(&now); 9678346981Scy 9679346981Scy /* 9680346981Scy * Entry format: 9681346981Scy * <BSSID> <PMKID> <PMK> <reauth_time in seconds> 9682346981Scy * <expiration in seconds> <akmp> <opportunistic> 9683346981Scy * [FILS Cache Identifier] 9684346981Scy */ 9685346981Scy 9686346981Scy for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry; 9687346981Scy entry = entry->next) { 9688346981Scy if (entry->network_ctx != ssid) 9689346981Scy continue; 9690346981Scy 9691346981Scy pos2 = pos; 9692346981Scy ret = os_snprintf(pos2, end - pos2, MACSTR " ", 9693346981Scy MAC2STR(entry->aa)); 9694346981Scy if (os_snprintf_error(end - pos2, ret)) 9695346981Scy break; 9696346981Scy pos2 += ret; 9697346981Scy 9698346981Scy pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid, 9699346981Scy PMKID_LEN); 9700346981Scy 9701346981Scy ret = os_snprintf(pos2, end - pos2, " "); 9702346981Scy if (os_snprintf_error(end - pos2, ret)) 9703346981Scy break; 9704346981Scy pos2 += ret; 9705346981Scy 9706346981Scy pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk, 9707346981Scy entry->pmk_len); 9708346981Scy 9709346981Scy ret = os_snprintf(pos2, end - pos2, " %d %d %d %d", 9710346981Scy (int) (entry->reauth_time - now.sec), 9711346981Scy (int) (entry->expiration - now.sec), 9712346981Scy entry->akmp, 9713346981Scy entry->opportunistic); 9714346981Scy if (os_snprintf_error(end - pos2, ret)) 9715346981Scy break; 9716346981Scy pos2 += ret; 9717346981Scy 9718346981Scy if (entry->fils_cache_id_set) { 9719346981Scy ret = os_snprintf(pos2, end - pos2, " %02x%02x", 9720346981Scy entry->fils_cache_id[0], 9721346981Scy entry->fils_cache_id[1]); 9722346981Scy if (os_snprintf_error(end - pos2, ret)) 9723346981Scy break; 9724346981Scy pos2 += ret; 9725346981Scy } 9726346981Scy 9727346981Scy ret = os_snprintf(pos2, end - pos2, "\n"); 9728346981Scy if (os_snprintf_error(end - pos2, ret)) 9729346981Scy break; 9730346981Scy pos2 += ret; 9731346981Scy 9732346981Scy pos = pos2; 9733346981Scy } 9734346981Scy 9735346981Scy return pos - buf; 9736346981Scy} 9737346981Scy 9738346981Scy 9739346981Scystatic int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s, 9740346981Scy char *cmd) 9741346981Scy{ 9742346981Scy struct rsn_pmksa_cache_entry *entry; 9743346981Scy struct wpa_ssid *ssid; 9744346981Scy char *pos, *pos2; 9745346981Scy int ret = -1; 9746346981Scy struct os_reltime now; 9747346981Scy int reauth_time = 0, expiration = 0, i; 9748346981Scy 9749346981Scy /* 9750346981Scy * Entry format: 9751346981Scy * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> 9752346981Scy * <expiration in seconds> <akmp> <opportunistic> 9753346981Scy * [FILS Cache Identifier] 9754346981Scy */ 9755346981Scy 9756346981Scy ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd)); 9757346981Scy if (!ssid) 9758346981Scy return -1; 9759346981Scy 9760346981Scy pos = os_strchr(cmd, ' '); 9761346981Scy if (!pos) 9762346981Scy return -1; 9763346981Scy pos++; 9764346981Scy 9765346981Scy entry = os_zalloc(sizeof(*entry)); 9766346981Scy if (!entry) 9767346981Scy return -1; 9768346981Scy 9769346981Scy if (hwaddr_aton(pos, entry->aa)) 9770346981Scy goto fail; 9771346981Scy 9772346981Scy pos = os_strchr(pos, ' '); 9773346981Scy if (!pos) 9774346981Scy goto fail; 9775346981Scy pos++; 9776346981Scy 9777346981Scy if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0) 9778346981Scy goto fail; 9779346981Scy 9780346981Scy pos = os_strchr(pos, ' '); 9781346981Scy if (!pos) 9782346981Scy goto fail; 9783346981Scy pos++; 9784346981Scy 9785346981Scy pos2 = os_strchr(pos, ' '); 9786346981Scy if (!pos2) 9787346981Scy goto fail; 9788346981Scy entry->pmk_len = (pos2 - pos) / 2; 9789346981Scy if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX || 9790346981Scy hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0) 9791346981Scy goto fail; 9792346981Scy 9793346981Scy pos = os_strchr(pos, ' '); 9794346981Scy if (!pos) 9795346981Scy goto fail; 9796346981Scy pos++; 9797346981Scy 9798346981Scy if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration, 9799346981Scy &entry->akmp, &entry->opportunistic) != 4) 9800346981Scy goto fail; 9801346981Scy for (i = 0; i < 4; i++) { 9802346981Scy pos = os_strchr(pos, ' '); 9803346981Scy if (!pos) { 9804346981Scy if (i < 3) 9805346981Scy goto fail; 9806346981Scy break; 9807346981Scy } 9808346981Scy pos++; 9809346981Scy } 9810346981Scy if (pos) { 9811346981Scy if (hexstr2bin(pos, entry->fils_cache_id, 9812346981Scy FILS_CACHE_ID_LEN) < 0) 9813346981Scy goto fail; 9814346981Scy entry->fils_cache_id_set = 1; 9815346981Scy } 9816346981Scy os_get_reltime(&now); 9817346981Scy entry->expiration = now.sec + expiration; 9818346981Scy entry->reauth_time = now.sec + reauth_time; 9819346981Scy 9820346981Scy entry->network_ctx = ssid; 9821346981Scy 9822346981Scy wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); 9823346981Scy entry = NULL; 9824346981Scy ret = 0; 9825346981Scyfail: 9826346981Scy os_free(entry); 9827346981Scy return ret; 9828346981Scy} 9829346981Scy 9830346981Scy 9831346981Scy#ifdef CONFIG_MESH 9832346981Scy 9833346981Scystatic int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s, 9834346981Scy const char *cmd, char *buf, 9835346981Scy size_t buflen) 9836346981Scy{ 9837346981Scy u8 spa[ETH_ALEN]; 9838346981Scy 9839346981Scy if (!wpa_s->ifmsh) 9840346981Scy return -1; 9841346981Scy 9842346981Scy if (os_strcasecmp(cmd, "any") == 0) 9843346981Scy return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen); 9844346981Scy 9845346981Scy if (hwaddr_aton(cmd, spa)) 9846346981Scy return -1; 9847346981Scy 9848346981Scy return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen); 9849346981Scy} 9850346981Scy 9851346981Scy 9852346981Scystatic int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s, 9853346981Scy char *cmd) 9854346981Scy{ 9855346981Scy /* 9856346981Scy * We do not check mesh interface existance because PMKSA should be 9857346981Scy * stored before wpa_s->ifmsh creation to suppress commit message 9858346981Scy * creation. 9859346981Scy */ 9860346981Scy return wpas_ap_pmksa_cache_add_external(wpa_s, cmd); 9861346981Scy} 9862346981Scy 9863346981Scy#endif /* CONFIG_MESH */ 9864346981Scy#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ 9865346981Scy 9866346981Scy 9867346981Scy#ifdef CONFIG_FILS 9868346981Scystatic int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s, 9869346981Scy const char *cmd) 9870346981Scy{ 9871346981Scy struct fils_hlp_req *req; 9872346981Scy const char *pos; 9873346981Scy 9874346981Scy /* format: <dst> <packet starting from ethertype> */ 9875346981Scy 9876346981Scy req = os_zalloc(sizeof(*req)); 9877346981Scy if (!req) 9878346981Scy return -1; 9879346981Scy 9880346981Scy if (hwaddr_aton(cmd, req->dst)) 9881346981Scy goto fail; 9882346981Scy 9883346981Scy pos = os_strchr(cmd, ' '); 9884346981Scy if (!pos) 9885346981Scy goto fail; 9886346981Scy pos++; 9887346981Scy req->pkt = wpabuf_parse_bin(pos); 9888346981Scy if (!req->pkt) 9889346981Scy goto fail; 9890346981Scy 9891346981Scy dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list); 9892346981Scy return 0; 9893346981Scyfail: 9894346981Scy wpabuf_free(req->pkt); 9895346981Scy os_free(req); 9896346981Scy return -1; 9897346981Scy} 9898346981Scy#endif /* CONFIG_FILS */ 9899346981Scy 9900346981Scy 9901289549Srpaulostatic int wpas_ctrl_cmd_debug_level(const char *cmd) 9902289549Srpaulo{ 9903289549Srpaulo if (os_strcmp(cmd, "PING") == 0 || 9904289549Srpaulo os_strncmp(cmd, "BSS ", 4) == 0 || 9905289549Srpaulo os_strncmp(cmd, "GET_NETWORK ", 12) == 0 || 9906289549Srpaulo os_strncmp(cmd, "STATUS", 6) == 0 || 9907289549Srpaulo os_strncmp(cmd, "STA ", 4) == 0 || 9908289549Srpaulo os_strncmp(cmd, "STA-", 4) == 0) 9909289549Srpaulo return MSG_EXCESSIVE; 9910289549Srpaulo return MSG_DEBUG; 9911289549Srpaulo} 9912289549Srpaulo 9913289549Srpaulo 9914189251Ssamchar * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, 9915189251Ssam char *buf, size_t *resp_len) 9916189251Ssam{ 9917189251Ssam char *reply; 9918252726Srpaulo const int reply_size = 4096; 9919189251Ssam int reply_len; 9920189251Ssam 9921189251Ssam if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || 9922346981Scy os_strncmp(buf, "SET_NETWORK ", 12) == 0 || 9923346981Scy os_strncmp(buf, "PMKSA_ADD ", 10) == 0 || 9924346981Scy os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { 9925281806Srpaulo if (wpa_debug_show_keys) 9926281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 9927281806Srpaulo "Control interface command '%s'", buf); 9928281806Srpaulo else 9929281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 9930281806Srpaulo "Control interface command '%s [REMOVED]'", 9931281806Srpaulo os_strncmp(buf, WPA_CTRL_RSP, 9932281806Srpaulo os_strlen(WPA_CTRL_RSP)) == 0 ? 9933346981Scy WPA_CTRL_RSP : 9934346981Scy (os_strncmp(buf, "SET_NETWORK ", 12) == 0 ? 9935346981Scy "SET_NETWORK" : "key-add")); 9936281806Srpaulo } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || 9937281806Srpaulo os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) { 9938189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", 9939189251Ssam (const u8 *) buf, os_strlen(buf)); 9940189251Ssam } else { 9941289549Srpaulo int level = wpas_ctrl_cmd_debug_level(buf); 9942252726Srpaulo wpa_dbg(wpa_s, level, "Control interface command '%s'", buf); 9943189251Ssam } 9944189251Ssam 9945189251Ssam reply = os_malloc(reply_size); 9946189251Ssam if (reply == NULL) { 9947189251Ssam *resp_len = 1; 9948189251Ssam return NULL; 9949189251Ssam } 9950189251Ssam 9951189251Ssam os_memcpy(reply, "OK\n", 3); 9952189251Ssam reply_len = 3; 9953189251Ssam 9954189251Ssam if (os_strcmp(buf, "PING") == 0) { 9955189251Ssam os_memcpy(reply, "PONG\n", 5); 9956189251Ssam reply_len = 5; 9957252726Srpaulo } else if (os_strcmp(buf, "IFNAME") == 0) { 9958252726Srpaulo reply_len = os_strlen(wpa_s->ifname); 9959252726Srpaulo os_memcpy(reply, wpa_s->ifname, reply_len); 9960252726Srpaulo } else if (os_strncmp(buf, "RELOG", 5) == 0) { 9961252726Srpaulo if (wpa_debug_reopen_file() < 0) 9962252726Srpaulo reply_len = -1; 9963252726Srpaulo } else if (os_strncmp(buf, "NOTE ", 5) == 0) { 9964252726Srpaulo wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); 9965189251Ssam } else if (os_strcmp(buf, "MIB") == 0) { 9966189251Ssam reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); 9967189251Ssam if (reply_len >= 0) { 9968281806Srpaulo reply_len += eapol_sm_get_mib(wpa_s->eapol, 9969281806Srpaulo reply + reply_len, 9970281806Srpaulo reply_size - reply_len); 9971346981Scy#ifdef CONFIG_MACSEC 9972346981Scy reply_len += ieee802_1x_kay_get_mib( 9973346981Scy wpa_s->kay, reply + reply_len, 9974346981Scy reply_size - reply_len); 9975346981Scy#endif /* CONFIG_MACSEC */ 9976189251Ssam } 9977189251Ssam } else if (os_strncmp(buf, "STATUS", 6) == 0) { 9978189251Ssam reply_len = wpa_supplicant_ctrl_iface_status( 9979189251Ssam wpa_s, buf + 6, reply, reply_size); 9980189251Ssam } else if (os_strcmp(buf, "PMKSA") == 0) { 9981337817Scy reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); 9982281806Srpaulo } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { 9983337817Scy wpas_ctrl_iface_pmksa_flush(wpa_s); 9984346981Scy#ifdef CONFIG_PMKSA_CACHE_EXTERNAL 9985346981Scy } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) { 9986346981Scy reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10, 9987346981Scy reply, reply_size); 9988346981Scy } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) { 9989346981Scy if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0) 9990346981Scy reply_len = -1; 9991346981Scy#ifdef CONFIG_MESH 9992346981Scy } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) { 9993346981Scy reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15, 9994346981Scy reply, reply_size); 9995346981Scy } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { 9996346981Scy if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0) 9997346981Scy reply_len = -1; 9998346981Scy#endif /* CONFIG_MESH */ 9999346981Scy#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ 10000189251Ssam } else if (os_strncmp(buf, "SET ", 4) == 0) { 10001189251Ssam if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) 10002189251Ssam reply_len = -1; 10003281806Srpaulo } else if (os_strncmp(buf, "DUMP", 4) == 0) { 10004281806Srpaulo reply_len = wpa_config_dump_values(wpa_s->conf, 10005281806Srpaulo reply, reply_size); 10006252726Srpaulo } else if (os_strncmp(buf, "GET ", 4) == 0) { 10007252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4, 10008252726Srpaulo reply, reply_size); 10009189251Ssam } else if (os_strcmp(buf, "LOGON") == 0) { 10010189251Ssam eapol_sm_notify_logoff(wpa_s->eapol, FALSE); 10011189251Ssam } else if (os_strcmp(buf, "LOGOFF") == 0) { 10012189251Ssam eapol_sm_notify_logoff(wpa_s->eapol, TRUE); 10013189251Ssam } else if (os_strcmp(buf, "REASSOCIATE") == 0) { 10014252726Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) 10015252726Srpaulo reply_len = -1; 10016252726Srpaulo else 10017252726Srpaulo wpas_request_connection(wpa_s); 10018281806Srpaulo } else if (os_strcmp(buf, "REATTACH") == 0) { 10019281806Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED || 10020281806Srpaulo !wpa_s->current_ssid) 10021281806Srpaulo reply_len = -1; 10022281806Srpaulo else { 10023281806Srpaulo wpa_s->reattach = 1; 10024281806Srpaulo wpas_request_connection(wpa_s); 10025281806Srpaulo } 10026189251Ssam } else if (os_strcmp(buf, "RECONNECT") == 0) { 10027252726Srpaulo if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) 10028252726Srpaulo reply_len = -1; 10029252726Srpaulo else if (wpa_s->disconnected) 10030252726Srpaulo wpas_request_connection(wpa_s); 10031189251Ssam#ifdef IEEE8021X_EAPOL 10032189251Ssam } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { 10033189251Ssam if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) 10034189251Ssam reply_len = -1; 10035189251Ssam#endif /* IEEE8021X_EAPOL */ 10036189251Ssam#ifdef CONFIG_IEEE80211R 10037189251Ssam } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { 10038189251Ssam if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) 10039189251Ssam reply_len = -1; 10040189251Ssam#endif /* CONFIG_IEEE80211R */ 10041189251Ssam#ifdef CONFIG_WPS 10042189251Ssam } else if (os_strcmp(buf, "WPS_PBC") == 0) { 10043252726Srpaulo int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL); 10044252726Srpaulo if (res == -2) { 10045252726Srpaulo os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 10046252726Srpaulo reply_len = 17; 10047252726Srpaulo } else if (res) 10048189251Ssam reply_len = -1; 10049189251Ssam } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) { 10050252726Srpaulo int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8); 10051252726Srpaulo if (res == -2) { 10052252726Srpaulo os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 10053252726Srpaulo reply_len = 17; 10054252726Srpaulo } else if (res) 10055189251Ssam reply_len = -1; 10056189251Ssam } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 10057189251Ssam reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, 10058189251Ssam reply, 10059189251Ssam reply_size); 10060252726Srpaulo } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { 10061252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_wps_check_pin( 10062252726Srpaulo wpa_s, buf + 14, reply, reply_size); 10063252726Srpaulo } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { 10064252726Srpaulo if (wpas_wps_cancel(wpa_s)) 10065214734Srpaulo reply_len = -1; 10066252726Srpaulo#ifdef CONFIG_WPS_NFC 10067252726Srpaulo } else if (os_strcmp(buf, "WPS_NFC") == 0) { 10068252726Srpaulo if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL)) 10069252726Srpaulo reply_len = -1; 10070252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) { 10071252726Srpaulo if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8)) 10072252726Srpaulo reply_len = -1; 10073281806Srpaulo } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { 10074281806Srpaulo reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token( 10075281806Srpaulo wpa_s, buf + 21, reply, reply_size); 10076252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { 10077252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token( 10078252726Srpaulo wpa_s, buf + 14, reply, reply_size); 10079252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { 10080252726Srpaulo if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s, 10081252726Srpaulo buf + 17)) 10082252726Srpaulo reply_len = -1; 10083252726Srpaulo } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) { 10084252726Srpaulo reply_len = wpas_ctrl_nfc_get_handover_req( 10085252726Srpaulo wpa_s, buf + 21, reply, reply_size); 10086252726Srpaulo } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { 10087252726Srpaulo reply_len = wpas_ctrl_nfc_get_handover_sel( 10088252726Srpaulo wpa_s, buf + 21, reply, reply_size); 10089281806Srpaulo } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { 10090281806Srpaulo if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20)) 10091252726Srpaulo reply_len = -1; 10092252726Srpaulo#endif /* CONFIG_WPS_NFC */ 10093189251Ssam } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) { 10094189251Ssam if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) 10095189251Ssam reply_len = -1; 10096252726Srpaulo#ifdef CONFIG_AP 10097252726Srpaulo } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 10098252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin( 10099252726Srpaulo wpa_s, buf + 11, reply, reply_size); 10100252726Srpaulo#endif /* CONFIG_AP */ 10101214734Srpaulo#ifdef CONFIG_WPS_ER 10102214734Srpaulo } else if (os_strcmp(buf, "WPS_ER_START") == 0) { 10103252726Srpaulo if (wpas_wps_er_start(wpa_s, NULL)) 10104214734Srpaulo reply_len = -1; 10105252726Srpaulo } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) { 10106252726Srpaulo if (wpas_wps_er_start(wpa_s, buf + 13)) 10107252726Srpaulo reply_len = -1; 10108214734Srpaulo } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) { 10109281806Srpaulo wpas_wps_er_stop(wpa_s); 10110214734Srpaulo } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) { 10111214734Srpaulo if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11)) 10112214734Srpaulo reply_len = -1; 10113214734Srpaulo } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) { 10114252726Srpaulo int ret = wpas_wps_er_pbc(wpa_s, buf + 11); 10115252726Srpaulo if (ret == -2) { 10116252726Srpaulo os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 10117252726Srpaulo reply_len = 17; 10118252726Srpaulo } else if (ret == -3) { 10119252726Srpaulo os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18); 10120252726Srpaulo reply_len = 18; 10121252726Srpaulo } else if (ret == -4) { 10122252726Srpaulo os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20); 10123252726Srpaulo reply_len = 20; 10124252726Srpaulo } else if (ret) 10125214734Srpaulo reply_len = -1; 10126214734Srpaulo } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) { 10127214734Srpaulo if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13)) 10128214734Srpaulo reply_len = -1; 10129252726Srpaulo } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) { 10130252726Srpaulo if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s, 10131252726Srpaulo buf + 18)) 10132252726Srpaulo reply_len = -1; 10133252726Srpaulo } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) { 10134252726Srpaulo if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14)) 10135252726Srpaulo reply_len = -1; 10136252726Srpaulo#ifdef CONFIG_WPS_NFC 10137252726Srpaulo } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) { 10138252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( 10139252726Srpaulo wpa_s, buf + 24, reply, reply_size); 10140252726Srpaulo#endif /* CONFIG_WPS_NFC */ 10141214734Srpaulo#endif /* CONFIG_WPS_ER */ 10142189251Ssam#endif /* CONFIG_WPS */ 10143214734Srpaulo#ifdef CONFIG_IBSS_RSN 10144214734Srpaulo } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) { 10145214734Srpaulo if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) 10146214734Srpaulo reply_len = -1; 10147214734Srpaulo#endif /* CONFIG_IBSS_RSN */ 10148281806Srpaulo#ifdef CONFIG_MESH 10149281806Srpaulo } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) { 10150281806Srpaulo reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add( 10151281806Srpaulo wpa_s, buf + 19, reply, reply_size); 10152281806Srpaulo } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) { 10153281806Srpaulo reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add( 10154281806Srpaulo wpa_s, "", reply, reply_size); 10155281806Srpaulo } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) { 10156281806Srpaulo if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15)) 10157281806Srpaulo reply_len = -1; 10158281806Srpaulo } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) { 10159281806Srpaulo if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, 10160281806Srpaulo buf + 18)) 10161281806Srpaulo reply_len = -1; 10162337817Scy } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) { 10163337817Scy if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17)) 10164337817Scy reply_len = -1; 10165337817Scy } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) { 10166337817Scy if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14)) 10167337817Scy reply_len = -1; 10168351611Scy } else if (os_strncmp(buf, "MESH_LINK_PROBE ", 16) == 0) { 10169351611Scy if (wpa_supplicant_ctrl_iface_mesh_link_probe(wpa_s, buf + 16)) 10170351611Scy reply_len = -1; 10171281806Srpaulo#endif /* CONFIG_MESH */ 10172252726Srpaulo#ifdef CONFIG_P2P 10173252726Srpaulo } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { 10174281806Srpaulo if (p2p_ctrl_find(wpa_s, buf + 8)) 10175252726Srpaulo reply_len = -1; 10176252726Srpaulo } else if (os_strcmp(buf, "P2P_FIND") == 0) { 10177252726Srpaulo if (p2p_ctrl_find(wpa_s, "")) 10178252726Srpaulo reply_len = -1; 10179252726Srpaulo } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { 10180252726Srpaulo wpas_p2p_stop_find(wpa_s); 10181281806Srpaulo } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) { 10182281806Srpaulo if (p2p_ctrl_asp_provision(wpa_s, buf + 18)) 10183281806Srpaulo reply_len = -1; 10184281806Srpaulo } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) { 10185281806Srpaulo if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23)) 10186281806Srpaulo reply_len = -1; 10187252726Srpaulo } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { 10188252726Srpaulo reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, 10189252726Srpaulo reply_size); 10190252726Srpaulo } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) { 10191252726Srpaulo if (p2p_ctrl_listen(wpa_s, buf + 11)) 10192252726Srpaulo reply_len = -1; 10193252726Srpaulo } else if (os_strcmp(buf, "P2P_LISTEN") == 0) { 10194252726Srpaulo if (p2p_ctrl_listen(wpa_s, "")) 10195252726Srpaulo reply_len = -1; 10196252726Srpaulo } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) { 10197252726Srpaulo if (wpas_p2p_group_remove(wpa_s, buf + 17)) 10198252726Srpaulo reply_len = -1; 10199252726Srpaulo } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { 10200289549Srpaulo if (p2p_ctrl_group_add(wpa_s, "")) 10201252726Srpaulo reply_len = -1; 10202252726Srpaulo } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { 10203252726Srpaulo if (p2p_ctrl_group_add(wpa_s, buf + 14)) 10204252726Srpaulo reply_len = -1; 10205337817Scy } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) { 10206337817Scy reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply, 10207337817Scy reply_size); 10208252726Srpaulo } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { 10209252726Srpaulo if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) 10210252726Srpaulo reply_len = -1; 10211252726Srpaulo } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { 10212252726Srpaulo reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); 10213252726Srpaulo } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { 10214252726Srpaulo reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, 10215252726Srpaulo reply_size); 10216252726Srpaulo } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) { 10217252726Srpaulo if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0) 10218252726Srpaulo reply_len = -1; 10219252726Srpaulo } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) { 10220252726Srpaulo if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0) 10221252726Srpaulo reply_len = -1; 10222252726Srpaulo } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) { 10223252726Srpaulo wpas_p2p_sd_service_update(wpa_s); 10224252726Srpaulo } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) { 10225252726Srpaulo if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0) 10226252726Srpaulo reply_len = -1; 10227252726Srpaulo } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) { 10228252726Srpaulo wpas_p2p_service_flush(wpa_s); 10229252726Srpaulo } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) { 10230252726Srpaulo if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0) 10231252726Srpaulo reply_len = -1; 10232252726Srpaulo } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) { 10233252726Srpaulo if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0) 10234252726Srpaulo reply_len = -1; 10235281806Srpaulo } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) { 10236281806Srpaulo if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0) 10237281806Srpaulo reply_len = -1; 10238252726Srpaulo } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) { 10239252726Srpaulo if (p2p_ctrl_reject(wpa_s, buf + 11) < 0) 10240252726Srpaulo reply_len = -1; 10241252726Srpaulo } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) { 10242252726Srpaulo if (p2p_ctrl_invite(wpa_s, buf + 11) < 0) 10243252726Srpaulo reply_len = -1; 10244252726Srpaulo } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) { 10245252726Srpaulo reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply, 10246252726Srpaulo reply_size); 10247252726Srpaulo } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) { 10248252726Srpaulo if (p2p_ctrl_set(wpa_s, buf + 8) < 0) 10249252726Srpaulo reply_len = -1; 10250252726Srpaulo } else if (os_strcmp(buf, "P2P_FLUSH") == 0) { 10251281806Srpaulo p2p_ctrl_flush(wpa_s); 10252252726Srpaulo } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) { 10253252726Srpaulo if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0) 10254252726Srpaulo reply_len = -1; 10255252726Srpaulo } else if (os_strcmp(buf, "P2P_CANCEL") == 0) { 10256252726Srpaulo if (wpas_p2p_cancel(wpa_s)) 10257252726Srpaulo reply_len = -1; 10258252726Srpaulo } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) { 10259252726Srpaulo if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0) 10260252726Srpaulo reply_len = -1; 10261252726Srpaulo } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) { 10262252726Srpaulo if (p2p_ctrl_presence_req(wpa_s, "") < 0) 10263252726Srpaulo reply_len = -1; 10264252726Srpaulo } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) { 10265252726Srpaulo if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0) 10266252726Srpaulo reply_len = -1; 10267252726Srpaulo } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) { 10268252726Srpaulo if (p2p_ctrl_ext_listen(wpa_s, "") < 0) 10269252726Srpaulo reply_len = -1; 10270281806Srpaulo } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) { 10271281806Srpaulo if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0) 10272281806Srpaulo reply_len = -1; 10273337817Scy } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) { 10274337817Scy if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13)) 10275337817Scy reply_len = -1; 10276337817Scy } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) { 10277337817Scy if (wpas_p2p_lo_stop(wpa_s)) 10278337817Scy reply_len = -1; 10279252726Srpaulo#endif /* CONFIG_P2P */ 10280252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY 10281252726Srpaulo } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { 10282252726Srpaulo if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0) 10283252726Srpaulo reply_len = -1; 10284252726Srpaulo } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) { 10285252726Srpaulo reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16, 10286252726Srpaulo reply, reply_size); 10287252726Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 10288252726Srpaulo#ifdef CONFIG_INTERWORKING 10289252726Srpaulo } else if (os_strcmp(buf, "FETCH_ANQP") == 0) { 10290252726Srpaulo if (interworking_fetch_anqp(wpa_s) < 0) 10291252726Srpaulo reply_len = -1; 10292252726Srpaulo } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) { 10293252726Srpaulo interworking_stop_fetch_anqp(wpa_s); 10294281806Srpaulo } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) { 10295281806Srpaulo if (ctrl_interworking_select(wpa_s, NULL) < 0) 10296252726Srpaulo reply_len = -1; 10297281806Srpaulo } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) { 10298281806Srpaulo if (ctrl_interworking_select(wpa_s, buf + 20) < 0) 10299281806Srpaulo reply_len = -1; 10300252726Srpaulo } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { 10301281806Srpaulo if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0) 10302252726Srpaulo reply_len = -1; 10303281806Srpaulo } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) { 10304281806Srpaulo int id; 10305281806Srpaulo 10306281806Srpaulo id = ctrl_interworking_connect(wpa_s, buf + 25, 1); 10307281806Srpaulo if (id < 0) 10308281806Srpaulo reply_len = -1; 10309281806Srpaulo else { 10310281806Srpaulo reply_len = os_snprintf(reply, reply_size, "%d\n", id); 10311281806Srpaulo if (os_snprintf_error(reply_size, reply_len)) 10312281806Srpaulo reply_len = -1; 10313281806Srpaulo } 10314252726Srpaulo } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) { 10315252726Srpaulo if (get_anqp(wpa_s, buf + 9) < 0) 10316252726Srpaulo reply_len = -1; 10317252726Srpaulo } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) { 10318252726Srpaulo if (gas_request(wpa_s, buf + 12) < 0) 10319252726Srpaulo reply_len = -1; 10320252726Srpaulo } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) { 10321252726Srpaulo reply_len = gas_response_get(wpa_s, buf + 17, reply, 10322252726Srpaulo reply_size); 10323252726Srpaulo#endif /* CONFIG_INTERWORKING */ 10324252726Srpaulo#ifdef CONFIG_HS20 10325252726Srpaulo } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) { 10326252726Srpaulo if (get_hs20_anqp(wpa_s, buf + 14) < 0) 10327252726Srpaulo reply_len = -1; 10328252726Srpaulo } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) { 10329252726Srpaulo if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) 10330252726Srpaulo reply_len = -1; 10331281806Srpaulo } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { 10332337817Scy if (hs20_icon_request(wpa_s, buf + 18, 0) < 0) 10333281806Srpaulo reply_len = -1; 10334337817Scy } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) { 10335337817Scy if (hs20_icon_request(wpa_s, buf + 14, 1) < 0) 10336337817Scy reply_len = -1; 10337337817Scy } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) { 10338337817Scy reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size); 10339337817Scy } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) { 10340337817Scy if (del_hs20_icon(wpa_s, buf + 14) < 0) 10341337817Scy reply_len = -1; 10342281806Srpaulo } else if (os_strcmp(buf, "FETCH_OSU") == 0) { 10343337817Scy if (hs20_fetch_osu(wpa_s, 0) < 0) 10344281806Srpaulo reply_len = -1; 10345337817Scy } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) { 10346337817Scy if (hs20_fetch_osu(wpa_s, 1) < 0) 10347337817Scy reply_len = -1; 10348281806Srpaulo } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) { 10349281806Srpaulo hs20_cancel_fetch_osu(wpa_s); 10350252726Srpaulo#endif /* CONFIG_HS20 */ 10351189251Ssam } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) 10352189251Ssam { 10353189251Ssam if (wpa_supplicant_ctrl_iface_ctrl_rsp( 10354189251Ssam wpa_s, buf + os_strlen(WPA_CTRL_RSP))) 10355189251Ssam reply_len = -1; 10356281806Srpaulo else { 10357281806Srpaulo /* 10358281806Srpaulo * Notify response from timeout to allow the control 10359281806Srpaulo * interface response to be sent first. 10360281806Srpaulo */ 10361281806Srpaulo eloop_register_timeout(0, 0, wpas_ctrl_eapol_response, 10362281806Srpaulo wpa_s, NULL); 10363281806Srpaulo } 10364189251Ssam } else if (os_strcmp(buf, "RECONFIGURE") == 0) { 10365189251Ssam if (wpa_supplicant_reload_configuration(wpa_s)) 10366189251Ssam reply_len = -1; 10367189251Ssam } else if (os_strcmp(buf, "TERMINATE") == 0) { 10368214734Srpaulo wpa_supplicant_terminate_proc(wpa_s->global); 10369189251Ssam } else if (os_strncmp(buf, "BSSID ", 6) == 0) { 10370189251Ssam if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) 10371189251Ssam reply_len = -1; 10372252726Srpaulo } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) { 10373252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_blacklist( 10374252726Srpaulo wpa_s, buf + 9, reply, reply_size); 10375252726Srpaulo } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) { 10376252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_log_level( 10377252726Srpaulo wpa_s, buf + 9, reply, reply_size); 10378281806Srpaulo } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) { 10379281806Srpaulo reply_len = wpa_supplicant_ctrl_iface_list_networks( 10380281806Srpaulo wpa_s, buf + 14, reply, reply_size); 10381189251Ssam } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { 10382189251Ssam reply_len = wpa_supplicant_ctrl_iface_list_networks( 10383281806Srpaulo wpa_s, NULL, reply, reply_size); 10384189251Ssam } else if (os_strcmp(buf, "DISCONNECT") == 0) { 10385337817Scy wpas_request_disconnection(wpa_s); 10386189251Ssam } else if (os_strcmp(buf, "SCAN") == 0) { 10387281806Srpaulo wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); 10388281806Srpaulo } else if (os_strncmp(buf, "SCAN ", 5) == 0) { 10389281806Srpaulo wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); 10390189251Ssam } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { 10391189251Ssam reply_len = wpa_supplicant_ctrl_iface_scan_results( 10392189251Ssam wpa_s, reply, reply_size); 10393337817Scy } else if (os_strcmp(buf, "ABORT_SCAN") == 0) { 10394337817Scy if (wpas_abort_ongoing_scan(wpa_s) < 0) 10395337817Scy reply_len = -1; 10396189251Ssam } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { 10397189251Ssam if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) 10398189251Ssam reply_len = -1; 10399189251Ssam } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { 10400189251Ssam if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) 10401189251Ssam reply_len = -1; 10402189251Ssam } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { 10403189251Ssam if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) 10404189251Ssam reply_len = -1; 10405189251Ssam } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { 10406189251Ssam reply_len = wpa_supplicant_ctrl_iface_add_network( 10407189251Ssam wpa_s, reply, reply_size); 10408189251Ssam } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { 10409189251Ssam if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) 10410189251Ssam reply_len = -1; 10411189251Ssam } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { 10412189251Ssam if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) 10413189251Ssam reply_len = -1; 10414189251Ssam } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { 10415189251Ssam reply_len = wpa_supplicant_ctrl_iface_get_network( 10416189251Ssam wpa_s, buf + 12, reply, reply_size); 10417281806Srpaulo } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { 10418289549Srpaulo if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12, 10419289549Srpaulo wpa_s)) 10420281806Srpaulo reply_len = -1; 10421252726Srpaulo } else if (os_strcmp(buf, "LIST_CREDS") == 0) { 10422252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_list_creds( 10423252726Srpaulo wpa_s, reply, reply_size); 10424252726Srpaulo } else if (os_strcmp(buf, "ADD_CRED") == 0) { 10425252726Srpaulo reply_len = wpa_supplicant_ctrl_iface_add_cred( 10426252726Srpaulo wpa_s, reply, reply_size); 10427252726Srpaulo } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) { 10428252726Srpaulo if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12)) 10429252726Srpaulo reply_len = -1; 10430252726Srpaulo } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) { 10431252726Srpaulo if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9)) 10432252726Srpaulo reply_len = -1; 10433281806Srpaulo } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) { 10434281806Srpaulo reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9, 10435281806Srpaulo reply, 10436281806Srpaulo reply_size); 10437189251Ssam#ifndef CONFIG_NO_CONFIG_WRITE 10438189251Ssam } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { 10439189251Ssam if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) 10440189251Ssam reply_len = -1; 10441189251Ssam#endif /* CONFIG_NO_CONFIG_WRITE */ 10442189251Ssam } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { 10443189251Ssam reply_len = wpa_supplicant_ctrl_iface_get_capability( 10444189251Ssam wpa_s, buf + 15, reply, reply_size); 10445189251Ssam } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { 10446189251Ssam if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) 10447189251Ssam reply_len = -1; 10448252726Srpaulo } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) { 10449252726Srpaulo if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14)) 10450252726Srpaulo reply_len = -1; 10451189251Ssam } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { 10452189251Ssam reply_len = wpa_supplicant_global_iface_list( 10453189251Ssam wpa_s->global, reply, reply_size); 10454337817Scy } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { 10455189251Ssam reply_len = wpa_supplicant_global_iface_interfaces( 10456337817Scy wpa_s->global, buf + 10, reply, reply_size); 10457189251Ssam } else if (os_strncmp(buf, "BSS ", 4) == 0) { 10458189251Ssam reply_len = wpa_supplicant_ctrl_iface_bss( 10459189251Ssam wpa_s, buf + 4, reply, reply_size); 10460214734Srpaulo#ifdef CONFIG_AP 10461214734Srpaulo } else if (os_strcmp(buf, "STA-FIRST") == 0) { 10462214734Srpaulo reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); 10463214734Srpaulo } else if (os_strncmp(buf, "STA ", 4) == 0) { 10464214734Srpaulo reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply, 10465214734Srpaulo reply_size); 10466214734Srpaulo } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 10467214734Srpaulo reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, 10468214734Srpaulo reply_size); 10469252726Srpaulo } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 10470252726Srpaulo if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15)) 10471252726Srpaulo reply_len = -1; 10472252726Srpaulo } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 10473252726Srpaulo if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13)) 10474252726Srpaulo reply_len = -1; 10475281806Srpaulo } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { 10476281806Srpaulo if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12)) 10477281806Srpaulo reply_len = -1; 10478281806Srpaulo } else if (os_strcmp(buf, "STOP_AP") == 0) { 10479281806Srpaulo if (wpas_ap_stop_ap(wpa_s)) 10480281806Srpaulo reply_len = -1; 10481214734Srpaulo#endif /* CONFIG_AP */ 10482214734Srpaulo } else if (os_strcmp(buf, "SUSPEND") == 0) { 10483214734Srpaulo wpas_notify_suspend(wpa_s->global); 10484214734Srpaulo } else if (os_strcmp(buf, "RESUME") == 0) { 10485214734Srpaulo wpas_notify_resume(wpa_s->global); 10486281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 10487214734Srpaulo } else if (os_strcmp(buf, "DROP_SA") == 0) { 10488214734Srpaulo wpa_supplicant_ctrl_iface_drop_sa(wpa_s); 10489281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 10490214734Srpaulo } else if (os_strncmp(buf, "ROAM ", 5) == 0) { 10491214734Srpaulo if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5)) 10492214734Srpaulo reply_len = -1; 10493252726Srpaulo } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { 10494281806Srpaulo wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0; 10495252726Srpaulo } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) { 10496252726Srpaulo if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15)) 10497252726Srpaulo reply_len = -1; 10498252726Srpaulo } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) { 10499252726Srpaulo if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s, 10500252726Srpaulo buf + 17)) 10501252726Srpaulo reply_len = -1; 10502252726Srpaulo } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) { 10503281806Srpaulo wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10); 10504252726Srpaulo#ifdef CONFIG_TDLS 10505252726Srpaulo } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) { 10506252726Srpaulo if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14)) 10507252726Srpaulo reply_len = -1; 10508252726Srpaulo } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) { 10509252726Srpaulo if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11)) 10510252726Srpaulo reply_len = -1; 10511252726Srpaulo } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) { 10512252726Srpaulo if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14)) 10513252726Srpaulo reply_len = -1; 10514281806Srpaulo } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) { 10515281806Srpaulo if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s, 10516281806Srpaulo buf + 17)) 10517281806Srpaulo reply_len = -1; 10518281806Srpaulo } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) { 10519281806Srpaulo if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s, 10520281806Srpaulo buf + 24)) 10521281806Srpaulo reply_len = -1; 10522289549Srpaulo } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) { 10523289549Srpaulo reply_len = wpa_supplicant_ctrl_iface_tdls_link_status( 10524289549Srpaulo wpa_s, buf + 17, reply, reply_size); 10525252726Srpaulo#endif /* CONFIG_TDLS */ 10526281806Srpaulo } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) { 10527281806Srpaulo reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size); 10528281806Srpaulo } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) { 10529281806Srpaulo if (wmm_ac_ctrl_addts(wpa_s, buf + 13)) 10530281806Srpaulo reply_len = -1; 10531281806Srpaulo } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) { 10532281806Srpaulo if (wmm_ac_ctrl_delts(wpa_s, buf + 13)) 10533281806Srpaulo reply_len = -1; 10534252726Srpaulo } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { 10535252726Srpaulo reply_len = wpa_supplicant_signal_poll(wpa_s, reply, 10536252726Srpaulo reply_size); 10537337817Scy } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) { 10538337817Scy if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14)) 10539337817Scy reply_len = -1; 10540252726Srpaulo } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { 10541252726Srpaulo reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, 10542252726Srpaulo reply_size); 10543252726Srpaulo#ifdef CONFIG_AUTOSCAN 10544252726Srpaulo } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) { 10545252726Srpaulo if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9)) 10546252726Srpaulo reply_len = -1; 10547252726Srpaulo#endif /* CONFIG_AUTOSCAN */ 10548337817Scy } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { 10549337817Scy reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply, 10550337817Scy reply_size); 10551281806Srpaulo#ifdef ANDROID 10552281806Srpaulo } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { 10553281806Srpaulo reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, 10554281806Srpaulo reply_size); 10555281806Srpaulo#endif /* ANDROID */ 10556281806Srpaulo } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { 10557281806Srpaulo reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply, 10558281806Srpaulo reply_size); 10559252726Srpaulo } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) { 10560252726Srpaulo pmksa_cache_clear_current(wpa_s->wpa); 10561252726Srpaulo eapol_sm_request_reauth(wpa_s->eapol); 10562252726Srpaulo#ifdef CONFIG_WNM 10563252726Srpaulo } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) { 10564252726Srpaulo if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10)) 10565252726Srpaulo reply_len = -1; 10566281806Srpaulo } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) { 10567281806Srpaulo if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14)) 10568281806Srpaulo reply_len = -1; 10569346981Scy } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) { 10570346981Scy if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) 10571346981Scy reply_len = -1; 10572252726Srpaulo#endif /* CONFIG_WNM */ 10573281806Srpaulo } else if (os_strcmp(buf, "FLUSH") == 0) { 10574281806Srpaulo wpa_supplicant_ctrl_iface_flush(wpa_s); 10575281806Srpaulo } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { 10576281806Srpaulo reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, 10577281806Srpaulo reply_size); 10578281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 10579281806Srpaulo } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { 10580281806Srpaulo if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0) 10581281806Srpaulo reply_len = -1; 10582281806Srpaulo } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { 10583281806Srpaulo wpas_ctrl_iface_mgmt_tx_done(wpa_s); 10584337817Scy } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) { 10585337817Scy if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0) 10586337817Scy reply_len = -1; 10587281806Srpaulo } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { 10588281806Srpaulo if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) 10589281806Srpaulo reply_len = -1; 10590281806Srpaulo } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { 10591281806Srpaulo if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0) 10592281806Srpaulo reply_len = -1; 10593281806Srpaulo } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { 10594281806Srpaulo if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0) 10595281806Srpaulo reply_len = -1; 10596281806Srpaulo } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) { 10597281806Srpaulo if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0) 10598281806Srpaulo reply_len = -1; 10599281806Srpaulo } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) { 10600281806Srpaulo if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0) 10601281806Srpaulo reply_len = -1; 10602281806Srpaulo } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { 10603281806Srpaulo if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0) 10604281806Srpaulo reply_len = -1; 10605281806Srpaulo } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { 10606281806Srpaulo reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size); 10607289549Srpaulo } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) { 10608289549Srpaulo if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0) 10609289549Srpaulo reply_len = -1; 10610289549Srpaulo } else if (os_strcmp(buf, "GET_FAIL") == 0) { 10611289549Srpaulo reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size); 10612337817Scy } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) { 10613337817Scy if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0) 10614337817Scy reply_len = -1; 10615337817Scy } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { 10616337817Scy if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) 10617337817Scy reply_len = -1; 10618346981Scy } else if (os_strcmp(buf, "RESET_PN") == 0) { 10619346981Scy if (wpas_ctrl_reset_pn(wpa_s) < 0) 10620346981Scy reply_len = -1; 10621346981Scy } else if (os_strncmp(buf, "KEY_REQUEST ", 12) == 0) { 10622346981Scy if (wpas_ctrl_key_request(wpa_s, buf + 12) < 0) 10623346981Scy reply_len = -1; 10624346981Scy } else if (os_strcmp(buf, "RESEND_ASSOC") == 0) { 10625346981Scy if (wpas_ctrl_resend_assoc(wpa_s) < 0) 10626346981Scy reply_len = -1; 10627346981Scy#ifdef CONFIG_IEEE80211W 10628346981Scy } else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) { 10629346981Scy sme_event_unprot_disconnect( 10630346981Scy wpa_s, wpa_s->bssid, NULL, 10631346981Scy WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); 10632346981Scy#endif /* CONFIG_IEEE80211W */ 10633281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 10634281806Srpaulo } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { 10635281806Srpaulo if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) 10636281806Srpaulo reply_len = -1; 10637281806Srpaulo } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) { 10638281806Srpaulo reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply, 10639281806Srpaulo reply_size); 10640281806Srpaulo } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) { 10641281806Srpaulo if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) 10642281806Srpaulo reply_len = -1; 10643281806Srpaulo } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) { 10644337817Scy if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20)) 10645281806Srpaulo reply_len = -1; 10646281806Srpaulo } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { 10647281806Srpaulo wpas_ctrl_iface_erp_flush(wpa_s); 10648281806Srpaulo } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) { 10649281806Srpaulo if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14)) 10650281806Srpaulo reply_len = -1; 10651289549Srpaulo } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { 10652289549Srpaulo reply_len = wpas_ctrl_iface_get_pref_freq_list( 10653289549Srpaulo wpa_s, buf + 19, reply, reply_size); 10654346981Scy#ifdef CONFIG_FILS 10655346981Scy } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) { 10656346981Scy if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17)) 10657346981Scy reply_len = -1; 10658346981Scy } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) { 10659346981Scy wpas_flush_fils_hlp_req(wpa_s); 10660346981Scy#endif /* CONFIG_FILS */ 10661346981Scy#ifdef CONFIG_DPP 10662346981Scy } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) { 10663346981Scy int res; 10664346981Scy 10665346981Scy res = wpas_dpp_qr_code(wpa_s, buf + 12); 10666346981Scy if (res < 0) { 10667346981Scy reply_len = -1; 10668346981Scy } else { 10669346981Scy reply_len = os_snprintf(reply, reply_size, "%d", res); 10670346981Scy if (os_snprintf_error(reply_size, reply_len)) 10671346981Scy reply_len = -1; 10672346981Scy } 10673346981Scy } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) { 10674346981Scy int res; 10675346981Scy 10676346981Scy res = dpp_bootstrap_gen(wpa_s->dpp, buf + 18); 10677346981Scy if (res < 0) { 10678346981Scy reply_len = -1; 10679346981Scy } else { 10680346981Scy reply_len = os_snprintf(reply, reply_size, "%d", res); 10681346981Scy if (os_snprintf_error(reply_size, reply_len)) 10682346981Scy reply_len = -1; 10683346981Scy } 10684346981Scy } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) { 10685346981Scy if (dpp_bootstrap_remove(wpa_s->dpp, buf + 21) < 0) 10686346981Scy reply_len = -1; 10687346981Scy } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) { 10688346981Scy const char *uri; 10689346981Scy 10690346981Scy uri = dpp_bootstrap_get_uri(wpa_s->dpp, atoi(buf + 22)); 10691346981Scy if (!uri) { 10692346981Scy reply_len = -1; 10693346981Scy } else { 10694346981Scy reply_len = os_snprintf(reply, reply_size, "%s", uri); 10695346981Scy if (os_snprintf_error(reply_size, reply_len)) 10696346981Scy reply_len = -1; 10697346981Scy } 10698346981Scy } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) { 10699346981Scy reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19), 10700346981Scy reply, reply_size); 10701346981Scy } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) { 10702346981Scy if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0) 10703346981Scy reply_len = -1; 10704346981Scy } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) { 10705346981Scy if (wpas_dpp_listen(wpa_s, buf + 11) < 0) 10706346981Scy reply_len = -1; 10707346981Scy } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) { 10708346981Scy wpas_dpp_stop(wpa_s); 10709346981Scy wpas_dpp_listen_stop(wpa_s); 10710346981Scy } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) { 10711346981Scy int res; 10712346981Scy 10713346981Scy res = dpp_configurator_add(wpa_s->dpp, buf + 20); 10714346981Scy if (res < 0) { 10715346981Scy reply_len = -1; 10716346981Scy } else { 10717346981Scy reply_len = os_snprintf(reply, reply_size, "%d", res); 10718346981Scy if (os_snprintf_error(reply_size, reply_len)) 10719346981Scy reply_len = -1; 10720346981Scy } 10721346981Scy } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) { 10722346981Scy if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0) 10723346981Scy reply_len = -1; 10724346981Scy } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) { 10725346981Scy if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0) 10726346981Scy reply_len = -1; 10727346981Scy } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) { 10728346981Scy reply_len = dpp_configurator_get_key_id(wpa_s->dpp, 10729346981Scy atoi(buf + 25), 10730346981Scy reply, reply_size); 10731346981Scy } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) { 10732346981Scy int res; 10733346981Scy 10734346981Scy res = wpas_dpp_pkex_add(wpa_s, buf + 12); 10735346981Scy if (res < 0) { 10736346981Scy reply_len = -1; 10737346981Scy } else { 10738346981Scy reply_len = os_snprintf(reply, reply_size, "%d", res); 10739346981Scy if (os_snprintf_error(reply_size, reply_len)) 10740346981Scy reply_len = -1; 10741346981Scy } 10742346981Scy } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) { 10743346981Scy if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0) 10744346981Scy reply_len = -1; 10745351611Scy#ifdef CONFIG_DPP2 10746351611Scy } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) { 10747351611Scy if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0) 10748351611Scy reply_len = -1; 10749351611Scy } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) { 10750351611Scy if (wpas_dpp_controller_start(wpa_s, NULL) < 0) 10751351611Scy reply_len = -1; 10752351611Scy } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) { 10753351611Scy dpp_controller_stop(wpa_s->dpp); 10754351611Scy#endif /* CONFIG_DPP2 */ 10755346981Scy#endif /* CONFIG_DPP */ 10756189251Ssam } else { 10757189251Ssam os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 10758189251Ssam reply_len = 16; 10759189251Ssam } 10760189251Ssam 10761189251Ssam if (reply_len < 0) { 10762189251Ssam os_memcpy(reply, "FAIL\n", 5); 10763189251Ssam reply_len = 5; 10764189251Ssam } 10765189251Ssam 10766189251Ssam *resp_len = reply_len; 10767189251Ssam return reply; 10768189251Ssam} 10769189251Ssam 10770189251Ssam 10771189251Ssamstatic int wpa_supplicant_global_iface_add(struct wpa_global *global, 10772189251Ssam char *cmd) 10773189251Ssam{ 10774189251Ssam struct wpa_interface iface; 10775289549Srpaulo char *pos, *extra; 10776289549Srpaulo struct wpa_supplicant *wpa_s; 10777289549Srpaulo unsigned int create_iface = 0; 10778289549Srpaulo u8 mac_addr[ETH_ALEN]; 10779337817Scy enum wpa_driver_if_type type = WPA_IF_STATION; 10780189251Ssam 10781189251Ssam /* 10782189251Ssam * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> 10783337817Scy * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]] 10784189251Ssam */ 10785189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); 10786189251Ssam 10787189251Ssam os_memset(&iface, 0, sizeof(iface)); 10788189251Ssam 10789189251Ssam do { 10790189251Ssam iface.ifname = pos = cmd; 10791189251Ssam pos = os_strchr(pos, '\t'); 10792189251Ssam if (pos) 10793189251Ssam *pos++ = '\0'; 10794189251Ssam if (iface.ifname[0] == '\0') 10795189251Ssam return -1; 10796189251Ssam if (pos == NULL) 10797189251Ssam break; 10798189251Ssam 10799189251Ssam iface.confname = pos; 10800189251Ssam pos = os_strchr(pos, '\t'); 10801189251Ssam if (pos) 10802189251Ssam *pos++ = '\0'; 10803189251Ssam if (iface.confname[0] == '\0') 10804189251Ssam iface.confname = NULL; 10805189251Ssam if (pos == NULL) 10806189251Ssam break; 10807189251Ssam 10808189251Ssam iface.driver = pos; 10809189251Ssam pos = os_strchr(pos, '\t'); 10810189251Ssam if (pos) 10811189251Ssam *pos++ = '\0'; 10812189251Ssam if (iface.driver[0] == '\0') 10813189251Ssam iface.driver = NULL; 10814189251Ssam if (pos == NULL) 10815189251Ssam break; 10816189251Ssam 10817189251Ssam iface.ctrl_interface = pos; 10818189251Ssam pos = os_strchr(pos, '\t'); 10819189251Ssam if (pos) 10820189251Ssam *pos++ = '\0'; 10821189251Ssam if (iface.ctrl_interface[0] == '\0') 10822189251Ssam iface.ctrl_interface = NULL; 10823189251Ssam if (pos == NULL) 10824189251Ssam break; 10825189251Ssam 10826189251Ssam iface.driver_param = pos; 10827189251Ssam pos = os_strchr(pos, '\t'); 10828189251Ssam if (pos) 10829189251Ssam *pos++ = '\0'; 10830189251Ssam if (iface.driver_param[0] == '\0') 10831189251Ssam iface.driver_param = NULL; 10832189251Ssam if (pos == NULL) 10833189251Ssam break; 10834189251Ssam 10835189251Ssam iface.bridge_ifname = pos; 10836189251Ssam pos = os_strchr(pos, '\t'); 10837189251Ssam if (pos) 10838189251Ssam *pos++ = '\0'; 10839189251Ssam if (iface.bridge_ifname[0] == '\0') 10840189251Ssam iface.bridge_ifname = NULL; 10841189251Ssam if (pos == NULL) 10842189251Ssam break; 10843289549Srpaulo 10844289549Srpaulo extra = pos; 10845289549Srpaulo pos = os_strchr(pos, '\t'); 10846289549Srpaulo if (pos) 10847289549Srpaulo *pos++ = '\0'; 10848289549Srpaulo if (!extra[0]) 10849289549Srpaulo break; 10850289549Srpaulo 10851337817Scy if (os_strcmp(extra, "create") == 0) { 10852289549Srpaulo create_iface = 1; 10853337817Scy if (!pos) 10854337817Scy break; 10855337817Scy 10856337817Scy if (os_strcmp(pos, "sta") == 0) { 10857337817Scy type = WPA_IF_STATION; 10858337817Scy } else if (os_strcmp(pos, "ap") == 0) { 10859337817Scy type = WPA_IF_AP_BSS; 10860337817Scy } else { 10861337817Scy wpa_printf(MSG_DEBUG, 10862337817Scy "INTERFACE_ADD unsupported interface type: '%s'", 10863337817Scy pos); 10864337817Scy return -1; 10865337817Scy } 10866337817Scy } else { 10867289549Srpaulo wpa_printf(MSG_DEBUG, 10868289549Srpaulo "INTERFACE_ADD unsupported extra parameter: '%s'", 10869289549Srpaulo extra); 10870289549Srpaulo return -1; 10871289549Srpaulo } 10872189251Ssam } while (0); 10873189251Ssam 10874289549Srpaulo if (create_iface) { 10875289549Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'", 10876289549Srpaulo iface.ifname); 10877289549Srpaulo if (!global->ifaces) 10878289549Srpaulo return -1; 10879337817Scy if (wpa_drv_if_add(global->ifaces, type, iface.ifname, 10880289549Srpaulo NULL, NULL, NULL, mac_addr, NULL) < 0) { 10881289549Srpaulo wpa_printf(MSG_ERROR, 10882289549Srpaulo "CTRL_IFACE interface creation failed"); 10883289549Srpaulo return -1; 10884289549Srpaulo } 10885289549Srpaulo 10886289549Srpaulo wpa_printf(MSG_DEBUG, 10887289549Srpaulo "CTRL_IFACE interface '%s' created with MAC addr: " 10888289549Srpaulo MACSTR, iface.ifname, MAC2STR(mac_addr)); 10889289549Srpaulo } 10890289549Srpaulo 10891189251Ssam if (wpa_supplicant_get_iface(global, iface.ifname)) 10892289549Srpaulo goto fail; 10893189251Ssam 10894289549Srpaulo wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); 10895289549Srpaulo if (!wpa_s) 10896289549Srpaulo goto fail; 10897289549Srpaulo wpa_s->added_vif = create_iface; 10898289549Srpaulo return 0; 10899289549Srpaulo 10900289549Srpaulofail: 10901289549Srpaulo if (create_iface) 10902289549Srpaulo wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname); 10903289549Srpaulo return -1; 10904189251Ssam} 10905189251Ssam 10906189251Ssam 10907189251Ssamstatic int wpa_supplicant_global_iface_remove(struct wpa_global *global, 10908189251Ssam char *cmd) 10909189251Ssam{ 10910189251Ssam struct wpa_supplicant *wpa_s; 10911289549Srpaulo int ret; 10912289549Srpaulo unsigned int delete_iface; 10913189251Ssam 10914189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd); 10915189251Ssam 10916189251Ssam wpa_s = wpa_supplicant_get_iface(global, cmd); 10917189251Ssam if (wpa_s == NULL) 10918189251Ssam return -1; 10919289549Srpaulo delete_iface = wpa_s->added_vif; 10920289549Srpaulo ret = wpa_supplicant_remove_iface(global, wpa_s, 0); 10921289549Srpaulo if (!ret && delete_iface) { 10922289549Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'", 10923289549Srpaulo cmd); 10924289549Srpaulo ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd); 10925289549Srpaulo } 10926289549Srpaulo return ret; 10927189251Ssam} 10928189251Ssam 10929189251Ssam 10930189251Ssamstatic void wpa_free_iface_info(struct wpa_interface_info *iface) 10931189251Ssam{ 10932189251Ssam struct wpa_interface_info *prev; 10933189251Ssam 10934189251Ssam while (iface) { 10935189251Ssam prev = iface; 10936189251Ssam iface = iface->next; 10937189251Ssam 10938189251Ssam os_free(prev->ifname); 10939189251Ssam os_free(prev->desc); 10940189251Ssam os_free(prev); 10941189251Ssam } 10942189251Ssam} 10943189251Ssam 10944189251Ssam 10945189251Ssamstatic int wpa_supplicant_global_iface_list(struct wpa_global *global, 10946189251Ssam char *buf, int len) 10947189251Ssam{ 10948189251Ssam int i, res; 10949189251Ssam struct wpa_interface_info *iface = NULL, *last = NULL, *tmp; 10950189251Ssam char *pos, *end; 10951189251Ssam 10952214734Srpaulo for (i = 0; wpa_drivers[i]; i++) { 10953289549Srpaulo const struct wpa_driver_ops *drv = wpa_drivers[i]; 10954189251Ssam if (drv->get_interfaces == NULL) 10955189251Ssam continue; 10956214734Srpaulo tmp = drv->get_interfaces(global->drv_priv[i]); 10957189251Ssam if (tmp == NULL) 10958189251Ssam continue; 10959189251Ssam 10960189251Ssam if (last == NULL) 10961189251Ssam iface = last = tmp; 10962189251Ssam else 10963189251Ssam last->next = tmp; 10964189251Ssam while (last->next) 10965189251Ssam last = last->next; 10966189251Ssam } 10967189251Ssam 10968189251Ssam pos = buf; 10969189251Ssam end = buf + len; 10970189251Ssam for (tmp = iface; tmp; tmp = tmp->next) { 10971189251Ssam res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n", 10972189251Ssam tmp->drv_name, tmp->ifname, 10973189251Ssam tmp->desc ? tmp->desc : ""); 10974281806Srpaulo if (os_snprintf_error(end - pos, res)) { 10975189251Ssam *pos = '\0'; 10976189251Ssam break; 10977189251Ssam } 10978189251Ssam pos += res; 10979189251Ssam } 10980189251Ssam 10981189251Ssam wpa_free_iface_info(iface); 10982189251Ssam 10983189251Ssam return pos - buf; 10984189251Ssam} 10985189251Ssam 10986189251Ssam 10987189251Ssamstatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, 10988337817Scy const char *input, 10989189251Ssam char *buf, int len) 10990189251Ssam{ 10991189251Ssam int res; 10992189251Ssam char *pos, *end; 10993189251Ssam struct wpa_supplicant *wpa_s; 10994337817Scy int show_ctrl = 0; 10995189251Ssam 10996337817Scy if (input) 10997337817Scy show_ctrl = !!os_strstr(input, "ctrl"); 10998337817Scy 10999189251Ssam wpa_s = global->ifaces; 11000189251Ssam pos = buf; 11001189251Ssam end = buf + len; 11002189251Ssam 11003189251Ssam while (wpa_s) { 11004337817Scy if (show_ctrl) 11005337817Scy res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n", 11006337817Scy wpa_s->ifname, 11007337817Scy wpa_s->conf->ctrl_interface ? 11008337817Scy wpa_s->conf->ctrl_interface : "N/A"); 11009337817Scy else 11010337817Scy res = os_snprintf(pos, end - pos, "%s\n", 11011337817Scy wpa_s->ifname); 11012337817Scy 11013281806Srpaulo if (os_snprintf_error(end - pos, res)) { 11014189251Ssam *pos = '\0'; 11015189251Ssam break; 11016189251Ssam } 11017189251Ssam pos += res; 11018189251Ssam wpa_s = wpa_s->next; 11019189251Ssam } 11020189251Ssam return pos - buf; 11021189251Ssam} 11022189251Ssam 11023189251Ssam 11024281806Srpaulostatic char * wpas_global_ctrl_iface_ifname(struct wpa_global *global, 11025281806Srpaulo const char *ifname, 11026281806Srpaulo char *cmd, size_t *resp_len) 11027281806Srpaulo{ 11028281806Srpaulo struct wpa_supplicant *wpa_s; 11029281806Srpaulo 11030281806Srpaulo for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 11031281806Srpaulo if (os_strcmp(ifname, wpa_s->ifname) == 0) 11032281806Srpaulo break; 11033281806Srpaulo } 11034281806Srpaulo 11035281806Srpaulo if (wpa_s == NULL) { 11036281806Srpaulo char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n"); 11037281806Srpaulo if (resp) 11038281806Srpaulo *resp_len = os_strlen(resp); 11039281806Srpaulo else 11040281806Srpaulo *resp_len = 1; 11041281806Srpaulo return resp; 11042281806Srpaulo } 11043281806Srpaulo 11044281806Srpaulo return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len); 11045281806Srpaulo} 11046281806Srpaulo 11047281806Srpaulo 11048281806Srpaulostatic char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, 11049281806Srpaulo char *buf, size_t *resp_len) 11050281806Srpaulo{ 11051281806Srpaulo#ifdef CONFIG_P2P 11052281806Srpaulo static const char * cmd[] = { 11053281806Srpaulo "LIST_NETWORKS", 11054281806Srpaulo "P2P_FIND", 11055281806Srpaulo "P2P_STOP_FIND", 11056281806Srpaulo "P2P_LISTEN", 11057281806Srpaulo "P2P_GROUP_ADD", 11058281806Srpaulo "P2P_GET_PASSPHRASE", 11059281806Srpaulo "P2P_SERVICE_UPDATE", 11060281806Srpaulo "P2P_SERVICE_FLUSH", 11061281806Srpaulo "P2P_FLUSH", 11062281806Srpaulo "P2P_CANCEL", 11063281806Srpaulo "P2P_PRESENCE_REQ", 11064281806Srpaulo "P2P_EXT_LISTEN", 11065346981Scy#ifdef CONFIG_AP 11066346981Scy "STA-FIRST", 11067346981Scy#endif /* CONFIG_AP */ 11068281806Srpaulo NULL 11069281806Srpaulo }; 11070281806Srpaulo static const char * prefix[] = { 11071281806Srpaulo#ifdef ANDROID 11072281806Srpaulo "DRIVER ", 11073281806Srpaulo#endif /* ANDROID */ 11074346981Scy "GET_CAPABILITY ", 11075281806Srpaulo "GET_NETWORK ", 11076281806Srpaulo "REMOVE_NETWORK ", 11077281806Srpaulo "P2P_FIND ", 11078281806Srpaulo "P2P_CONNECT ", 11079281806Srpaulo "P2P_LISTEN ", 11080281806Srpaulo "P2P_GROUP_REMOVE ", 11081281806Srpaulo "P2P_GROUP_ADD ", 11082337817Scy "P2P_GROUP_MEMBER ", 11083281806Srpaulo "P2P_PROV_DISC ", 11084281806Srpaulo "P2P_SERV_DISC_REQ ", 11085281806Srpaulo "P2P_SERV_DISC_CANCEL_REQ ", 11086281806Srpaulo "P2P_SERV_DISC_RESP ", 11087281806Srpaulo "P2P_SERV_DISC_EXTERNAL ", 11088281806Srpaulo "P2P_SERVICE_ADD ", 11089281806Srpaulo "P2P_SERVICE_DEL ", 11090281806Srpaulo "P2P_SERVICE_REP ", 11091281806Srpaulo "P2P_REJECT ", 11092281806Srpaulo "P2P_INVITE ", 11093281806Srpaulo "P2P_PEER ", 11094281806Srpaulo "P2P_SET ", 11095281806Srpaulo "P2P_UNAUTHORIZE ", 11096281806Srpaulo "P2P_PRESENCE_REQ ", 11097281806Srpaulo "P2P_EXT_LISTEN ", 11098281806Srpaulo "P2P_REMOVE_CLIENT ", 11099281806Srpaulo "WPS_NFC_TOKEN ", 11100281806Srpaulo "WPS_NFC_TAG_READ ", 11101281806Srpaulo "NFC_GET_HANDOVER_SEL ", 11102281806Srpaulo "NFC_GET_HANDOVER_REQ ", 11103281806Srpaulo "NFC_REPORT_HANDOVER ", 11104281806Srpaulo "P2P_ASP_PROVISION ", 11105281806Srpaulo "P2P_ASP_PROVISION_RESP ", 11106346981Scy#ifdef CONFIG_AP 11107346981Scy "STA ", 11108346981Scy "STA-NEXT ", 11109346981Scy#endif /* CONFIG_AP */ 11110281806Srpaulo NULL 11111281806Srpaulo }; 11112281806Srpaulo int found = 0; 11113281806Srpaulo int i; 11114281806Srpaulo 11115281806Srpaulo if (global->p2p_init_wpa_s == NULL) 11116281806Srpaulo return NULL; 11117281806Srpaulo 11118281806Srpaulo for (i = 0; !found && cmd[i]; i++) { 11119281806Srpaulo if (os_strcmp(buf, cmd[i]) == 0) 11120281806Srpaulo found = 1; 11121281806Srpaulo } 11122281806Srpaulo 11123281806Srpaulo for (i = 0; !found && prefix[i]; i++) { 11124281806Srpaulo if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0) 11125281806Srpaulo found = 1; 11126281806Srpaulo } 11127281806Srpaulo 11128281806Srpaulo if (found) 11129281806Srpaulo return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, 11130281806Srpaulo buf, resp_len); 11131281806Srpaulo#endif /* CONFIG_P2P */ 11132281806Srpaulo return NULL; 11133281806Srpaulo} 11134281806Srpaulo 11135281806Srpaulo 11136281806Srpaulostatic char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global, 11137281806Srpaulo char *buf, size_t *resp_len) 11138281806Srpaulo{ 11139281806Srpaulo#ifdef CONFIG_WIFI_DISPLAY 11140281806Srpaulo if (global->p2p_init_wpa_s == NULL) 11141281806Srpaulo return NULL; 11142281806Srpaulo if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 || 11143281806Srpaulo os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) 11144281806Srpaulo return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, 11145281806Srpaulo buf, resp_len); 11146281806Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 11147281806Srpaulo return NULL; 11148281806Srpaulo} 11149281806Srpaulo 11150281806Srpaulo 11151281806Srpaulostatic char * wpas_global_ctrl_iface_redir(struct wpa_global *global, 11152281806Srpaulo char *buf, size_t *resp_len) 11153281806Srpaulo{ 11154281806Srpaulo char *ret; 11155281806Srpaulo 11156281806Srpaulo ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len); 11157281806Srpaulo if (ret) 11158281806Srpaulo return ret; 11159281806Srpaulo 11160281806Srpaulo ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len); 11161281806Srpaulo if (ret) 11162281806Srpaulo return ret; 11163281806Srpaulo 11164281806Srpaulo return NULL; 11165281806Srpaulo} 11166281806Srpaulo 11167281806Srpaulo 11168281806Srpaulostatic int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd) 11169281806Srpaulo{ 11170281806Srpaulo char *value; 11171281806Srpaulo 11172281806Srpaulo value = os_strchr(cmd, ' '); 11173281806Srpaulo if (value == NULL) 11174281806Srpaulo return -1; 11175281806Srpaulo *value++ = '\0'; 11176281806Srpaulo 11177281806Srpaulo wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value); 11178281806Srpaulo 11179281806Srpaulo#ifdef CONFIG_WIFI_DISPLAY 11180281806Srpaulo if (os_strcasecmp(cmd, "wifi_display") == 0) { 11181281806Srpaulo wifi_display_enable(global, !!atoi(value)); 11182281806Srpaulo return 0; 11183281806Srpaulo } 11184281806Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 11185281806Srpaulo 11186281806Srpaulo /* Restore cmd to its original value to allow redirection */ 11187281806Srpaulo value[-1] = ' '; 11188281806Srpaulo 11189281806Srpaulo return -1; 11190281806Srpaulo} 11191281806Srpaulo 11192281806Srpaulo 11193289549Srpaulostatic int wpas_global_ctrl_iface_dup_network(struct wpa_global *global, 11194289549Srpaulo char *cmd) 11195289549Srpaulo{ 11196289549Srpaulo struct wpa_supplicant *wpa_s[2]; /* src, dst */ 11197289549Srpaulo char *p; 11198289549Srpaulo unsigned int i; 11199289549Srpaulo 11200289549Srpaulo /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id> 11201289549Srpaulo * <variable name> */ 11202289549Srpaulo 11203289549Srpaulo for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) { 11204289549Srpaulo p = os_strchr(cmd, ' '); 11205289549Srpaulo if (p == NULL) 11206289549Srpaulo return -1; 11207289549Srpaulo *p = '\0'; 11208289549Srpaulo 11209289549Srpaulo wpa_s[i] = global->ifaces; 11210289549Srpaulo for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) { 11211289549Srpaulo if (os_strcmp(cmd, wpa_s[i]->ifname) == 0) 11212289549Srpaulo break; 11213289549Srpaulo } 11214289549Srpaulo 11215289549Srpaulo if (!wpa_s[i]) { 11216289549Srpaulo wpa_printf(MSG_DEBUG, 11217289549Srpaulo "CTRL_IFACE: Could not find iface=%s", cmd); 11218289549Srpaulo return -1; 11219289549Srpaulo } 11220289549Srpaulo 11221289549Srpaulo cmd = p + 1; 11222289549Srpaulo } 11223289549Srpaulo 11224289549Srpaulo return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]); 11225289549Srpaulo} 11226289549Srpaulo 11227289549Srpaulo 11228281806Srpaulo#ifndef CONFIG_NO_CONFIG_WRITE 11229281806Srpaulostatic int wpas_global_ctrl_iface_save_config(struct wpa_global *global) 11230281806Srpaulo{ 11231281806Srpaulo int ret = 0, saved = 0; 11232281806Srpaulo struct wpa_supplicant *wpa_s; 11233281806Srpaulo 11234281806Srpaulo for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 11235281806Srpaulo if (!wpa_s->conf->update_config) { 11236281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)"); 11237281806Srpaulo continue; 11238281806Srpaulo } 11239281806Srpaulo 11240281806Srpaulo if (wpa_config_write(wpa_s->confname, wpa_s->conf)) { 11241281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration"); 11242281806Srpaulo ret = 1; 11243281806Srpaulo } else { 11244281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated"); 11245281806Srpaulo saved++; 11246281806Srpaulo } 11247281806Srpaulo } 11248281806Srpaulo 11249281806Srpaulo if (!saved && !ret) { 11250281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 11251281806Srpaulo "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated"); 11252281806Srpaulo ret = 1; 11253281806Srpaulo } 11254281806Srpaulo 11255281806Srpaulo return ret; 11256281806Srpaulo} 11257281806Srpaulo#endif /* CONFIG_NO_CONFIG_WRITE */ 11258281806Srpaulo 11259281806Srpaulo 11260281806Srpaulostatic int wpas_global_ctrl_iface_status(struct wpa_global *global, 11261281806Srpaulo char *buf, size_t buflen) 11262281806Srpaulo{ 11263281806Srpaulo char *pos, *end; 11264281806Srpaulo int ret; 11265281806Srpaulo struct wpa_supplicant *wpa_s; 11266281806Srpaulo 11267281806Srpaulo pos = buf; 11268281806Srpaulo end = buf + buflen; 11269281806Srpaulo 11270281806Srpaulo#ifdef CONFIG_P2P 11271281806Srpaulo if (global->p2p && !global->p2p_disabled) { 11272281806Srpaulo ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR 11273281806Srpaulo "\n" 11274281806Srpaulo "p2p_state=%s\n", 11275281806Srpaulo MAC2STR(global->p2p_dev_addr), 11276281806Srpaulo p2p_get_state_txt(global->p2p)); 11277281806Srpaulo if (os_snprintf_error(end - pos, ret)) 11278281806Srpaulo return pos - buf; 11279281806Srpaulo pos += ret; 11280281806Srpaulo } else if (global->p2p) { 11281281806Srpaulo ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n"); 11282281806Srpaulo if (os_snprintf_error(end - pos, ret)) 11283281806Srpaulo return pos - buf; 11284281806Srpaulo pos += ret; 11285281806Srpaulo } 11286281806Srpaulo#endif /* CONFIG_P2P */ 11287281806Srpaulo 11288281806Srpaulo#ifdef CONFIG_WIFI_DISPLAY 11289281806Srpaulo ret = os_snprintf(pos, end - pos, "wifi_display=%d\n", 11290281806Srpaulo !!global->wifi_display); 11291281806Srpaulo if (os_snprintf_error(end - pos, ret)) 11292281806Srpaulo return pos - buf; 11293281806Srpaulo pos += ret; 11294281806Srpaulo#endif /* CONFIG_WIFI_DISPLAY */ 11295281806Srpaulo 11296281806Srpaulo for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 11297281806Srpaulo ret = os_snprintf(pos, end - pos, "ifname=%s\n" 11298281806Srpaulo "address=" MACSTR "\n", 11299281806Srpaulo wpa_s->ifname, MAC2STR(wpa_s->own_addr)); 11300281806Srpaulo if (os_snprintf_error(end - pos, ret)) 11301281806Srpaulo return pos - buf; 11302281806Srpaulo pos += ret; 11303281806Srpaulo } 11304281806Srpaulo 11305281806Srpaulo return pos - buf; 11306281806Srpaulo} 11307281806Srpaulo 11308281806Srpaulo 11309289549Srpaulo#ifdef CONFIG_FST 11310289549Srpaulo 11311289549Srpaulostatic int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global, 11312289549Srpaulo char *cmd, char *buf, 11313289549Srpaulo size_t reply_size) 11314289549Srpaulo{ 11315289549Srpaulo char ifname[IFNAMSIZ + 1]; 11316289549Srpaulo struct fst_iface_cfg cfg; 11317289549Srpaulo struct wpa_supplicant *wpa_s; 11318289549Srpaulo struct fst_wpa_obj iface_obj; 11319289549Srpaulo 11320289549Srpaulo if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) { 11321289549Srpaulo wpa_s = wpa_supplicant_get_iface(global, ifname); 11322289549Srpaulo if (wpa_s) { 11323289549Srpaulo if (wpa_s->fst) { 11324289549Srpaulo wpa_printf(MSG_INFO, "FST: Already attached"); 11325289549Srpaulo return -1; 11326289549Srpaulo } 11327289549Srpaulo fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj); 11328289549Srpaulo wpa_s->fst = fst_attach(ifname, wpa_s->own_addr, 11329289549Srpaulo &iface_obj, &cfg); 11330289549Srpaulo if (wpa_s->fst) 11331289549Srpaulo return os_snprintf(buf, reply_size, "OK\n"); 11332289549Srpaulo } 11333289549Srpaulo } 11334289549Srpaulo 11335289549Srpaulo return -1; 11336289549Srpaulo} 11337289549Srpaulo 11338289549Srpaulo 11339289549Srpaulostatic int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global, 11340289549Srpaulo char *cmd, char *buf, 11341289549Srpaulo size_t reply_size) 11342289549Srpaulo{ 11343289549Srpaulo char ifname[IFNAMSIZ + 1]; 11344289549Srpaulo struct wpa_supplicant *wpa_s; 11345289549Srpaulo 11346289549Srpaulo if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) { 11347289549Srpaulo wpa_s = wpa_supplicant_get_iface(global, ifname); 11348289549Srpaulo if (wpa_s) { 11349289549Srpaulo if (!fst_iface_detach(ifname)) { 11350289549Srpaulo wpa_s->fst = NULL; 11351289549Srpaulo return os_snprintf(buf, reply_size, "OK\n"); 11352289549Srpaulo } 11353289549Srpaulo } 11354289549Srpaulo } 11355289549Srpaulo 11356289549Srpaulo return -1; 11357289549Srpaulo} 11358289549Srpaulo 11359289549Srpaulo#endif /* CONFIG_FST */ 11360289549Srpaulo 11361289549Srpaulo 11362189251Ssamchar * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, 11363189251Ssam char *buf, size_t *resp_len) 11364189251Ssam{ 11365189251Ssam char *reply; 11366189251Ssam const int reply_size = 2048; 11367189251Ssam int reply_len; 11368252726Srpaulo int level = MSG_DEBUG; 11369189251Ssam 11370281806Srpaulo if (os_strncmp(buf, "IFNAME=", 7) == 0) { 11371281806Srpaulo char *pos = os_strchr(buf + 7, ' '); 11372281806Srpaulo if (pos) { 11373281806Srpaulo *pos++ = '\0'; 11374281806Srpaulo return wpas_global_ctrl_iface_ifname(global, 11375281806Srpaulo buf + 7, pos, 11376281806Srpaulo resp_len); 11377281806Srpaulo } 11378281806Srpaulo } 11379281806Srpaulo 11380281806Srpaulo reply = wpas_global_ctrl_iface_redir(global, buf, resp_len); 11381281806Srpaulo if (reply) 11382281806Srpaulo return reply; 11383281806Srpaulo 11384252726Srpaulo if (os_strcmp(buf, "PING") == 0) 11385252726Srpaulo level = MSG_EXCESSIVE; 11386252726Srpaulo wpa_hexdump_ascii(level, "RX global ctrl_iface", 11387189251Ssam (const u8 *) buf, os_strlen(buf)); 11388189251Ssam 11389189251Ssam reply = os_malloc(reply_size); 11390189251Ssam if (reply == NULL) { 11391189251Ssam *resp_len = 1; 11392189251Ssam return NULL; 11393189251Ssam } 11394189251Ssam 11395189251Ssam os_memcpy(reply, "OK\n", 3); 11396189251Ssam reply_len = 3; 11397189251Ssam 11398189251Ssam if (os_strcmp(buf, "PING") == 0) { 11399189251Ssam os_memcpy(reply, "PONG\n", 5); 11400189251Ssam reply_len = 5; 11401189251Ssam } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { 11402189251Ssam if (wpa_supplicant_global_iface_add(global, buf + 14)) 11403189251Ssam reply_len = -1; 11404189251Ssam } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { 11405189251Ssam if (wpa_supplicant_global_iface_remove(global, buf + 17)) 11406189251Ssam reply_len = -1; 11407189251Ssam } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { 11408189251Ssam reply_len = wpa_supplicant_global_iface_list( 11409189251Ssam global, reply, reply_size); 11410337817Scy } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { 11411189251Ssam reply_len = wpa_supplicant_global_iface_interfaces( 11412337817Scy global, buf + 10, reply, reply_size); 11413289549Srpaulo#ifdef CONFIG_FST 11414289549Srpaulo } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { 11415289549Srpaulo reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, 11416289549Srpaulo reply, 11417289549Srpaulo reply_size); 11418289549Srpaulo } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) { 11419289549Srpaulo reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11, 11420289549Srpaulo reply, 11421289549Srpaulo reply_size); 11422289549Srpaulo } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) { 11423289549Srpaulo reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size); 11424289549Srpaulo#endif /* CONFIG_FST */ 11425189251Ssam } else if (os_strcmp(buf, "TERMINATE") == 0) { 11426214734Srpaulo wpa_supplicant_terminate_proc(global); 11427214734Srpaulo } else if (os_strcmp(buf, "SUSPEND") == 0) { 11428214734Srpaulo wpas_notify_suspend(global); 11429214734Srpaulo } else if (os_strcmp(buf, "RESUME") == 0) { 11430214734Srpaulo wpas_notify_resume(global); 11431281806Srpaulo } else if (os_strncmp(buf, "SET ", 4) == 0) { 11432281806Srpaulo if (wpas_global_ctrl_iface_set(global, buf + 4)) { 11433281806Srpaulo#ifdef CONFIG_P2P 11434281806Srpaulo if (global->p2p_init_wpa_s) { 11435281806Srpaulo os_free(reply); 11436281806Srpaulo /* Check if P2P redirection would work for this 11437281806Srpaulo * command. */ 11438281806Srpaulo return wpa_supplicant_ctrl_iface_process( 11439281806Srpaulo global->p2p_init_wpa_s, 11440281806Srpaulo buf, resp_len); 11441281806Srpaulo } 11442281806Srpaulo#endif /* CONFIG_P2P */ 11443281806Srpaulo reply_len = -1; 11444281806Srpaulo } 11445289549Srpaulo } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { 11446289549Srpaulo if (wpas_global_ctrl_iface_dup_network(global, buf + 12)) 11447289549Srpaulo reply_len = -1; 11448281806Srpaulo#ifndef CONFIG_NO_CONFIG_WRITE 11449281806Srpaulo } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { 11450281806Srpaulo if (wpas_global_ctrl_iface_save_config(global)) 11451281806Srpaulo reply_len = -1; 11452281806Srpaulo#endif /* CONFIG_NO_CONFIG_WRITE */ 11453281806Srpaulo } else if (os_strcmp(buf, "STATUS") == 0) { 11454281806Srpaulo reply_len = wpas_global_ctrl_iface_status(global, reply, 11455281806Srpaulo reply_size); 11456281806Srpaulo#ifdef CONFIG_MODULE_TESTS 11457281806Srpaulo } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { 11458281806Srpaulo if (wpas_module_tests() < 0) 11459281806Srpaulo reply_len = -1; 11460281806Srpaulo#endif /* CONFIG_MODULE_TESTS */ 11461281806Srpaulo } else if (os_strncmp(buf, "RELOG", 5) == 0) { 11462281806Srpaulo if (wpa_debug_reopen_file() < 0) 11463281806Srpaulo reply_len = -1; 11464189251Ssam } else { 11465189251Ssam os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 11466189251Ssam reply_len = 16; 11467189251Ssam } 11468189251Ssam 11469189251Ssam if (reply_len < 0) { 11470189251Ssam os_memcpy(reply, "FAIL\n", 5); 11471189251Ssam reply_len = 5; 11472189251Ssam } 11473189251Ssam 11474189251Ssam *resp_len = reply_len; 11475189251Ssam return reply; 11476189251Ssam} 11477