ctrl_iface.c revision 337817
1114402Sru/* 2151497Sru * WPA Supplicant / Control interface (shared code for all backends) 3151497Sru * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> 4114402Sru * 5114402Sru * This software may be distributed under the terms of the BSD license. 6114402Sru * See README for more details. 7114402Sru */ 8114402Sru 9114402Sru#include "utils/includes.h" 10114402Sru#ifdef CONFIG_TESTING_OPTIONS 11114402Sru#include <net/ethernet.h> 12114402Sru#include <netinet/ip.h> 13114402Sru#endif /* CONFIG_TESTING_OPTIONS */ 14114402Sru 15114402Sru#include "utils/common.h" 16114402Sru#include "utils/eloop.h" 17114402Sru#include "utils/uuid.h" 18114402Sru#include "utils/module_tests.h" 19114402Sru#include "common/version.h" 20114402Sru#include "common/ieee802_11_defs.h" 21114402Sru#include "common/ieee802_11_common.h" 22114402Sru#include "common/wpa_ctrl.h" 23114402Sru#include "crypto/tls.h" 24114402Sru#include "ap/hostapd.h" 25151497Sru#include "eap_peer/eap.h" 26114402Sru#include "eapol_supp/eapol_supp_sm.h" 27114402Sru#include "rsn_supp/wpa.h" 28114402Sru#include "rsn_supp/preauth.h" 29114402Sru#include "rsn_supp/pmksa_cache.h" 30114402Sru#include "l2_packet/l2_packet.h" 31114402Sru#include "wps/wps.h" 32114402Sru#include "fst/fst.h" 33114402Sru#include "fst/fst_ctrl_iface.h" 34114402Sru#include "config.h" 35114402Sru#include "wpa_supplicant_i.h" 36114402Sru#include "driver_i.h" 37114402Sru#include "wps_supplicant.h" 38114402Sru#include "ibss_rsn.h" 39114402Sru#include "ap.h" 40114402Sru#include "p2p_supplicant.h" 41114402Sru#include "p2p/p2p.h" 42151497Sru#include "hs20_supplicant.h" 43114402Sru#include "wifi_display.h" 44114402Sru#include "notify.h" 45114402Sru#include "bss.h" 46114402Sru#include "scan.h" 47114402Sru#include "ctrl_iface.h" 48114402Sru#include "interworking.h" 49114402Sru#include "blacklist.h" 50114402Sru#include "autoscan.h" 51114402Sru#include "wnm_sta.h" 52114402Sru#include "offchannel.h" 53114402Sru#include "drivers/driver.h" 54114402Sru#include "mesh.h" 55151497Sru 56114402Srustatic int wpa_supplicant_global_iface_list(struct wpa_global *global, 57114402Sru char *buf, int len); 58114402Srustatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, 59114402Sru const char *input, 60114402Sru char *buf, int len); 61114402Srustatic int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, 62114402Sru char *val); 63114402Sru 64151497Srustatic int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) 65114402Sru{ 66114402Sru char *pos; 67114402Sru u8 addr[ETH_ALEN], *filter = NULL, *n; 68114402Sru size_t count = 0; 69114402Sru 70114402Sru pos = val; 71114402Sru while (pos) { 72114402Sru if (*pos == '\0') 73114402Sru break; 74114402Sru if (hwaddr_aton(pos, addr)) { 75114402Sru os_free(filter); 76114402Sru return -1; 77114402Sru } 78114402Sru n = os_realloc_array(filter, count + 1, ETH_ALEN); 79114402Sru if (n == NULL) { 80114402Sru os_free(filter); 81114402Sru return -1; 82151497Sru } 83151497Sru filter = n; 84151497Sru os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN); 85151497Sru count++; 86151497Sru 87151497Sru pos = os_strchr(pos, ' '); 88151497Sru if (pos) 89151497Sru pos++; 90151497Sru } 91151497Sru 92114402Sru wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN); 93114402Sru os_free(wpa_s->bssid_filter); 94114402Sru wpa_s->bssid_filter = filter; 95114402Sru wpa_s->bssid_filter_count = count; 96114402Sru 97114402Sru return 0; 98114402Sru} 99114402Sru 100114402Sru 101114402Srustatic int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val) 102114402Sru{ 103114402Sru char *pos; 104114402Sru u8 addr[ETH_ALEN], *bssid = NULL, *n; 105114402Sru struct wpa_ssid_value *ssid = NULL, *ns; 106114402Sru size_t count = 0, ssid_count = 0; 107114402Sru struct wpa_ssid *c; 108114402Sru 109114402Sru /* 110114402Sru * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | "" 111114402Sru * SSID_SPEC ::= ssid <SSID_HEX> 112114402Sru * BSSID_SPEC ::= bssid <BSSID_HEX> 113114402Sru */ 114114402Sru 115114402Sru pos = val; 116114402Sru while (pos) { 117114402Sru if (*pos == '\0') 118114402Sru break; 119114402Sru if (os_strncmp(pos, "bssid ", 6) == 0) { 120114402Sru int res; 121114402Sru pos += 6; 122114402Sru res = hwaddr_aton2(pos, addr); 123151497Sru if (res < 0) { 124114402Sru os_free(ssid); 125114402Sru os_free(bssid); 126114402Sru wpa_printf(MSG_DEBUG, "Invalid disallow_aps " 127114402Sru "BSSID value '%s'", pos); 128114402Sru return -1; 129114402Sru } 130114402Sru pos += res; 131114402Sru n = os_realloc_array(bssid, count + 1, ETH_ALEN); 132151497Sru if (n == NULL) { 133114402Sru os_free(ssid); 134114402Sru os_free(bssid); 135114402Sru return -1; 136114402Sru } 137114402Sru bssid = n; 138114402Sru os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN); 139114402Sru count++; 140114402Sru } else if (os_strncmp(pos, "ssid ", 5) == 0) { 141114402Sru char *end; 142151497Sru pos += 5; 143151497Sru 144151497Sru end = pos; 145114402Sru while (*end) { 146114402Sru if (*end == '\0' || *end == ' ') 147114402Sru break; 148114402Sru end++; 149114402Sru } 150114402Sru 151114402Sru ns = os_realloc_array(ssid, ssid_count + 1, 152114402Sru sizeof(struct wpa_ssid_value)); 153114402Sru if (ns == NULL) { 154151497Sru os_free(ssid); 155151497Sru os_free(bssid); 156114402Sru return -1; 157114402Sru } 158114402Sru ssid = ns; 159114402Sru 160114402Sru if ((end - pos) & 0x01 || 161151497Sru end - pos > 2 * SSID_MAX_LEN || 162151497Sru hexstr2bin(pos, ssid[ssid_count].ssid, 163151497Sru (end - pos) / 2) < 0) { 164151497Sru os_free(ssid); 165151497Sru os_free(bssid); 166151497Sru wpa_printf(MSG_DEBUG, "Invalid disallow_aps " 167151497Sru "SSID value '%s'", pos); 168151497Sru return -1; 169151497Sru } 170151497Sru ssid[ssid_count].ssid_len = (end - pos) / 2; 171151497Sru wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID", 172114402Sru ssid[ssid_count].ssid, 173151497Sru ssid[ssid_count].ssid_len); 174151497Sru ssid_count++; 175151497Sru pos = end; 176114402Sru } else { 177114402Sru wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value " 178114402Sru "'%s'", pos); 179114402Sru os_free(ssid); 180114402Sru os_free(bssid); 181114402Sru return -1; 182114402Sru } 183151497Sru 184114402Sru pos = os_strchr(pos, ' '); 185114402Sru if (pos) 186114402Sru pos++; 187114402Sru } 188114402Sru 189114402Sru wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN); 190114402Sru os_free(wpa_s->disallow_aps_bssid); 191114402Sru wpa_s->disallow_aps_bssid = bssid; 192114402Sru wpa_s->disallow_aps_bssid_count = count; 193151497Sru 194151497Sru wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count); 195151497Sru os_free(wpa_s->disallow_aps_ssid); 196151497Sru wpa_s->disallow_aps_ssid = ssid; 197114402Sru wpa_s->disallow_aps_ssid_count = ssid_count; 198114402Sru 199114402Sru if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING) 200114402Sru return 0; 201114402Sru 202114402Sru c = wpa_s->current_ssid; 203114402Sru if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS) 204114402Sru return 0; 205114402Sru 206114402Sru if (!disallowed_bssid(wpa_s, wpa_s->bssid) && 207114402Sru !disallowed_ssid(wpa_s, c->ssid, c->ssid_len)) 208114402Sru return 0; 209114402Sru 210114402Sru wpa_printf(MSG_DEBUG, "Disconnect and try to find another network " 211114402Sru "because current AP was marked disallowed"); 212114402Sru 213114402Sru#ifdef CONFIG_SME 214151497Sru wpa_s->sme.prev_bssid_set = 0; 215114402Sru#endif /* CONFIG_SME */ 216114402Sru wpa_s->reassociate = 1; 217114402Sru wpa_s->own_disconnect_req = 1; 218114402Sru wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 219114402Sru wpa_supplicant_req_scan(wpa_s, 0, 0); 220114402Sru 221114402Sru return 0; 222114402Sru} 223114402Sru 224151497Sru 225114402Sru#ifndef CONFIG_NO_CONFIG_BLOBS 226114402Srustatic int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos) 227114402Sru{ 228114402Sru char *name = pos; 229114402Sru struct wpa_config_blob *blob; 230114402Sru size_t len; 231114402Sru 232114402Sru pos = os_strchr(pos, ' '); 233114402Sru if (pos == NULL) 234114402Sru return -1; 235151497Sru *pos++ = '\0'; 236151497Sru len = os_strlen(pos); 237151497Sru if (len & 1) 238151497Sru return -1; 239151497Sru 240151497Sru wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name); 241151497Sru blob = os_zalloc(sizeof(*blob)); 242151497Sru if (blob == NULL) 243151497Sru return -1; 244151497Sru blob->name = os_strdup(name); 245151497Sru blob->data = os_malloc(len / 2); 246151497Sru if (blob->name == NULL || blob->data == NULL) { 247151497Sru wpa_config_free_blob(blob); 248151497Sru return -1; 249151497Sru } 250151497Sru 251151497Sru if (hexstr2bin(pos, blob->data, len / 2) < 0) { 252151497Sru wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data"); 253151497Sru wpa_config_free_blob(blob); 254151497Sru return -1; 255151497Sru } 256151497Sru blob->len = len / 2; 257151497Sru 258151497Sru wpa_config_set_blob(wpa_s->conf, blob); 259151497Sru 260151497Sru return 0; 261151497Sru} 262151497Sru#endif /* CONFIG_NO_CONFIG_BLOBS */ 263151497Sru 264151497Sru 265151497Srustatic int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd) 266151497Sru{ 267151497Sru char *params; 268151497Sru char *pos; 269151497Sru int *freqs = NULL; 270151497Sru int ret; 271151497Sru 272151497Sru if (atoi(cmd)) { 273151497Sru params = os_strchr(cmd, ' '); 274151497Sru os_free(wpa_s->manual_sched_scan_freqs); 275151497Sru if (params) { 276151497Sru params++; 277151497Sru pos = os_strstr(params, "freq="); 278151497Sru if (pos) 279151497Sru freqs = freq_range_to_channel_list(wpa_s, 280151497Sru pos + 5); 281151497Sru } 282151497Sru wpa_s->manual_sched_scan_freqs = freqs; 283151497Sru ret = wpas_start_pno(wpa_s); 284151497Sru } else { 285151497Sru ret = wpas_stop_pno(wpa_s); 286151497Sru } 287151497Sru return ret; 288151497Sru} 289151497Sru 290151497Sru 291151497Srustatic int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) 292151497Sru{ 293151497Sru union wpa_event_data event; 294151497Sru 295151497Sru if (os_strcmp(band, "AUTO") == 0) 296151497Sru wpa_s->setband = WPA_SETBAND_AUTO; 297151497Sru else if (os_strcmp(band, "5G") == 0) 298151497Sru wpa_s->setband = WPA_SETBAND_5G; 299151497Sru else if (os_strcmp(band, "2G") == 0) 300151497Sru wpa_s->setband = WPA_SETBAND_2G; 301151497Sru else 302151497Sru return -1; 303151497Sru 304151497Sru if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) { 305114402Sru os_memset(&event, 0, sizeof(event)); 306114402Sru event.channel_list_changed.initiator = REGDOM_SET_BY_USER; 307114402Sru event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; 308114402Sru wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event); 309114402Sru } 310114402Sru 311114402Sru return 0; 312114402Sru} 313114402Sru 314114402Sru 315114402Srustatic int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, 316114402Sru const char *cmd) 317114402Sru{ 318114402Sru struct wpabuf *lci; 319114402Sru 320114402Sru if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { 321114402Sru wpabuf_free(wpa_s->lci); 322151497Sru wpa_s->lci = NULL; 323114402Sru return 0; 324114402Sru } 325114402Sru 326114402Sru lci = wpabuf_parse_bin(cmd); 327114402Sru if (!lci) 328114402Sru return -1; 329114402Sru 330114402Sru if (os_get_reltime(&wpa_s->lci_time)) { 331114402Sru wpabuf_free(lci); 332114402Sru return -1; 333114402Sru } 334114402Sru 335114402Sru wpabuf_free(wpa_s->lci); 336114402Sru wpa_s->lci = lci; 337114402Sru 338114402Sru return 0; 339114402Sru} 340114402Sru 341114402Sru 342114402Srustatic int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, 343114402Sru char *cmd) 344114402Sru{ 345114402Sru char *value; 346114402Sru int ret = 0; 347114402Sru 348114402Sru value = os_strchr(cmd, ' '); 349114402Sru if (value == NULL) 350114402Sru return -1; 351114402Sru *value++ = '\0'; 352114402Sru 353114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); 354114402Sru if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { 355114402Sru eapol_sm_configure(wpa_s->eapol, 356114402Sru atoi(value), -1, -1, -1); 357114402Sru } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) { 358151497Sru eapol_sm_configure(wpa_s->eapol, 359114402Sru -1, atoi(value), -1, -1); 360114402Sru } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) { 361114402Sru eapol_sm_configure(wpa_s->eapol, 362114402Sru -1, -1, atoi(value), -1); 363151497Sru } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { 364114402Sru eapol_sm_configure(wpa_s->eapol, 365151497Sru -1, -1, -1, atoi(value)); 366114402Sru } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { 367114402Sru if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 368114402Sru atoi(value))) 369114402Sru ret = -1; 370114402Sru } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 371114402Sru 0) { 372114402Sru if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 373151497Sru atoi(value))) 374114402Sru ret = -1; 375114402Sru } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { 376114402Sru if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) 377114402Sru ret = -1; 378114402Sru } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { 379114402Sru wpa_s->wps_fragment_size = atoi(value); 380114402Sru#ifdef CONFIG_WPS_TESTING 381114402Sru } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { 382114402Sru long int val; 383114402Sru val = strtol(value, NULL, 0); 384114402Sru if (val < 0 || val > 0xff) { 385114402Sru ret = -1; 386114402Sru wpa_printf(MSG_DEBUG, "WPS: Invalid " 387114402Sru "wps_version_number %ld", val); 388151497Sru } else { 389114402Sru wps_version_number = val; 390114402Sru wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " 391114402Sru "version %u.%u", 392114402Sru (wps_version_number & 0xf0) >> 4, 393114402Sru wps_version_number & 0x0f); 394151497Sru } 395114402Sru } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { 396114402Sru wps_testing_dummy_cred = atoi(value); 397114402Sru wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", 398114402Sru wps_testing_dummy_cred); 399114402Sru } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { 400114402Sru wps_corrupt_pkhash = atoi(value); 401114402Sru wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", 402114402Sru wps_corrupt_pkhash); 403114402Sru } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) { 404114402Sru if (value[0] == '\0') { 405114402Sru wps_force_auth_types_in_use = 0; 406114402Sru } else { 407114402Sru wps_force_auth_types = strtol(value, NULL, 0); 408114402Sru wps_force_auth_types_in_use = 1; 409151497Sru } 410114402Sru } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) { 411114402Sru if (value[0] == '\0') { 412114402Sru wps_force_encr_types_in_use = 0; 413114402Sru } else { 414114402Sru wps_force_encr_types = strtol(value, NULL, 0); 415114402Sru wps_force_encr_types_in_use = 1; 416114402Sru } 417114402Sru#endif /* CONFIG_WPS_TESTING */ 418114402Sru } else if (os_strcasecmp(cmd, "ampdu") == 0) { 419114402Sru if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) 420114402Sru ret = -1; 421114402Sru#ifdef CONFIG_TDLS 422114402Sru#ifdef CONFIG_TDLS_TESTING 423114402Sru } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { 424114402Sru tdls_testing = strtol(value, NULL, 0); 425114402Sru wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); 426114402Sru#endif /* CONFIG_TDLS_TESTING */ 427114402Sru } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) { 428114402Sru int disabled = atoi(value); 429114402Sru wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled); 430114402Sru if (disabled) { 431114402Sru if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0) 432114402Sru ret = -1; 433114402Sru } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0) 434151497Sru ret = -1; 435114402Sru wpa_tdls_enable(wpa_s->wpa, !disabled); 436114402Sru#endif /* CONFIG_TDLS */ 437114402Sru } else if (os_strcasecmp(cmd, "pno") == 0) { 438114402Sru ret = wpas_ctrl_pno(wpa_s, value); 439114402Sru } else if (os_strcasecmp(cmd, "radio_disabled") == 0) { 440114402Sru int disabled = atoi(value); 441114402Sru if (wpa_drv_radio_disable(wpa_s, disabled) < 0) 442114402Sru ret = -1; 443114402Sru else if (disabled) 444114402Sru wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); 445114402Sru } else if (os_strcasecmp(cmd, "uapsd") == 0) { 446114402Sru if (os_strcmp(value, "disable") == 0) 447114402Sru wpa_s->set_sta_uapsd = 0; 448114402Sru else { 449114402Sru int be, bk, vi, vo; 450114402Sru char *pos; 451114402Sru /* format: BE,BK,VI,VO;max SP Length */ 452114402Sru be = atoi(value); 453114402Sru pos = os_strchr(value, ','); 454114402Sru if (pos == NULL) 455114402Sru return -1; 456114402Sru pos++; 457114402Sru bk = atoi(pos); 458114402Sru pos = os_strchr(pos, ','); 459114402Sru if (pos == NULL) 460114402Sru return -1; 461114402Sru pos++; 462114402Sru vi = atoi(pos); 463114402Sru pos = os_strchr(pos, ','); 464114402Sru if (pos == NULL) 465114402Sru return -1; 466114402Sru pos++; 467114402Sru vo = atoi(pos); 468114402Sru /* ignore max SP Length for now */ 469114402Sru 470114402Sru wpa_s->set_sta_uapsd = 1; 471114402Sru wpa_s->sta_uapsd = 0; 472114402Sru if (be) 473114402Sru wpa_s->sta_uapsd |= BIT(0); 474114402Sru if (bk) 475151497Sru wpa_s->sta_uapsd |= BIT(1); 476114402Sru if (vi) 477151497Sru wpa_s->sta_uapsd |= BIT(2); 478151497Sru if (vo) 479114402Sru wpa_s->sta_uapsd |= BIT(3); 480114402Sru } 481114402Sru } else if (os_strcasecmp(cmd, "ps") == 0) { 482114402Sru ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1); 483114402Sru#ifdef CONFIG_WIFI_DISPLAY 484114402Sru } else if (os_strcasecmp(cmd, "wifi_display") == 0) { 485114402Sru int enabled = !!atoi(value); 486114402Sru if (enabled && !wpa_s->global->p2p) 487114402Sru ret = -1; 488151497Sru else 489114402Sru wifi_display_enable(wpa_s->global, enabled); 490114402Sru#endif /* CONFIG_WIFI_DISPLAY */ 491114402Sru } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { 492114402Sru ret = set_bssid_filter(wpa_s, value); 493114402Sru } else if (os_strcasecmp(cmd, "disallow_aps") == 0) { 494114402Sru ret = set_disallow_aps(wpa_s, value); 495114402Sru } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) { 496114402Sru wpa_s->no_keep_alive = !!atoi(value); 497114402Sru#ifdef CONFIG_TESTING_OPTIONS 498114402Sru } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { 499114402Sru wpa_s->ext_mgmt_frame_handling = !!atoi(value); 500114402Sru } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { 501114402Sru wpa_s->ext_eapol_frame_io = !!atoi(value); 502114402Sru#ifdef CONFIG_AP 503114402Sru if (wpa_s->ap_iface) { 504114402Sru wpa_s->ap_iface->bss[0]->ext_eapol_frame_io = 505114402Sru wpa_s->ext_eapol_frame_io; 506114402Sru } 507114402Sru#endif /* CONFIG_AP */ 508114402Sru } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) { 509114402Sru wpa_s->extra_roc_dur = atoi(value); 510114402Sru } else if (os_strcasecmp(cmd, "test_failure") == 0) { 511114402Sru wpa_s->test_failure = atoi(value); 512114402Sru } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) { 513114402Sru wpa_s->p2p_go_csa_on_inv = !!atoi(value); 514114402Sru } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) { 515114402Sru wpa_s->ignore_auth_resp = !!atoi(value); 516114402Sru } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { 517114402Sru wpa_s->ignore_assoc_disallow = !!atoi(value); 518114402Sru } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) { 519114402Sru wpa_s->reject_btm_req_reason = atoi(value); 520151497Sru#endif /* CONFIG_TESTING_OPTIONS */ 521114402Sru#ifndef CONFIG_NO_CONFIG_BLOBS 522114402Sru } else if (os_strcmp(cmd, "blob") == 0) { 523114402Sru ret = wpas_ctrl_set_blob(wpa_s, value); 524151497Sru#endif /* CONFIG_NO_CONFIG_BLOBS */ 525114402Sru } else if (os_strcasecmp(cmd, "setband") == 0) { 526114402Sru ret = wpas_ctrl_set_band(wpa_s, value); 527114402Sru#ifdef CONFIG_MBO 528114402Sru } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { 529151497Sru ret = wpas_mbo_update_non_pref_chan(wpa_s, value); 530114402Sru } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { 531114402Sru wpas_mbo_update_cell_capa(wpa_s, atoi(value)); 532114402Sru#endif /* CONFIG_MBO */ 533114402Sru } else if (os_strcasecmp(cmd, "lci") == 0) { 534114402Sru ret = wpas_ctrl_iface_set_lci(wpa_s, value); 535114402Sru } else { 536114402Sru value[-1] = '='; 537114402Sru ret = wpa_config_process_global(wpa_s->conf, cmd, -1); 538114402Sru if (ret == 0) 539114402Sru wpa_supplicant_update_config(wpa_s); 540114402Sru } 541114402Sru 542114402Sru return ret; 543114402Sru} 544114402Sru 545114402Sru 546114402Srustatic int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, 547114402Sru char *cmd, char *buf, size_t buflen) 548114402Sru{ 549114402Sru int res = -1; 550114402Sru 551114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); 552114402Sru 553114402Sru if (os_strcmp(cmd, "version") == 0) { 554114402Sru res = os_snprintf(buf, buflen, "%s", VERSION_STR); 555114402Sru } else if (os_strcasecmp(cmd, "country") == 0) { 556114402Sru if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) 557114402Sru res = os_snprintf(buf, buflen, "%c%c", 558114402Sru wpa_s->conf->country[0], 559114402Sru wpa_s->conf->country[1]); 560114402Sru#ifdef CONFIG_WIFI_DISPLAY 561114402Sru } else if (os_strcasecmp(cmd, "wifi_display") == 0) { 562114402Sru int enabled; 563114402Sru if (wpa_s->global->p2p == NULL || 564114402Sru wpa_s->global->p2p_disabled) 565114402Sru enabled = 0; 566114402Sru else 567114402Sru enabled = wpa_s->global->wifi_display; 568114402Sru res = os_snprintf(buf, buflen, "%d", enabled); 569114402Sru#endif /* CONFIG_WIFI_DISPLAY */ 570114402Sru#ifdef CONFIG_TESTING_GET_GTK 571114402Sru } else if (os_strcmp(cmd, "gtk") == 0) { 572114402Sru if (wpa_s->last_gtk_len == 0) 573114402Sru return -1; 574114402Sru res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk, 575114402Sru wpa_s->last_gtk_len); 576114402Sru return res; 577114402Sru#endif /* CONFIG_TESTING_GET_GTK */ 578114402Sru } else if (os_strcmp(cmd, "tls_library") == 0) { 579114402Sru res = tls_get_library_version(buf, buflen); 580151497Sru } else { 581114402Sru res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen); 582114402Sru } 583114402Sru 584151497Sru if (os_snprintf_error(buflen, res)) 585114402Sru return -1; 586114402Sru return res; 587114402Sru} 588114402Sru 589114402Sru 590114402Sru#ifdef IEEE8021X_EAPOL 591114402Srustatic int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, 592114402Sru char *addr) 593114402Sru{ 594114402Sru u8 bssid[ETH_ALEN]; 595114402Sru struct wpa_ssid *ssid = wpa_s->current_ssid; 596114402Sru 597114402Sru if (hwaddr_aton(addr, bssid)) { 598114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address " 599114402Sru "'%s'", addr); 600114402Sru return -1; 601114402Sru } 602114402Sru 603114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid)); 604114402Sru rsn_preauth_deinit(wpa_s->wpa); 605114402Sru if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL)) 606114402Sru return -1; 607114402Sru 608114402Sru return 0; 609114402Sru} 610114402Sru#endif /* IEEE8021X_EAPOL */ 611114402Sru 612114402Sru 613114402Sru#ifdef CONFIG_PEERKEY 614114402Sru/* MLME-STKSTART.request(peer) */ 615114402Srustatic int wpa_supplicant_ctrl_iface_stkstart( 616114402Sru struct wpa_supplicant *wpa_s, char *addr) 617114402Sru{ 618114402Sru u8 peer[ETH_ALEN]; 619114402Sru 620114402Sru if (hwaddr_aton(addr, peer)) { 621114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid " 622114402Sru "address '%s'", addr); 623114402Sru return -1; 624114402Sru } 625114402Sru 626114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR, 627114402Sru MAC2STR(peer)); 628114402Sru 629114402Sru return wpa_sm_stkstart(wpa_s->wpa, peer); 630114402Sru} 631114402Sru#endif /* CONFIG_PEERKEY */ 632114402Sru 633114402Sru 634114402Sru#ifdef CONFIG_TDLS 635114402Sru 636114402Srustatic int wpa_supplicant_ctrl_iface_tdls_discover( 637114402Sru struct wpa_supplicant *wpa_s, char *addr) 638114402Sru{ 639114402Sru u8 peer[ETH_ALEN]; 640114402Sru int ret; 641114402Sru 642114402Sru if (hwaddr_aton(addr, peer)) { 643114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid " 644114402Sru "address '%s'", addr); 645114402Sru return -1; 646114402Sru } 647114402Sru 648114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR, 649114402Sru MAC2STR(peer)); 650114402Sru 651114402Sru if (wpa_tdls_is_external_setup(wpa_s->wpa)) 652114402Sru ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); 653114402Sru else 654114402Sru ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); 655114402Sru 656114402Sru return ret; 657114402Sru} 658114402Sru 659114402Sru 660114402Srustatic int wpa_supplicant_ctrl_iface_tdls_setup( 661114402Sru struct wpa_supplicant *wpa_s, char *addr) 662151497Sru{ 663114402Sru u8 peer[ETH_ALEN]; 664114402Sru int ret; 665114402Sru 666114402Sru if (hwaddr_aton(addr, peer)) { 667114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid " 668114402Sru "address '%s'", addr); 669114402Sru return -1; 670114402Sru } 671151497Sru 672114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR, 673114402Sru MAC2STR(peer)); 674151497Sru 675151497Sru if ((wpa_s->conf->tdls_external_control) && 676151497Sru wpa_tdls_is_external_setup(wpa_s->wpa)) 677114402Sru return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); 678151497Sru 679151497Sru wpa_tdls_remove(wpa_s->wpa, peer); 680151497Sru 681151497Sru if (wpa_tdls_is_external_setup(wpa_s->wpa)) 682151497Sru ret = wpa_tdls_start(wpa_s->wpa, peer); 683114402Sru else 684151497Sru ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); 685114402Sru 686114402Sru return ret; 687151497Sru} 688151497Sru 689151497Sru 690151497Srustatic int wpa_supplicant_ctrl_iface_tdls_teardown( 691151497Sru struct wpa_supplicant *wpa_s, char *addr) 692151497Sru{ 693151497Sru u8 peer[ETH_ALEN]; 694151497Sru int ret; 695151497Sru 696114402Sru if (os_strcmp(addr, "*") == 0) { 697114402Sru /* remove everyone */ 698151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *"); 699151497Sru wpa_tdls_teardown_peers(wpa_s->wpa); 700151497Sru return 0; 701114402Sru } 702114402Sru 703114402Sru if (hwaddr_aton(addr, peer)) { 704151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid " 705114402Sru "address '%s'", addr); 706114402Sru return -1; 707114402Sru } 708114402Sru 709151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR, 710151497Sru MAC2STR(peer)); 711151497Sru 712114402Sru if ((wpa_s->conf->tdls_external_control) && 713114402Sru wpa_tdls_is_external_setup(wpa_s->wpa)) 714114402Sru return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); 715151497Sru 716151497Sru if (wpa_tdls_is_external_setup(wpa_s->wpa)) 717151497Sru ret = wpa_tdls_teardown_link( 718151497Sru wpa_s->wpa, peer, 719151497Sru WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 720151497Sru else 721151497Sru ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); 722151497Sru 723151497Sru return ret; 724114402Sru} 725114402Sru 726114402Sru 727114402Srustatic int ctrl_iface_get_capability_tdls( 728114402Sru struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 729151497Sru{ 730151497Sru int ret; 731114402Sru 732114402Sru ret = os_snprintf(buf, buflen, "%s\n", 733114402Sru wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ? 734114402Sru (wpa_s->drv_flags & 735114402Sru WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ? 736114402Sru "EXTERNAL" : "INTERNAL") : "UNSUPPORTED"); 737114402Sru if (os_snprintf_error(buflen, ret)) 738114402Sru return -1; 739151497Sru return ret; 740151497Sru} 741114402Sru 742114402Sru 743114402Srustatic int wpa_supplicant_ctrl_iface_tdls_chan_switch( 744114402Sru struct wpa_supplicant *wpa_s, char *cmd) 745114402Sru{ 746114402Sru u8 peer[ETH_ALEN]; 747114402Sru struct hostapd_freq_params freq_params; 748114402Sru u8 oper_class; 749151497Sru char *pos, *end; 750151497Sru 751114402Sru if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { 752114402Sru wpa_printf(MSG_INFO, 753114402Sru "tdls_chanswitch: Only supported with external setup"); 754114402Sru return -1; 755114402Sru } 756114402Sru 757114402Sru os_memset(&freq_params, 0, sizeof(freq_params)); 758114402Sru 759151497Sru pos = os_strchr(cmd, ' '); 760151497Sru if (pos == NULL) 761114402Sru return -1; 762114402Sru *pos++ = '\0'; 763114402Sru 764151497Sru oper_class = strtol(pos, &end, 10); 765151497Sru if (pos == end) { 766151497Sru wpa_printf(MSG_INFO, 767151497Sru "tdls_chanswitch: Invalid op class provided"); 768151497Sru return -1; 769151497Sru } 770151497Sru 771151497Sru pos = end; 772151497Sru freq_params.freq = atoi(pos); 773151497Sru if (freq_params.freq == 0) { 774114402Sru wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided"); 775114402Sru return -1; 776114402Sru } 777114402Sru 778114402Sru#define SET_FREQ_SETTING(str) \ 779151497Sru do { \ 780151497Sru const char *pos2 = os_strstr(pos, " " #str "="); \ 781114402Sru if (pos2) { \ 782114402Sru pos2 += sizeof(" " #str "=") - 1; \ 783114402Sru freq_params.str = atoi(pos2); \ 784114402Sru } \ 785114402Sru } while (0) 786114402Sru 787114402Sru SET_FREQ_SETTING(center_freq1); 788114402Sru SET_FREQ_SETTING(center_freq2); 789151497Sru SET_FREQ_SETTING(bandwidth); 790114402Sru SET_FREQ_SETTING(sec_channel_offset); 791114402Sru#undef SET_FREQ_SETTING 792114402Sru 793114402Sru freq_params.ht_enabled = !!os_strstr(pos, " ht"); 794114402Sru freq_params.vht_enabled = !!os_strstr(pos, " vht"); 795114402Sru 796114402Sru if (hwaddr_aton(cmd, peer)) { 797114402Sru wpa_printf(MSG_DEBUG, 798151497Sru "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'", 799114402Sru cmd); 800114402Sru return -1; 801114402Sru } 802114402Sru 803114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR 804114402Sru " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s", 805114402Sru MAC2STR(peer), oper_class, freq_params.freq, 806114402Sru freq_params.center_freq1, freq_params.center_freq2, 807151497Sru freq_params.bandwidth, freq_params.sec_channel_offset, 808151497Sru freq_params.ht_enabled ? " HT" : "", 809114402Sru freq_params.vht_enabled ? " VHT" : ""); 810114402Sru 811114402Sru return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class, 812114402Sru &freq_params); 813114402Sru} 814114402Sru 815114402Sru 816114402Srustatic int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch( 817151497Sru struct wpa_supplicant *wpa_s, char *cmd) 818151497Sru{ 819114402Sru u8 peer[ETH_ALEN]; 820114402Sru 821114402Sru if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { 822114402Sru wpa_printf(MSG_INFO, 823114402Sru "tdls_chanswitch: Only supported with external setup"); 824114402Sru return -1; 825114402Sru } 826114402Sru 827151497Sru if (hwaddr_aton(cmd, peer)) { 828151497Sru wpa_printf(MSG_DEBUG, 829114402Sru "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'", 830114402Sru cmd); 831114402Sru return -1; 832114402Sru } 833114402Sru 834114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR, 835114402Sru MAC2STR(peer)); 836114402Sru 837114402Sru return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer); 838114402Sru} 839114402Sru 840114402Sru 841114402Srustatic int wpa_supplicant_ctrl_iface_tdls_link_status( 842114402Sru struct wpa_supplicant *wpa_s, const char *addr, 843114402Sru char *buf, size_t buflen) 844114402Sru{ 845114402Sru u8 peer[ETH_ALEN]; 846114402Sru const char *tdls_status; 847114402Sru int ret; 848114402Sru 849114402Sru if (hwaddr_aton(addr, peer)) { 850151497Sru wpa_printf(MSG_DEBUG, 851151497Sru "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'", 852151497Sru addr); 853114402Sru return -1; 854114402Sru } 855114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR, 856114402Sru MAC2STR(peer)); 857151497Sru 858114402Sru tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); 859114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status); 860114402Sru ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status); 861114402Sru if (os_snprintf_error(buflen, ret)) 862114402Sru return -1; 863114402Sru 864114402Sru return ret; 865114402Sru} 866114402Sru 867114402Sru#endif /* CONFIG_TDLS */ 868114402Sru 869114402Sru 870114402Srustatic int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd) 871114402Sru{ 872114402Sru char *token, *context = NULL; 873114402Sru struct wmm_ac_ts_setup_params params = { 874114402Sru .tsid = 0xff, 875114402Sru .direction = 0xff, 876114402Sru }; 877151497Sru 878114402Sru while ((token = str_token(cmd, " ", &context))) { 879114402Sru if (sscanf(token, "tsid=%i", ¶ms.tsid) == 1 || 880114402Sru sscanf(token, "up=%i", ¶ms.user_priority) == 1 || 881114402Sru sscanf(token, "nominal_msdu_size=%i", 882114402Sru ¶ms.nominal_msdu_size) == 1 || 883114402Sru sscanf(token, "mean_data_rate=%i", 884114402Sru ¶ms.mean_data_rate) == 1 || 885114402Sru sscanf(token, "min_phy_rate=%i", 886114402Sru ¶ms.minimum_phy_rate) == 1 || 887114402Sru sscanf(token, "sba=%i", 888114402Sru ¶ms.surplus_bandwidth_allowance) == 1) 889114402Sru continue; 890114402Sru 891114402Sru if (os_strcasecmp(token, "downlink") == 0) { 892114402Sru params.direction = WMM_TSPEC_DIRECTION_DOWNLINK; 893114402Sru } else if (os_strcasecmp(token, "uplink") == 0) { 894114402Sru params.direction = WMM_TSPEC_DIRECTION_UPLINK; 895114402Sru } else if (os_strcasecmp(token, "bidi") == 0) { 896114402Sru params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL; 897114402Sru } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) { 898114402Sru params.fixed_nominal_msdu = 1; 899114402Sru } else { 900114402Sru wpa_printf(MSG_DEBUG, 901114402Sru "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'", 902114402Sru token); 903114402Sru return -1; 904114402Sru } 905114402Sru 906114402Sru } 907114402Sru 908114402Sru return wpas_wmm_ac_addts(wpa_s, ¶ms); 909114402Sru} 910114402Sru 911114402Sru 912114402Srustatic int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd) 913114402Sru{ 914114402Sru u8 tsid = atoi(cmd); 915114402Sru 916114402Sru return wpas_wmm_ac_delts(wpa_s, tsid); 917114402Sru} 918114402Sru 919151497Sru 920151497Sru#ifdef CONFIG_IEEE80211R 921151497Srustatic int wpa_supplicant_ctrl_iface_ft_ds( 922151497Sru struct wpa_supplicant *wpa_s, char *addr) 923151497Sru{ 924114402Sru u8 target_ap[ETH_ALEN]; 925114402Sru struct wpa_bss *bss; 926114402Sru const u8 *mdie; 927114402Sru 928114402Sru if (hwaddr_aton(addr, target_ap)) { 929114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid " 930114402Sru "address '%s'", addr); 931114402Sru return -1; 932114402Sru } 933114402Sru 934114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap)); 935114402Sru 936114402Sru bss = wpa_bss_get_bssid(wpa_s, target_ap); 937114402Sru if (bss) 938114402Sru mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); 939114402Sru else 940114402Sru mdie = NULL; 941114402Sru 942114402Sru return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie); 943114402Sru} 944114402Sru#endif /* CONFIG_IEEE80211R */ 945114402Sru 946114402Sru 947114402Sru#ifdef CONFIG_WPS 948114402Srustatic int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, 949114402Sru char *cmd) 950114402Sru{ 951114402Sru u8 bssid[ETH_ALEN], *_bssid = bssid; 952114402Sru#ifdef CONFIG_P2P 953114402Sru u8 p2p_dev_addr[ETH_ALEN]; 954114402Sru#endif /* CONFIG_P2P */ 955114402Sru#ifdef CONFIG_AP 956114402Sru u8 *_p2p_dev_addr = NULL; 957114402Sru#endif /* CONFIG_AP */ 958114402Sru 959114402Sru if (cmd == NULL || os_strcmp(cmd, "any") == 0) { 960114402Sru _bssid = NULL; 961114402Sru#ifdef CONFIG_P2P 962114402Sru } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { 963114402Sru if (hwaddr_aton(cmd + 13, p2p_dev_addr)) { 964114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid " 965114402Sru "P2P Device Address '%s'", 966114402Sru cmd + 13); 967114402Sru return -1; 968114402Sru } 969114402Sru _p2p_dev_addr = p2p_dev_addr; 970114402Sru#endif /* CONFIG_P2P */ 971114402Sru } else if (hwaddr_aton(cmd, bssid)) { 972114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", 973114402Sru cmd); 974114402Sru return -1; 975114402Sru } 976114402Sru 977114402Sru#ifdef CONFIG_AP 978114402Sru if (wpa_s->ap_iface) 979114402Sru return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); 980114402Sru#endif /* CONFIG_AP */ 981114402Sru 982114402Sru return wpas_wps_start_pbc(wpa_s, _bssid, 0); 983114402Sru} 984114402Sru 985114402Sru 986114402Srustatic int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, 987114402Sru char *cmd, char *buf, 988114402Sru size_t buflen) 989114402Sru{ 990114402Sru u8 bssid[ETH_ALEN], *_bssid = bssid; 991114402Sru char *pin; 992114402Sru int ret; 993114402Sru 994114402Sru pin = os_strchr(cmd, ' '); 995114402Sru if (pin) 996114402Sru *pin++ = '\0'; 997114402Sru 998114402Sru if (os_strcmp(cmd, "any") == 0) 999114402Sru _bssid = NULL; 1000114402Sru else if (os_strcmp(cmd, "get") == 0) { 1001114402Sru if (wps_generate_pin((unsigned int *) &ret) < 0) 1002114402Sru return -1; 1003114402Sru goto done; 1004114402Sru } else if (hwaddr_aton(cmd, bssid)) { 1005114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", 1006114402Sru cmd); 1007114402Sru return -1; 1008114402Sru } 1009114402Sru 1010114402Sru#ifdef CONFIG_AP 1011114402Sru if (wpa_s->ap_iface) { 1012114402Sru int timeout = 0; 1013114402Sru char *pos; 1014114402Sru 1015114402Sru if (pin) { 1016114402Sru pos = os_strchr(pin, ' '); 1017114402Sru if (pos) { 1018114402Sru *pos++ = '\0'; 1019114402Sru timeout = atoi(pos); 1020114402Sru } 1021114402Sru } 1022114402Sru 1023114402Sru return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin, 1024114402Sru buf, buflen, timeout); 1025114402Sru } 1026114402Sru#endif /* CONFIG_AP */ 1027114402Sru 1028114402Sru if (pin) { 1029114402Sru ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, 1030114402Sru DEV_PW_DEFAULT); 1031114402Sru if (ret < 0) 1032114402Sru return -1; 1033114402Sru ret = os_snprintf(buf, buflen, "%s", pin); 1034114402Sru if (os_snprintf_error(buflen, ret)) 1035114402Sru return -1; 1036114402Sru return ret; 1037114402Sru } 1038114402Sru 1039151497Sru ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); 1040151497Sru if (ret < 0) 1041114402Sru return -1; 1042114402Sru 1043114402Srudone: 1044114402Sru /* Return the generated PIN */ 1045114402Sru ret = os_snprintf(buf, buflen, "%08d", ret); 1046114402Sru if (os_snprintf_error(buflen, ret)) 1047114402Sru return -1; 1048114402Sru return ret; 1049151497Sru} 1050151497Sru 1051151497Sru 1052151497Srustatic int wpa_supplicant_ctrl_iface_wps_check_pin( 1053151497Sru struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 1054151497Sru{ 1055151497Sru char pin[9]; 1056114402Sru size_t len; 1057114402Sru char *pos; 1058114402Sru int ret; 1059114402Sru 1060114402Sru wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", 1061114402Sru (u8 *) cmd, os_strlen(cmd)); 1062114402Sru for (pos = cmd, len = 0; *pos != '\0'; pos++) { 1063114402Sru if (*pos < '0' || *pos > '9') 1064151497Sru continue; 1065114402Sru pin[len++] = *pos; 1066114402Sru if (len == 9) { 1067114402Sru wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); 1068114402Sru return -1; 1069114402Sru } 1070114402Sru } 1071114402Sru if (len != 4 && len != 8) { 1072114402Sru wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); 1073151497Sru return -1; 1074114402Sru } 1075114402Sru pin[len] = '\0'; 1076114402Sru 1077114402Sru if (len == 8) { 1078114402Sru unsigned int pin_val; 1079114402Sru pin_val = atoi(pin); 1080114402Sru if (!wps_pin_valid(pin_val)) { 1081114402Sru wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); 1082151497Sru ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); 1083114402Sru if (os_snprintf_error(buflen, ret)) 1084114402Sru return -1; 1085114402Sru return ret; 1086114402Sru } 1087114402Sru } 1088114402Sru 1089114402Sru ret = os_snprintf(buf, buflen, "%s", pin); 1090114402Sru if (os_snprintf_error(buflen, ret)) 1091114402Sru return -1; 1092114402Sru 1093114402Sru return ret; 1094114402Sru} 1095114402Sru 1096114402Sru 1097114402Sru#ifdef CONFIG_WPS_NFC 1098151497Sru 1099151497Srustatic int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s, 1100114402Sru char *cmd) 1101151497Sru{ 1102151497Sru u8 bssid[ETH_ALEN], *_bssid = bssid; 1103151497Sru 1104114402Sru if (cmd == NULL || cmd[0] == '\0') 1105151497Sru _bssid = NULL; 1106114402Sru else if (hwaddr_aton(cmd, bssid)) 1107151497Sru return -1; 1108114402Sru 1109114402Sru return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL, 1110114402Sru 0, 0); 1111151497Sru} 1112114402Sru 1113114402Sru 1114114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_config_token( 1115114402Sru struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1116114402Sru{ 1117114402Sru int ndef; 1118114402Sru struct wpabuf *buf; 1119114402Sru int res; 1120114402Sru char *pos; 1121114402Sru 1122114402Sru pos = os_strchr(cmd, ' '); 1123114402Sru if (pos) 1124114402Sru *pos++ = '\0'; 1125114402Sru if (os_strcmp(cmd, "WPS") == 0) 1126114402Sru ndef = 0; 1127114402Sru else if (os_strcmp(cmd, "NDEF") == 0) 1128114402Sru ndef = 1; 1129114402Sru else 1130114402Sru return -1; 1131114402Sru 1132114402Sru buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos); 1133114402Sru if (buf == NULL) 1134114402Sru return -1; 1135114402Sru 1136114402Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1137114402Sru wpabuf_len(buf)); 1138114402Sru reply[res++] = '\n'; 1139151497Sru reply[res] = '\0'; 1140114402Sru 1141114402Sru wpabuf_free(buf); 1142114402Sru 1143114402Sru return res; 1144114402Sru} 1145114402Sru 1146114402Sru 1147114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_token( 1148151497Sru struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1149114402Sru{ 1150114402Sru int ndef; 1151114402Sru struct wpabuf *buf; 1152114402Sru int res; 1153114402Sru 1154114402Sru if (os_strcmp(cmd, "WPS") == 0) 1155114402Sru ndef = 0; 1156114402Sru else if (os_strcmp(cmd, "NDEF") == 0) 1157151497Sru ndef = 1; 1158114402Sru else 1159114402Sru return -1; 1160114402Sru 1161114402Sru buf = wpas_wps_nfc_token(wpa_s, ndef); 1162114402Sru if (buf == NULL) 1163114402Sru return -1; 1164114402Sru 1165114402Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1166114402Sru wpabuf_len(buf)); 1167114402Sru reply[res++] = '\n'; 1168114402Sru reply[res] = '\0'; 1169114402Sru 1170114402Sru wpabuf_free(buf); 1171114402Sru 1172114402Sru return res; 1173114402Sru} 1174114402Sru 1175114402Sru 1176114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_tag_read( 1177114402Sru struct wpa_supplicant *wpa_s, char *pos) 1178114402Sru{ 1179114402Sru size_t len; 1180114402Sru struct wpabuf *buf; 1181114402Sru int ret; 1182114402Sru char *freq; 1183114402Sru int forced_freq = 0; 1184151497Sru 1185114402Sru freq = strstr(pos, " freq="); 1186114402Sru if (freq) { 1187114402Sru *freq = '\0'; 1188114402Sru freq += 6; 1189114402Sru forced_freq = atoi(freq); 1190114402Sru } 1191114402Sru 1192114402Sru len = os_strlen(pos); 1193114402Sru if (len & 0x01) 1194114402Sru return -1; 1195151497Sru len /= 2; 1196151497Sru 1197151497Sru buf = wpabuf_alloc(len); 1198151497Sru if (buf == NULL) 1199114402Sru return -1; 1200114402Sru if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 1201114402Sru wpabuf_free(buf); 1202114402Sru return -1; 1203114402Sru } 1204114402Sru 1205114402Sru ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq); 1206114402Sru wpabuf_free(buf); 1207114402Sru 1208114402Sru return ret; 1209151497Sru} 1210151497Sru 1211151497Sru 1212151497Srustatic int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s, 1213114402Sru char *reply, size_t max_len, 1214114402Sru int ndef) 1215114402Sru{ 1216114402Sru struct wpabuf *buf; 1217114402Sru int res; 1218114402Sru 1219114402Sru buf = wpas_wps_nfc_handover_req(wpa_s, ndef); 1220114402Sru if (buf == NULL) 1221114402Sru return -1; 1222114402Sru 1223114402Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1224151497Sru wpabuf_len(buf)); 1225114402Sru reply[res++] = '\n'; 1226114402Sru reply[res] = '\0'; 1227114402Sru 1228114402Sru wpabuf_free(buf); 1229114402Sru 1230114402Sru return res; 1231114402Sru} 1232114402Sru 1233114402Sru 1234114402Sru#ifdef CONFIG_P2P 1235114402Srustatic int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s, 1236114402Sru char *reply, size_t max_len, 1237114402Sru int ndef) 1238114402Sru{ 1239114402Sru struct wpabuf *buf; 1240114402Sru int res; 1241114402Sru 1242114402Sru buf = wpas_p2p_nfc_handover_req(wpa_s, ndef); 1243114402Sru if (buf == NULL) { 1244114402Sru wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request"); 1245114402Sru return -1; 1246114402Sru } 1247114402Sru 1248114402Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1249114402Sru wpabuf_len(buf)); 1250114402Sru reply[res++] = '\n'; 1251114402Sru reply[res] = '\0'; 1252114402Sru 1253114402Sru wpabuf_free(buf); 1254114402Sru 1255114402Sru return res; 1256114402Sru} 1257114402Sru#endif /* CONFIG_P2P */ 1258114402Sru 1259114402Sru 1260114402Srustatic int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s, 1261114402Sru char *cmd, char *reply, 1262114402Sru size_t max_len) 1263114402Sru{ 1264114402Sru char *pos; 1265114402Sru int ndef; 1266114402Sru 1267151497Sru pos = os_strchr(cmd, ' '); 1268151497Sru if (pos == NULL) 1269114402Sru return -1; 1270114402Sru *pos++ = '\0'; 1271114402Sru 1272114402Sru if (os_strcmp(cmd, "WPS") == 0) 1273114402Sru ndef = 0; 1274114402Sru else if (os_strcmp(cmd, "NDEF") == 0) 1275114402Sru ndef = 1; 1276114402Sru else 1277114402Sru return -1; 1278114402Sru 1279114402Sru if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { 1280114402Sru if (!ndef) 1281114402Sru return -1; 1282114402Sru return wpas_ctrl_nfc_get_handover_req_wps( 1283114402Sru wpa_s, reply, max_len, ndef); 1284114402Sru } 1285114402Sru 1286114402Sru#ifdef CONFIG_P2P 1287114402Sru if (os_strcmp(pos, "P2P-CR") == 0) { 1288114402Sru return wpas_ctrl_nfc_get_handover_req_p2p( 1289114402Sru wpa_s, reply, max_len, ndef); 1290114402Sru } 1291114402Sru#endif /* CONFIG_P2P */ 1292114402Sru 1293114402Sru return -1; 1294114402Sru} 1295114402Sru 1296114402Sru 1297114402Srustatic int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s, 1298114402Sru char *reply, size_t max_len, 1299114402Sru int ndef, int cr, char *uuid) 1300114402Sru{ 1301114402Sru struct wpabuf *buf; 1302114402Sru int res; 1303114402Sru 1304114402Sru buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid); 1305114402Sru if (buf == NULL) 1306114402Sru return -1; 1307114402Sru 1308114402Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1309114402Sru wpabuf_len(buf)); 1310114402Sru reply[res++] = '\n'; 1311114402Sru reply[res] = '\0'; 1312114402Sru 1313114402Sru wpabuf_free(buf); 1314114402Sru 1315114402Sru return res; 1316114402Sru} 1317114402Sru 1318114402Sru 1319114402Sru#ifdef CONFIG_P2P 1320114402Srustatic int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s, 1321114402Sru char *reply, size_t max_len, 1322114402Sru int ndef, int tag) 1323114402Sru{ 1324114402Sru struct wpabuf *buf; 1325114402Sru int res; 1326114402Sru 1327114402Sru buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag); 1328114402Sru if (buf == NULL) 1329114402Sru return -1; 1330151497Sru 1331151497Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1332114402Sru wpabuf_len(buf)); 1333114402Sru reply[res++] = '\n'; 1334114402Sru reply[res] = '\0'; 1335114402Sru 1336114402Sru wpabuf_free(buf); 1337114402Sru 1338114402Sru return res; 1339114402Sru} 1340114402Sru#endif /* CONFIG_P2P */ 1341114402Sru 1342114402Sru 1343114402Srustatic int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s, 1344114402Sru char *cmd, char *reply, 1345114402Sru size_t max_len) 1346114402Sru{ 1347114402Sru char *pos, *pos2; 1348114402Sru int ndef; 1349114402Sru 1350151497Sru pos = os_strchr(cmd, ' '); 1351114402Sru if (pos == NULL) 1352114402Sru return -1; 1353151497Sru *pos++ = '\0'; 1354114402Sru 1355114402Sru if (os_strcmp(cmd, "WPS") == 0) 1356151497Sru ndef = 0; 1357151497Sru else if (os_strcmp(cmd, "NDEF") == 0) 1358114402Sru ndef = 1; 1359151497Sru else 1360151497Sru return -1; 1361151497Sru 1362114402Sru pos2 = os_strchr(pos, ' '); 1363114402Sru if (pos2) 1364114402Sru *pos2++ = '\0'; 1365114402Sru if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { 1366114402Sru if (!ndef) 1367114402Sru return -1; 1368114402Sru return wpas_ctrl_nfc_get_handover_sel_wps( 1369114402Sru wpa_s, reply, max_len, ndef, 1370114402Sru os_strcmp(pos, "WPS-CR") == 0, pos2); 1371114402Sru } 1372114402Sru 1373114402Sru#ifdef CONFIG_P2P 1374114402Sru if (os_strcmp(pos, "P2P-CR") == 0) { 1375114402Sru return wpas_ctrl_nfc_get_handover_sel_p2p( 1376114402Sru wpa_s, reply, max_len, ndef, 0); 1377114402Sru } 1378114402Sru 1379114402Sru if (os_strcmp(pos, "P2P-CR-TAG") == 0) { 1380114402Sru return wpas_ctrl_nfc_get_handover_sel_p2p( 1381114402Sru wpa_s, reply, max_len, ndef, 1); 1382114402Sru } 1383114402Sru#endif /* CONFIG_P2P */ 1384114402Sru 1385114402Sru return -1; 1386114402Sru} 1387114402Sru 1388114402Sru 1389114402Srustatic int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s, 1390114402Sru char *cmd) 1391151497Sru{ 1392151497Sru size_t len; 1393114402Sru struct wpabuf *req, *sel; 1394114402Sru int ret; 1395114402Sru char *pos, *role, *type, *pos2; 1396114402Sru#ifdef CONFIG_P2P 1397114402Sru char *freq; 1398114402Sru int forced_freq = 0; 1399114402Sru 1400114402Sru freq = strstr(cmd, " freq="); 1401114402Sru if (freq) { 1402114402Sru *freq = '\0'; 1403114402Sru freq += 6; 1404114402Sru forced_freq = atoi(freq); 1405114402Sru } 1406114402Sru#endif /* CONFIG_P2P */ 1407114402Sru 1408114402Sru role = cmd; 1409114402Sru pos = os_strchr(role, ' '); 1410114402Sru if (pos == NULL) { 1411114402Sru wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report"); 1412114402Sru return -1; 1413114402Sru } 1414114402Sru *pos++ = '\0'; 1415114402Sru 1416114402Sru type = pos; 1417114402Sru pos = os_strchr(type, ' '); 1418114402Sru if (pos == NULL) { 1419151497Sru wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report"); 1420114402Sru return -1; 1421151497Sru } 1422151497Sru *pos++ = '\0'; 1423114402Sru 1424114402Sru pos2 = os_strchr(pos, ' '); 1425114402Sru if (pos2 == NULL) { 1426114402Sru wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report"); 1427114402Sru return -1; 1428114402Sru } 1429114402Sru *pos2++ = '\0'; 1430114402Sru 1431151497Sru len = os_strlen(pos); 1432151497Sru if (len & 0x01) { 1433151497Sru wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report"); 1434151497Sru return -1; 1435151497Sru } 1436151497Sru len /= 2; 1437151497Sru 1438151497Sru req = wpabuf_alloc(len); 1439151497Sru if (req == NULL) { 1440151497Sru wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message"); 1441151497Sru return -1; 1442151497Sru } 1443114402Sru if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { 1444114402Sru wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report"); 1445114402Sru wpabuf_free(req); 1446114402Sru return -1; 1447114402Sru } 1448114402Sru 1449114402Sru len = os_strlen(pos2); 1450114402Sru if (len & 0x01) { 1451114402Sru wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report"); 1452114402Sru wpabuf_free(req); 1453114402Sru return -1; 1454114402Sru } 1455114402Sru len /= 2; 1456114402Sru 1457114402Sru sel = wpabuf_alloc(len); 1458114402Sru if (sel == NULL) { 1459114402Sru wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message"); 1460114402Sru wpabuf_free(req); 1461114402Sru return -1; 1462114402Sru } 1463114402Sru if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { 1464114402Sru wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report"); 1465114402Sru wpabuf_free(req); 1466114402Sru wpabuf_free(sel); 1467114402Sru return -1; 1468114402Sru } 1469114402Sru 1470114402Sru wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d", 1471114402Sru role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel)); 1472114402Sru 1473114402Sru if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) { 1474114402Sru ret = wpas_wps_nfc_report_handover(wpa_s, req, sel); 1475114402Sru#ifdef CONFIG_AP 1476114402Sru } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) 1477114402Sru { 1478114402Sru ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel); 1479114402Sru if (ret < 0) 1480114402Sru ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel); 1481114402Sru#endif /* CONFIG_AP */ 1482114402Sru#ifdef CONFIG_P2P 1483114402Sru } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0) 1484114402Sru { 1485114402Sru ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0); 1486114402Sru } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0) 1487114402Sru { 1488114402Sru ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel, 1489114402Sru forced_freq); 1490114402Sru#endif /* CONFIG_P2P */ 1491114402Sru } else { 1492114402Sru wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " 1493114402Sru "reported: role=%s type=%s", role, type); 1494114402Sru ret = -1; 1495114402Sru } 1496114402Sru wpabuf_free(req); 1497114402Sru wpabuf_free(sel); 1498114402Sru 1499114402Sru if (ret) 1500114402Sru wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages"); 1501114402Sru 1502114402Sru return ret; 1503114402Sru} 1504114402Sru 1505114402Sru#endif /* CONFIG_WPS_NFC */ 1506114402Sru 1507114402Sru 1508114402Srustatic int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s, 1509114402Sru char *cmd) 1510114402Sru{ 1511114402Sru u8 bssid[ETH_ALEN]; 1512114402Sru char *pin; 1513114402Sru char *new_ssid; 1514114402Sru char *new_auth; 1515114402Sru char *new_encr; 1516114402Sru char *new_key; 1517114402Sru struct wps_new_ap_settings ap; 1518114402Sru 1519114402Sru pin = os_strchr(cmd, ' '); 1520114402Sru if (pin == NULL) 1521114402Sru return -1; 1522114402Sru *pin++ = '\0'; 1523114402Sru 1524114402Sru if (hwaddr_aton(cmd, bssid)) { 1525114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'", 1526114402Sru cmd); 1527114402Sru return -1; 1528114402Sru } 1529114402Sru 1530114402Sru new_ssid = os_strchr(pin, ' '); 1531114402Sru if (new_ssid == NULL) 1532114402Sru return wpas_wps_start_reg(wpa_s, bssid, pin, NULL); 1533114402Sru *new_ssid++ = '\0'; 1534114402Sru 1535114402Sru new_auth = os_strchr(new_ssid, ' '); 1536114402Sru if (new_auth == NULL) 1537114402Sru return -1; 1538114402Sru *new_auth++ = '\0'; 1539114402Sru 1540114402Sru new_encr = os_strchr(new_auth, ' '); 1541151497Sru if (new_encr == NULL) 1542151497Sru return -1; 1543151497Sru *new_encr++ = '\0'; 1544151497Sru 1545151497Sru new_key = os_strchr(new_encr, ' '); 1546151497Sru if (new_key == NULL) 1547151497Sru return -1; 1548151497Sru *new_key++ = '\0'; 1549114402Sru 1550114402Sru os_memset(&ap, 0, sizeof(ap)); 1551114402Sru ap.ssid_hex = new_ssid; 1552114402Sru ap.auth = new_auth; 1553114402Sru ap.encr = new_encr; 1554151497Sru ap.key_hex = new_key; 1555151497Sru return wpas_wps_start_reg(wpa_s, bssid, pin, &ap); 1556114402Sru} 1557114402Sru 1558114402Sru 1559114402Sru#ifdef CONFIG_AP 1560114402Srustatic int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s, 1561114402Sru char *cmd, char *buf, 1562114402Sru size_t buflen) 1563114402Sru{ 1564114402Sru int timeout = 300; 1565114402Sru char *pos; 1566114402Sru const char *pin_txt; 1567114402Sru 1568114402Sru if (!wpa_s->ap_iface) 1569114402Sru return -1; 1570114402Sru 1571114402Sru pos = os_strchr(cmd, ' '); 1572114402Sru if (pos) 1573114402Sru *pos++ = '\0'; 1574114402Sru 1575114402Sru if (os_strcmp(cmd, "disable") == 0) { 1576151497Sru wpas_wps_ap_pin_disable(wpa_s); 1577114402Sru return os_snprintf(buf, buflen, "OK\n"); 1578114402Sru } 1579151497Sru 1580151497Sru if (os_strcmp(cmd, "random") == 0) { 1581151497Sru if (pos) 1582151497Sru timeout = atoi(pos); 1583151497Sru pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout); 1584151497Sru if (pin_txt == NULL) 1585114402Sru return -1; 1586114402Sru return os_snprintf(buf, buflen, "%s", pin_txt); 1587114402Sru } 1588114402Sru 1589114402Sru if (os_strcmp(cmd, "get") == 0) { 1590222083Sbenl pin_txt = wpas_wps_ap_pin_get(wpa_s); 1591114402Sru if (pin_txt == NULL) 1592114402Sru return -1; 1593114402Sru return os_snprintf(buf, buflen, "%s", pin_txt); 1594114402Sru } 1595114402Sru 1596114402Sru if (os_strcmp(cmd, "set") == 0) { 1597114402Sru char *pin; 1598151497Sru if (pos == NULL) 1599151497Sru return -1; 1600114402Sru pin = pos; 1601114402Sru pos = os_strchr(pos, ' '); 1602114402Sru if (pos) { 1603114402Sru *pos++ = '\0'; 1604114402Sru timeout = atoi(pos); 1605114402Sru } 1606151497Sru if (os_strlen(pin) > buflen) 1607151497Sru return -1; 1608151497Sru if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0) 1609151497Sru return -1; 1610151497Sru return os_snprintf(buf, buflen, "%s", pin); 1611151497Sru } 1612151497Sru 1613151497Sru return -1; 1614151497Sru} 1615151497Sru#endif /* CONFIG_AP */ 1616151497Sru 1617151497Sru 1618151497Sru#ifdef CONFIG_WPS_ER 1619151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s, 1620151497Sru char *cmd) 1621151497Sru{ 1622151497Sru char *uuid = cmd, *pin, *pos; 1623151497Sru u8 addr_buf[ETH_ALEN], *addr = NULL; 1624151497Sru pin = os_strchr(uuid, ' '); 1625151497Sru if (pin == NULL) 1626151497Sru return -1; 1627151497Sru *pin++ = '\0'; 1628151497Sru pos = os_strchr(pin, ' '); 1629151497Sru if (pos) { 1630151497Sru *pos++ = '\0'; 1631151497Sru if (hwaddr_aton(pos, addr_buf) == 0) 1632151497Sru addr = addr_buf; 1633151497Sru } 1634151497Sru return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin); 1635151497Sru} 1636151497Sru 1637151497Sru 1638151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s, 1639151497Sru char *cmd) 1640151497Sru{ 1641151497Sru char *uuid = cmd, *pin; 1642151497Sru pin = os_strchr(uuid, ' '); 1643151497Sru if (pin == NULL) 1644151497Sru return -1; 1645151497Sru *pin++ = '\0'; 1646151497Sru return wpas_wps_er_learn(wpa_s, uuid, pin); 1647151497Sru} 1648151497Sru 1649151497Sru 1650151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_set_config( 1651151497Sru struct wpa_supplicant *wpa_s, char *cmd) 1652151497Sru{ 1653151497Sru char *uuid = cmd, *id; 1654151497Sru id = os_strchr(uuid, ' '); 1655151497Sru if (id == NULL) 1656151497Sru return -1; 1657151497Sru *id++ = '\0'; 1658151497Sru return wpas_wps_er_set_config(wpa_s, uuid, atoi(id)); 1659151497Sru} 1660151497Sru 1661151497Sru 1662151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_config( 1663151497Sru struct wpa_supplicant *wpa_s, char *cmd) 1664151497Sru{ 1665151497Sru char *pin; 1666151497Sru char *new_ssid; 1667151497Sru char *new_auth; 1668151497Sru char *new_encr; 1669151497Sru char *new_key; 1670151497Sru struct wps_new_ap_settings ap; 1671151497Sru 1672151497Sru pin = os_strchr(cmd, ' '); 1673151497Sru if (pin == NULL) 1674151497Sru return -1; 1675151497Sru *pin++ = '\0'; 1676151497Sru 1677151497Sru new_ssid = os_strchr(pin, ' '); 1678151497Sru if (new_ssid == NULL) 1679151497Sru return -1; 1680151497Sru *new_ssid++ = '\0'; 1681151497Sru 1682151497Sru new_auth = os_strchr(new_ssid, ' '); 1683151497Sru if (new_auth == NULL) 1684151497Sru return -1; 1685151497Sru *new_auth++ = '\0'; 1686151497Sru 1687151497Sru new_encr = os_strchr(new_auth, ' '); 1688151497Sru if (new_encr == NULL) 1689151497Sru return -1; 1690151497Sru *new_encr++ = '\0'; 1691151497Sru 1692151497Sru new_key = os_strchr(new_encr, ' '); 1693151497Sru if (new_key == NULL) 1694151497Sru return -1; 1695151497Sru *new_key++ = '\0'; 1696151497Sru 1697151497Sru os_memset(&ap, 0, sizeof(ap)); 1698151497Sru ap.ssid_hex = new_ssid; 1699151497Sru ap.auth = new_auth; 1700151497Sru ap.encr = new_encr; 1701151497Sru ap.key_hex = new_key; 1702151497Sru return wpas_wps_er_config(wpa_s, cmd, pin, &ap); 1703151497Sru} 1704151497Sru 1705151497Sru 1706151497Sru#ifdef CONFIG_WPS_NFC 1707151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( 1708151497Sru struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 1709151497Sru{ 1710151497Sru int ndef; 1711151497Sru struct wpabuf *buf; 1712151497Sru int res; 1713151497Sru char *uuid; 1714151497Sru 1715151497Sru uuid = os_strchr(cmd, ' '); 1716151497Sru if (uuid == NULL) 1717151497Sru return -1; 1718151497Sru *uuid++ = '\0'; 1719151497Sru 1720151497Sru if (os_strcmp(cmd, "WPS") == 0) 1721151497Sru ndef = 0; 1722151497Sru else if (os_strcmp(cmd, "NDEF") == 0) 1723151497Sru ndef = 1; 1724151497Sru else 1725151497Sru return -1; 1726151497Sru 1727151497Sru buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid); 1728151497Sru if (buf == NULL) 1729151497Sru return -1; 1730151497Sru 1731151497Sru res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 1732151497Sru wpabuf_len(buf)); 1733151497Sru reply[res++] = '\n'; 1734151497Sru reply[res] = '\0'; 1735151497Sru 1736151497Sru wpabuf_free(buf); 1737151497Sru 1738151497Sru return res; 1739151497Sru} 1740151497Sru#endif /* CONFIG_WPS_NFC */ 1741151497Sru#endif /* CONFIG_WPS_ER */ 1742151497Sru 1743151497Sru#endif /* CONFIG_WPS */ 1744151497Sru 1745151497Sru 1746151497Sru#ifdef CONFIG_IBSS_RSN 1747151497Srustatic int wpa_supplicant_ctrl_iface_ibss_rsn( 1748151497Sru struct wpa_supplicant *wpa_s, char *addr) 1749151497Sru{ 1750151497Sru u8 peer[ETH_ALEN]; 1751151497Sru 1752151497Sru if (hwaddr_aton(addr, peer)) { 1753151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid " 1754151497Sru "address '%s'", addr); 1755151497Sru return -1; 1756151497Sru } 1757151497Sru 1758151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR, 1759151497Sru MAC2STR(peer)); 1760151497Sru 1761151497Sru return ibss_rsn_start(wpa_s->ibss_rsn, peer); 1762151497Sru} 1763151497Sru#endif /* CONFIG_IBSS_RSN */ 1764151497Sru 1765151497Sru 1766151497Srustatic int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, 1767151497Sru char *rsp) 1768151497Sru{ 1769151497Sru#ifdef IEEE8021X_EAPOL 1770151497Sru char *pos, *id_pos; 1771151497Sru int id; 1772151497Sru struct wpa_ssid *ssid; 1773151497Sru 1774151497Sru pos = os_strchr(rsp, '-'); 1775151497Sru if (pos == NULL) 1776151497Sru return -1; 1777151497Sru *pos++ = '\0'; 1778151497Sru id_pos = pos; 1779151497Sru pos = os_strchr(pos, ':'); 1780151497Sru if (pos == NULL) 1781151497Sru return -1; 1782151497Sru *pos++ = '\0'; 1783151497Sru id = atoi(id_pos); 1784151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id); 1785151497Sru wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 1786151497Sru (u8 *) pos, os_strlen(pos)); 1787151497Sru 1788151497Sru ssid = wpa_config_get_network(wpa_s->conf, id); 1789151497Sru if (ssid == NULL) { 1790151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 1791151497Sru "to update", id); 1792151497Sru return -1; 1793151497Sru } 1794151497Sru 1795151497Sru return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp, 1796151497Sru pos); 1797151497Sru#else /* IEEE8021X_EAPOL */ 1798151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); 1799151497Sru return -1; 1800151497Sru#endif /* IEEE8021X_EAPOL */ 1801151497Sru} 1802151497Sru 1803151497Sru 1804151497Srustatic int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, 1805151497Sru const char *params, 1806151497Sru char *buf, size_t buflen) 1807151497Sru{ 1808151497Sru char *pos, *end, tmp[30]; 1809151497Sru int res, verbose, wps, ret; 1810151497Sru#ifdef CONFIG_HS20 1811151497Sru const u8 *hs20; 1812151497Sru#endif /* CONFIG_HS20 */ 1813151497Sru const u8 *sess_id; 1814151497Sru size_t sess_id_len; 1815151497Sru 1816151497Sru if (os_strcmp(params, "-DRIVER") == 0) 1817151497Sru return wpa_drv_status(wpa_s, buf, buflen); 1818151497Sru verbose = os_strcmp(params, "-VERBOSE") == 0; 1819151497Sru wps = os_strcmp(params, "-WPS") == 0; 1820151497Sru pos = buf; 1821151497Sru end = buf + buflen; 1822151497Sru if (wpa_s->wpa_state >= WPA_ASSOCIATED) { 1823151497Sru struct wpa_ssid *ssid = wpa_s->current_ssid; 1824151497Sru ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", 1825151497Sru MAC2STR(wpa_s->bssid)); 1826151497Sru if (os_snprintf_error(end - pos, ret)) 1827151497Sru return pos - buf; 1828151497Sru pos += ret; 1829151497Sru ret = os_snprintf(pos, end - pos, "freq=%u\n", 1830151497Sru wpa_s->assoc_freq); 1831151497Sru if (os_snprintf_error(end - pos, ret)) 1832151497Sru return pos - buf; 1833151497Sru pos += ret; 1834151497Sru if (ssid) { 1835151497Sru u8 *_ssid = ssid->ssid; 1836151497Sru size_t ssid_len = ssid->ssid_len; 1837151497Sru u8 ssid_buf[SSID_MAX_LEN]; 1838151497Sru if (ssid_len == 0) { 1839151497Sru int _res = wpa_drv_get_ssid(wpa_s, ssid_buf); 1840151497Sru if (_res < 0) 1841151497Sru ssid_len = 0; 1842151497Sru else 1843151497Sru ssid_len = _res; 1844151497Sru _ssid = ssid_buf; 1845151497Sru } 1846151497Sru ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n", 1847151497Sru wpa_ssid_txt(_ssid, ssid_len), 1848151497Sru ssid->id); 1849151497Sru if (os_snprintf_error(end - pos, ret)) 1850151497Sru return pos - buf; 1851151497Sru pos += ret; 1852151497Sru 1853151497Sru if (wps && ssid->passphrase && 1854151497Sru wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && 1855151497Sru (ssid->mode == WPAS_MODE_AP || 1856151497Sru ssid->mode == WPAS_MODE_P2P_GO)) { 1857151497Sru ret = os_snprintf(pos, end - pos, 1858151497Sru "passphrase=%s\n", 1859151497Sru ssid->passphrase); 1860151497Sru if (os_snprintf_error(end - pos, ret)) 1861151497Sru return pos - buf; 1862151497Sru pos += ret; 1863151497Sru } 1864151497Sru if (ssid->id_str) { 1865151497Sru ret = os_snprintf(pos, end - pos, 1866151497Sru "id_str=%s\n", 1867151497Sru ssid->id_str); 1868151497Sru if (os_snprintf_error(end - pos, ret)) 1869151497Sru return pos - buf; 1870151497Sru pos += ret; 1871151497Sru } 1872151497Sru 1873151497Sru switch (ssid->mode) { 1874151497Sru case WPAS_MODE_INFRA: 1875151497Sru ret = os_snprintf(pos, end - pos, 1876151497Sru "mode=station\n"); 1877151497Sru break; 1878151497Sru case WPAS_MODE_IBSS: 1879151497Sru ret = os_snprintf(pos, end - pos, 1880151497Sru "mode=IBSS\n"); 1881151497Sru break; 1882151497Sru case WPAS_MODE_AP: 1883151497Sru ret = os_snprintf(pos, end - pos, 1884151497Sru "mode=AP\n"); 1885151497Sru break; 1886151497Sru case WPAS_MODE_P2P_GO: 1887151497Sru ret = os_snprintf(pos, end - pos, 1888151497Sru "mode=P2P GO\n"); 1889151497Sru break; 1890151497Sru case WPAS_MODE_P2P_GROUP_FORMATION: 1891151497Sru ret = os_snprintf(pos, end - pos, 1892151497Sru "mode=P2P GO - group " 1893151497Sru "formation\n"); 1894151497Sru break; 1895151497Sru case WPAS_MODE_MESH: 1896151497Sru ret = os_snprintf(pos, end - pos, 1897151497Sru "mode=mesh\n"); 1898151497Sru break; 1899151497Sru default: 1900151497Sru ret = 0; 1901151497Sru break; 1902151497Sru } 1903151497Sru if (os_snprintf_error(end - pos, ret)) 1904151497Sru return pos - buf; 1905151497Sru pos += ret; 1906151497Sru } 1907151497Sru 1908151497Sru#ifdef CONFIG_AP 1909151497Sru if (wpa_s->ap_iface) { 1910151497Sru pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, 1911151497Sru end - pos, 1912151497Sru verbose); 1913151497Sru } else 1914151497Sru#endif /* CONFIG_AP */ 1915151497Sru pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); 1916151497Sru } 1917151497Sru#ifdef CONFIG_SAE 1918151497Sru if (wpa_s->wpa_state >= WPA_ASSOCIATED && 1919151497Sru#ifdef CONFIG_AP 1920151497Sru !wpa_s->ap_iface && 1921151497Sru#endif /* CONFIG_AP */ 1922151497Sru wpa_s->sme.sae.state == SAE_ACCEPTED) { 1923151497Sru ret = os_snprintf(pos, end - pos, "sae_group=%d\n", 1924151497Sru wpa_s->sme.sae.group); 1925151497Sru if (os_snprintf_error(end - pos, ret)) 1926151497Sru return pos - buf; 1927151497Sru pos += ret; 1928151497Sru } 1929151497Sru#endif /* CONFIG_SAE */ 1930151497Sru ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", 1931151497Sru wpa_supplicant_state_txt(wpa_s->wpa_state)); 1932151497Sru if (os_snprintf_error(end - pos, ret)) 1933151497Sru return pos - buf; 1934151497Sru pos += ret; 1935151497Sru 1936151497Sru if (wpa_s->l2 && 1937114402Sru l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) { 1938114402Sru ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp); 1939114402Sru if (os_snprintf_error(end - pos, ret)) 1940114402Sru return pos - buf; 1941114402Sru pos += ret; 1942114402Sru } 1943114402Sru 1944114402Sru#ifdef CONFIG_P2P 1945114402Sru if (wpa_s->global->p2p) { 1946114402Sru ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR 1947114402Sru "\n", MAC2STR(wpa_s->global->p2p_dev_addr)); 1948114402Sru if (os_snprintf_error(end - pos, ret)) 1949114402Sru return pos - buf; 1950114402Sru pos += ret; 1951114402Sru } 1952114402Sru#endif /* CONFIG_P2P */ 1953114402Sru 1954114402Sru ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n", 1955114402Sru MAC2STR(wpa_s->own_addr)); 1956114402Sru if (os_snprintf_error(end - pos, ret)) 1957114402Sru return pos - buf; 1958114402Sru pos += ret; 1959114402Sru 1960114402Sru#ifdef CONFIG_HS20 1961114402Sru if (wpa_s->current_bss && 1962114402Sru (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss, 1963114402Sru HS20_IE_VENDOR_TYPE)) && 1964114402Sru wpa_s->wpa_proto == WPA_PROTO_RSN && 1965114402Sru wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { 1966114402Sru int release = 1; 1967114402Sru if (hs20[1] >= 5) { 1968114402Sru u8 rel_num = (hs20[6] & 0xf0) >> 4; 1969114402Sru release = rel_num + 1; 1970114402Sru } 1971114402Sru ret = os_snprintf(pos, end - pos, "hs20=%d\n", release); 1972114402Sru if (os_snprintf_error(end - pos, ret)) 1973114402Sru return pos - buf; 1974114402Sru pos += ret; 1975114402Sru } 1976114402Sru 1977114402Sru if (wpa_s->current_ssid) { 1978114402Sru struct wpa_cred *cred; 1979114402Sru char *type; 1980151497Sru 1981151497Sru for (cred = wpa_s->conf->cred; cred; cred = cred->next) { 1982151497Sru size_t i; 1983114402Sru 1984114402Sru if (wpa_s->current_ssid->parent_cred != cred) 1985114402Sru continue; 1986114402Sru 1987151497Sru if (cred->provisioning_sp) { 1988151497Sru ret = os_snprintf(pos, end - pos, 1989151497Sru "provisioning_sp=%s\n", 1990151497Sru cred->provisioning_sp); 1991151497Sru if (os_snprintf_error(end - pos, ret)) 1992151497Sru return pos - buf; 1993151497Sru pos += ret; 1994151497Sru } 1995151497Sru 1996151497Sru if (!cred->domain) 1997151497Sru goto no_domain; 1998151497Sru 1999151497Sru i = 0; 2000114402Sru if (wpa_s->current_bss && wpa_s->current_bss->anqp) { 2001114402Sru struct wpabuf *names = 2002114402Sru wpa_s->current_bss->anqp->domain_name; 2003114402Sru for (i = 0; names && i < cred->num_domain; i++) 2004114402Sru { 2005114402Sru if (domain_name_list_contains( 2006114402Sru names, cred->domain[i], 1)) 2007114402Sru break; 2008114402Sru } 2009114402Sru if (i == cred->num_domain) 2010114402Sru i = 0; /* show first entry by default */ 2011114402Sru } 2012114402Sru ret = os_snprintf(pos, end - pos, "home_sp=%s\n", 2013114402Sru cred->domain[i]); 2014114402Sru if (os_snprintf_error(end - pos, ret)) 2015114402Sru return pos - buf; 2016114402Sru pos += ret; 2017114402Sru 2018114402Sru no_domain: 2019114402Sru if (wpa_s->current_bss == NULL || 2020114402Sru wpa_s->current_bss->anqp == NULL) 2021114402Sru res = -1; 2022114402Sru else 2023114402Sru res = interworking_home_sp_cred( 2024114402Sru wpa_s, cred, 2025151497Sru wpa_s->current_bss->anqp->domain_name); 2026114402Sru if (res > 0) 2027114402Sru type = "home"; 2028114402Sru else if (res == 0) 2029114402Sru type = "roaming"; 2030151497Sru else 2031114402Sru type = "unknown"; 2032151497Sru 2033114402Sru ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type); 2034114402Sru if (os_snprintf_error(end - pos, ret)) 2035114402Sru return pos - buf; 2036151497Sru pos += ret; 2037114402Sru 2038114402Sru break; 2039114402Sru } 2040114402Sru } 2041114402Sru#endif /* CONFIG_HS20 */ 2042114402Sru 2043114402Sru if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || 2044114402Sru wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 2045114402Sru res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, 2046114402Sru verbose); 2047114402Sru if (res >= 0) 2048114402Sru pos += res; 2049114402Sru } 2050114402Sru 2051114402Sru sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len); 2052114402Sru if (sess_id) { 2053151497Sru char *start = pos; 2054151497Sru 2055151497Sru ret = os_snprintf(pos, end - pos, "eap_session_id="); 2056114402Sru if (os_snprintf_error(end - pos, ret)) 2057114402Sru return start - buf; 2058114402Sru pos += ret; 2059114402Sru ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len); 2060114402Sru if (ret <= 0) 2061114402Sru return start - buf; 2062114402Sru pos += ret; 2063114402Sru ret = os_snprintf(pos, end - pos, "\n"); 2064114402Sru if (os_snprintf_error(end - pos, ret)) 2065114402Sru return start - buf; 2066114402Sru pos += ret; 2067114402Sru } 2068114402Sru 2069114402Sru res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose); 2070114402Sru if (res >= 0) 2071114402Sru pos += res; 2072114402Sru 2073114402Sru#ifdef CONFIG_WPS 2074114402Sru { 2075114402Sru char uuid_str[100]; 2076114402Sru uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str)); 2077114402Sru ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str); 2078114402Sru if (os_snprintf_error(end - pos, ret)) 2079114402Sru return pos - buf; 2080114402Sru pos += ret; 2081114402Sru } 2082114402Sru#endif /* CONFIG_WPS */ 2083114402Sru 2084114402Sru#ifdef ANDROID 2085114402Sru /* 2086151497Sru * Allow using the STATUS command with default behavior, say for debug, 2087151497Sru * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE 2088151497Sru * events with STATUS-NO_EVENTS. 2089151497Sru */ 2090151497Sru if (os_strcmp(params, "-NO_EVENTS")) { 2091151497Sru wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE 2092151497Sru "id=%d state=%d BSSID=" MACSTR " SSID=%s", 2093151497Sru wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, 2094151497Sru wpa_s->wpa_state, 2095151497Sru MAC2STR(wpa_s->bssid), 2096151497Sru wpa_s->current_ssid && wpa_s->current_ssid->ssid ? 2097151497Sru wpa_ssid_txt(wpa_s->current_ssid->ssid, 2098114402Sru wpa_s->current_ssid->ssid_len) : ""); 2099114402Sru if (wpa_s->wpa_state == WPA_COMPLETED) { 2100114402Sru struct wpa_ssid *ssid = wpa_s->current_ssid; 2101114402Sru wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED 2102114402Sru "- connection to " MACSTR 2103114402Sru " completed %s [id=%d id_str=%s]", 2104114402Sru MAC2STR(wpa_s->bssid), "(auth)", 2105151497Sru ssid ? ssid->id : -1, 2106151497Sru ssid && ssid->id_str ? ssid->id_str : ""); 2107114402Sru } 2108114402Sru } 2109114402Sru#endif /* ANDROID */ 2110114402Sru 2111151497Sru return pos - buf; 2112114402Sru} 2113114402Sru 2114114402Sru 2115114402Srustatic int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, 2116114402Sru char *cmd) 2117114402Sru{ 2118114402Sru char *pos; 2119114402Sru int id; 2120114402Sru struct wpa_ssid *ssid; 2121114402Sru u8 bssid[ETH_ALEN]; 2122114402Sru 2123114402Sru /* cmd: "<network id> <BSSID>" */ 2124114402Sru pos = os_strchr(cmd, ' '); 2125114402Sru if (pos == NULL) 2126114402Sru return -1; 2127114402Sru *pos++ = '\0'; 2128114402Sru id = atoi(cmd); 2129114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos); 2130114402Sru if (hwaddr_aton(pos, bssid)) { 2131114402Sru wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos); 2132114402Sru return -1; 2133114402Sru } 2134114402Sru 2135114402Sru ssid = wpa_config_get_network(wpa_s->conf, id); 2136114402Sru if (ssid == NULL) { 2137114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 2138114402Sru "to update", id); 2139114402Sru return -1; 2140114402Sru } 2141114402Sru 2142114402Sru os_memcpy(ssid->bssid, bssid, ETH_ALEN); 2143114402Sru ssid->bssid_set = !is_zero_ether_addr(bssid); 2144114402Sru 2145114402Sru return 0; 2146114402Sru} 2147114402Sru 2148114402Sru 2149114402Srustatic int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s, 2150114402Sru char *cmd, char *buf, 2151114402Sru size_t buflen) 2152114402Sru{ 2153114402Sru u8 bssid[ETH_ALEN]; 2154114402Sru struct wpa_blacklist *e; 2155114402Sru char *pos, *end; 2156114402Sru int ret; 2157114402Sru 2158114402Sru /* cmd: "BLACKLIST [<BSSID>]" */ 2159114402Sru if (*cmd == '\0') { 2160114402Sru pos = buf; 2161114402Sru end = buf + buflen; 2162114402Sru e = wpa_s->blacklist; 2163114402Sru while (e) { 2164114402Sru ret = os_snprintf(pos, end - pos, MACSTR "\n", 2165114402Sru MAC2STR(e->bssid)); 2166114402Sru if (os_snprintf_error(end - pos, ret)) 2167114402Sru return pos - buf; 2168114402Sru pos += ret; 2169114402Sru e = e->next; 2170114402Sru } 2171114402Sru return pos - buf; 2172114402Sru } 2173114402Sru 2174114402Sru cmd++; 2175114402Sru if (os_strncmp(cmd, "clear", 5) == 0) { 2176114402Sru wpa_blacklist_clear(wpa_s); 2177114402Sru os_memcpy(buf, "OK\n", 3); 2178151497Sru return 3; 2179151497Sru } 2180151497Sru 2181151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd); 2182151497Sru if (hwaddr_aton(cmd, bssid)) { 2183151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd); 2184151497Sru return -1; 2185151497Sru } 2186151497Sru 2187151497Sru /* 2188151497Sru * Add the BSSID twice, so its count will be 2, causing it to be 2189151497Sru * skipped when processing scan results. 2190151497Sru */ 2191151497Sru ret = wpa_blacklist_add(wpa_s, bssid); 2192151497Sru if (ret < 0) 2193151497Sru return -1; 2194151497Sru ret = wpa_blacklist_add(wpa_s, bssid); 2195151497Sru if (ret < 0) 2196114402Sru return -1; 2197114402Sru os_memcpy(buf, "OK\n", 3); 2198114402Sru return 3; 2199114402Sru} 2200114402Sru 2201114402Sru 2202114402Srustatic int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s, 2203114402Sru char *cmd, char *buf, 2204114402Sru size_t buflen) 2205114402Sru{ 2206151497Sru char *pos, *end, *stamp; 2207151497Sru int ret; 2208114402Sru 2209151497Sru /* cmd: "LOG_LEVEL [<level>]" */ 2210114402Sru if (*cmd == '\0') { 2211114402Sru pos = buf; 2212114402Sru end = buf + buflen; 2213151497Sru ret = os_snprintf(pos, end - pos, "Current level: %s\n" 2214114402Sru "Timestamp: %d\n", 2215114402Sru debug_level_str(wpa_debug_level), 2216151497Sru wpa_debug_timestamp); 2217114402Sru if (os_snprintf_error(end - pos, ret)) 2218114402Sru ret = 0; 2219151497Sru 2220114402Sru return ret; 2221114402Sru } 2222114402Sru 2223114402Sru while (*cmd == ' ') 2224114402Sru cmd++; 2225114402Sru 2226114402Sru stamp = os_strchr(cmd, ' '); 2227114402Sru if (stamp) { 2228151497Sru *stamp++ = '\0'; 2229151497Sru while (*stamp == ' ') { 2230114402Sru stamp++; 2231114402Sru } 2232114402Sru } 2233114402Sru 2234151497Sru if (os_strlen(cmd)) { 2235151497Sru int level = str_to_debug_level(cmd); 2236151497Sru if (level < 0) 2237151497Sru return -1; 2238151497Sru wpa_debug_level = level; 2239151497Sru } 2240151497Sru 2241151497Sru if (stamp && os_strlen(stamp)) 2242151497Sru wpa_debug_timestamp = atoi(stamp); 2243151497Sru 2244151497Sru os_memcpy(buf, "OK\n", 3); 2245151497Sru return 3; 2246151497Sru} 2247151497Sru 2248114402Sru 2249114402Srustatic int wpa_supplicant_ctrl_iface_list_networks( 2250114402Sru struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 2251114402Sru{ 2252114402Sru char *pos, *end, *prev; 2253151497Sru struct wpa_ssid *ssid; 2254151497Sru int ret; 2255114402Sru 2256114402Sru pos = buf; 2257114402Sru end = buf + buflen; 2258151497Sru ret = os_snprintf(pos, end - pos, 2259114402Sru "network id / ssid / bssid / flags\n"); 2260114402Sru if (os_snprintf_error(end - pos, ret)) 2261114402Sru return pos - buf; 2262114402Sru pos += ret; 2263114402Sru 2264114402Sru ssid = wpa_s->conf->ssid; 2265114402Sru 2266114402Sru /* skip over ssids until we find next one */ 2267114402Sru if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) { 2268151497Sru int last_id = atoi(cmd + 8); 2269114402Sru if (last_id != -1) { 2270114402Sru while (ssid != NULL && ssid->id <= last_id) { 2271114402Sru ssid = ssid->next; 2272114402Sru } 2273114402Sru } 2274114402Sru } 2275114402Sru 2276114402Sru while (ssid) { 2277114402Sru prev = pos; 2278151497Sru ret = os_snprintf(pos, end - pos, "%d\t%s", 2279114402Sru ssid->id, 2280114402Sru wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 2281114402Sru if (os_snprintf_error(end - pos, ret)) 2282114402Sru return prev - buf; 2283114402Sru pos += ret; 2284114402Sru if (ssid->bssid_set) { 2285114402Sru ret = os_snprintf(pos, end - pos, "\t" MACSTR, 2286114402Sru MAC2STR(ssid->bssid)); 2287114402Sru } else { 2288114402Sru ret = os_snprintf(pos, end - pos, "\tany"); 2289114402Sru } 2290114402Sru if (os_snprintf_error(end - pos, ret)) 2291114402Sru return prev - buf; 2292114402Sru pos += ret; 2293114402Sru ret = os_snprintf(pos, end - pos, "\t%s%s%s%s", 2294114402Sru ssid == wpa_s->current_ssid ? 2295114402Sru "[CURRENT]" : "", 2296114402Sru ssid->disabled ? "[DISABLED]" : "", 2297114402Sru ssid->disabled_until.sec ? 2298114402Sru "[TEMP-DISABLED]" : "", 2299114402Sru ssid->disabled == 2 ? "[P2P-PERSISTENT]" : 2300114402Sru ""); 2301114402Sru if (os_snprintf_error(end - pos, ret)) 2302114402Sru return prev - buf; 2303114402Sru pos += ret; 2304114402Sru ret = os_snprintf(pos, end - pos, "\n"); 2305114402Sru if (os_snprintf_error(end - pos, ret)) 2306114402Sru return prev - buf; 2307114402Sru pos += ret; 2308114402Sru 2309114402Sru ssid = ssid->next; 2310114402Sru } 2311114402Sru 2312114402Sru return pos - buf; 2313114402Sru} 2314114402Sru 2315114402Sru 2316151497Srustatic char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) 2317151497Sru{ 2318114402Sru int ret; 2319114402Sru ret = os_snprintf(pos, end - pos, "-"); 2320114402Sru if (os_snprintf_error(end - pos, ret)) 2321114402Sru return pos; 2322114402Sru pos += ret; 2323114402Sru ret = wpa_write_ciphers(pos, end, cipher, "+"); 2324114402Sru if (ret < 0) 2325114402Sru return pos; 2326114402Sru pos += ret; 2327114402Sru return pos; 2328114402Sru} 2329114402Sru 2330114402Sru 2331114402Srustatic char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, 2332114402Sru const u8 *ie, size_t ie_len) 2333114402Sru{ 2334114402Sru struct wpa_ie_data data; 2335114402Sru char *start; 2336114402Sru int ret; 2337114402Sru 2338114402Sru ret = os_snprintf(pos, end - pos, "[%s-", proto); 2339114402Sru if (os_snprintf_error(end - pos, ret)) 2340114402Sru return pos; 2341114402Sru pos += ret; 2342114402Sru 2343114402Sru if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) { 2344114402Sru ret = os_snprintf(pos, end - pos, "?]"); 2345114402Sru if (os_snprintf_error(end - pos, ret)) 2346114402Sru return pos; 2347114402Sru pos += ret; 2348114402Sru return pos; 2349114402Sru } 2350114402Sru 2351114402Sru start = pos; 2352114402Sru if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 2353114402Sru ret = os_snprintf(pos, end - pos, "%sEAP", 2354114402Sru pos == start ? "" : "+"); 2355114402Sru if (os_snprintf_error(end - pos, ret)) 2356114402Sru return pos; 2357114402Sru pos += ret; 2358114402Sru } 2359114402Sru if (data.key_mgmt & WPA_KEY_MGMT_PSK) { 2360114402Sru ret = os_snprintf(pos, end - pos, "%sPSK", 2361114402Sru pos == start ? "" : "+"); 2362114402Sru if (os_snprintf_error(end - pos, ret)) 2363114402Sru return pos; 2364114402Sru pos += ret; 2365114402Sru } 2366114402Sru if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 2367114402Sru ret = os_snprintf(pos, end - pos, "%sNone", 2368114402Sru pos == start ? "" : "+"); 2369114402Sru if (os_snprintf_error(end - pos, ret)) 2370114402Sru return pos; 2371114402Sru pos += ret; 2372114402Sru } 2373114402Sru if (data.key_mgmt & WPA_KEY_MGMT_SAE) { 2374114402Sru ret = os_snprintf(pos, end - pos, "%sSAE", 2375114402Sru pos == start ? "" : "+"); 2376114402Sru if (os_snprintf_error(end - pos, ret)) 2377114402Sru return pos; 2378114402Sru pos += ret; 2379114402Sru } 2380114402Sru#ifdef CONFIG_IEEE80211R 2381114402Sru if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 2382114402Sru ret = os_snprintf(pos, end - pos, "%sFT/EAP", 2383114402Sru pos == start ? "" : "+"); 2384114402Sru if (os_snprintf_error(end - pos, ret)) 2385114402Sru return pos; 2386114402Sru pos += ret; 2387151497Sru } 2388114402Sru if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) { 2389114402Sru ret = os_snprintf(pos, end - pos, "%sFT/PSK", 2390114402Sru pos == start ? "" : "+"); 2391114402Sru if (os_snprintf_error(end - pos, ret)) 2392114402Sru return pos; 2393151497Sru pos += ret; 2394151497Sru } 2395151497Sru if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) { 2396151497Sru ret = os_snprintf(pos, end - pos, "%sFT/SAE", 2397114402Sru pos == start ? "" : "+"); 2398114402Sru if (os_snprintf_error(end - pos, ret)) 2399114402Sru return pos; 2400114402Sru pos += ret; 2401114402Sru } 2402114402Sru#endif /* CONFIG_IEEE80211R */ 2403114402Sru#ifdef CONFIG_IEEE80211W 2404114402Sru if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 2405114402Sru ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", 2406114402Sru pos == start ? "" : "+"); 2407114402Sru if (os_snprintf_error(end - pos, ret)) 2408114402Sru return pos; 2409114402Sru pos += ret; 2410151497Sru } 2411151497Sru if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 2412114402Sru ret = os_snprintf(pos, end - pos, "%sPSK-SHA256", 2413114402Sru pos == start ? "" : "+"); 2414114402Sru if (os_snprintf_error(end - pos, ret)) 2415114402Sru return pos; 2416114402Sru pos += ret; 2417114402Sru } 2418114402Sru#endif /* CONFIG_IEEE80211W */ 2419151497Sru 2420151497Sru#ifdef CONFIG_SUITEB 2421114402Sru if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 2422114402Sru ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B", 2423114402Sru pos == start ? "" : "+"); 2424114402Sru if (os_snprintf_error(end - pos, ret)) 2425114402Sru return pos; 2426114402Sru pos += ret; 2427114402Sru } 2428114402Sru#endif /* CONFIG_SUITEB */ 2429114402Sru 2430114402Sru#ifdef CONFIG_SUITEB192 2431114402Sru if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 2432114402Sru ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192", 2433114402Sru pos == start ? "" : "+"); 2434114402Sru if (os_snprintf_error(end - pos, ret)) 2435114402Sru return pos; 2436114402Sru pos += ret; 2437114402Sru } 2438114402Sru#endif /* CONFIG_SUITEB192 */ 2439114402Sru 2440114402Sru if (data.key_mgmt & WPA_KEY_MGMT_OSEN) { 2441114402Sru ret = os_snprintf(pos, end - pos, "%sOSEN", 2442114402Sru pos == start ? "" : "+"); 2443114402Sru if (os_snprintf_error(end - pos, ret)) 2444114402Sru return pos; 2445114402Sru pos += ret; 2446114402Sru } 2447114402Sru 2448151497Sru pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); 2449114402Sru 2450114402Sru if (data.capabilities & WPA_CAPABILITY_PREAUTH) { 2451114402Sru ret = os_snprintf(pos, end - pos, "-preauth"); 2452114402Sru if (os_snprintf_error(end - pos, ret)) 2453114402Sru return pos; 2454114402Sru pos += ret; 2455114402Sru } 2456114402Sru 2457114402Sru ret = os_snprintf(pos, end - pos, "]"); 2458114402Sru if (os_snprintf_error(end - pos, ret)) 2459114402Sru return pos; 2460114402Sru pos += ret; 2461114402Sru 2462114402Sru return pos; 2463114402Sru} 2464114402Sru 2465114402Sru 2466114402Sru#ifdef CONFIG_WPS 2467114402Srustatic char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s, 2468114402Sru char *pos, char *end, 2469114402Sru struct wpabuf *wps_ie) 2470114402Sru{ 2471114402Sru int ret; 2472114402Sru const char *txt; 2473114402Sru 2474114402Sru if (wps_ie == NULL) 2475114402Sru return pos; 2476114402Sru if (wps_is_selected_pbc_registrar(wps_ie)) 2477114402Sru txt = "[WPS-PBC]"; 2478114402Sru else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0)) 2479114402Sru txt = "[WPS-AUTH]"; 2480114402Sru else if (wps_is_selected_pin_registrar(wps_ie)) 2481114402Sru txt = "[WPS-PIN]"; 2482114402Sru else 2483114402Sru txt = "[WPS]"; 2484114402Sru 2485114402Sru ret = os_snprintf(pos, end - pos, "%s", txt); 2486114402Sru if (!os_snprintf_error(end - pos, ret)) 2487114402Sru pos += ret; 2488151497Sru wpabuf_free(wps_ie); 2489151497Sru return pos; 2490151497Sru} 2491151497Sru#endif /* CONFIG_WPS */ 2492151497Sru 2493151497Sru 2494151497Srustatic char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s, 2495151497Sru char *pos, char *end, 2496151497Sru const struct wpa_bss *bss) 2497151497Sru{ 2498151497Sru#ifdef CONFIG_WPS 2499151497Sru struct wpabuf *wps_ie; 2500151497Sru wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 2501151497Sru return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie); 2502151497Sru#else /* CONFIG_WPS */ 2503151497Sru return pos; 2504151497Sru#endif /* CONFIG_WPS */ 2505114402Sru} 2506114402Sru 2507114402Sru 2508114402Sru/* Format one result on one text line into a buffer. */ 2509114402Srustatic int wpa_supplicant_ctrl_iface_scan_result( 2510114402Sru struct wpa_supplicant *wpa_s, 2511114402Sru const struct wpa_bss *bss, char *buf, size_t buflen) 2512114402Sru{ 2513114402Sru char *pos, *end; 2514114402Sru int ret; 2515114402Sru const u8 *ie, *ie2, *osen_ie, *p2p, *mesh; 2516114402Sru 2517114402Sru mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); 2518114402Sru p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); 2519114402Sru if (!p2p) 2520114402Sru p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE); 2521114402Sru if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN && 2522151497Sru os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 2523151497Sru 0) 2524151497Sru return 0; /* Do not show P2P listen discovery results here */ 2525151497Sru 2526114402Sru pos = buf; 2527114402Sru end = buf + buflen; 2528114402Sru 2529114402Sru ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", 2530114402Sru MAC2STR(bss->bssid), bss->freq, bss->level); 2531114402Sru if (os_snprintf_error(end - pos, ret)) 2532114402Sru return -1; 2533114402Sru pos += ret; 2534114402Sru ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 2535114402Sru if (ie) 2536151497Sru pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); 2537114402Sru ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); 2538114402Sru if (ie2) { 2539114402Sru pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2", 2540114402Sru ie2, 2 + ie2[1]); 2541114402Sru } 2542151497Sru osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); 2543114402Sru if (osen_ie) 2544114402Sru pos = wpa_supplicant_ie_txt(pos, end, "OSEN", 2545114402Sru osen_ie, 2 + osen_ie[1]); 2546114402Sru pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); 2547114402Sru if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) { 2548114402Sru ret = os_snprintf(pos, end - pos, "[WEP]"); 2549151497Sru if (os_snprintf_error(end - pos, ret)) 2550114402Sru return -1; 2551114402Sru pos += ret; 2552114402Sru } 2553114402Sru if (mesh) { 2554151497Sru ret = os_snprintf(pos, end - pos, "[MESH]"); 2555151497Sru if (os_snprintf_error(end - pos, ret)) 2556151497Sru return -1; 2557151497Sru pos += ret; 2558151497Sru } 2559151497Sru if (bss_is_dmg(bss)) { 2560151497Sru const char *s; 2561151497Sru ret = os_snprintf(pos, end - pos, "[DMG]"); 2562114402Sru if (os_snprintf_error(end - pos, ret)) 2563151497Sru return -1; 2564114402Sru pos += ret; 2565151497Sru switch (bss->caps & IEEE80211_CAP_DMG_MASK) { 2566114402Sru case IEEE80211_CAP_DMG_IBSS: 2567114402Sru s = "[IBSS]"; 2568151497Sru break; 2569114402Sru case IEEE80211_CAP_DMG_AP: 2570114402Sru s = "[ESS]"; 2571114402Sru break; 2572114402Sru case IEEE80211_CAP_DMG_PBSS: 2573114402Sru s = "[PBSS]"; 2574151497Sru break; 2575114402Sru default: 2576114402Sru s = ""; 2577114402Sru break; 2578114402Sru } 2579114402Sru ret = os_snprintf(pos, end - pos, "%s", s); 2580114402Sru if (os_snprintf_error(end - pos, ret)) 2581114402Sru return -1; 2582114402Sru pos += ret; 2583114402Sru } else { 2584114402Sru if (bss->caps & IEEE80211_CAP_IBSS) { 2585114402Sru ret = os_snprintf(pos, end - pos, "[IBSS]"); 2586114402Sru if (os_snprintf_error(end - pos, ret)) 2587114402Sru return -1; 2588114402Sru pos += ret; 2589114402Sru } 2590114402Sru if (bss->caps & IEEE80211_CAP_ESS) { 2591114402Sru ret = os_snprintf(pos, end - pos, "[ESS]"); 2592114402Sru if (os_snprintf_error(end - pos, ret)) 2593114402Sru return -1; 2594114402Sru pos += ret; 2595114402Sru } 2596114402Sru } 2597114402Sru if (p2p) { 2598114402Sru ret = os_snprintf(pos, end - pos, "[P2P]"); 2599114402Sru if (os_snprintf_error(end - pos, ret)) 2600114402Sru return -1; 2601114402Sru pos += ret; 2602114402Sru } 2603114402Sru#ifdef CONFIG_HS20 2604114402Sru if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) { 2605114402Sru ret = os_snprintf(pos, end - pos, "[HS20]"); 2606114402Sru if (os_snprintf_error(end - pos, ret)) 2607114402Sru return -1; 2608114402Sru pos += ret; 2609114402Sru } 2610114402Sru#endif /* CONFIG_HS20 */ 2611114402Sru#ifdef CONFIG_FST 2612114402Sru if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { 2613114402Sru ret = os_snprintf(pos, end - pos, "[FST]"); 2614114402Sru if (os_snprintf_error(end - pos, ret)) 2615114402Sru return -1; 2616114402Sru pos += ret; 2617114402Sru } 2618114402Sru#endif /* CONFIG_FST */ 2619114402Sru 2620114402Sru ret = os_snprintf(pos, end - pos, "\t%s", 2621114402Sru wpa_ssid_txt(bss->ssid, bss->ssid_len)); 2622114402Sru if (os_snprintf_error(end - pos, ret)) 2623114402Sru return -1; 2624151497Sru pos += ret; 2625151497Sru 2626114402Sru ret = os_snprintf(pos, end - pos, "\n"); 2627114402Sru if (os_snprintf_error(end - pos, ret)) 2628114402Sru return -1; 2629114402Sru pos += ret; 2630114402Sru 2631114402Sru return pos - buf; 2632114402Sru} 2633114402Sru 2634151497Sru 2635151497Srustatic int wpa_supplicant_ctrl_iface_scan_results( 2636114402Sru struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 2637114402Sru{ 2638114402Sru char *pos, *end; 2639151497Sru struct wpa_bss *bss; 2640151497Sru int ret; 2641151497Sru 2642151497Sru pos = buf; 2643151497Sru end = buf + buflen; 2644151497Sru ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / " 2645151497Sru "flags / ssid\n"); 2646151497Sru if (os_snprintf_error(end - pos, ret)) 2647151497Sru return pos - buf; 2648151497Sru pos += ret; 2649151497Sru 2650151497Sru dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 2651114402Sru ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos, 2652114402Sru end - pos); 2653114402Sru if (ret < 0 || ret >= end - pos) 2654114402Sru return pos - buf; 2655114402Sru pos += ret; 2656151497Sru } 2657151497Sru 2658114402Sru return pos - buf; 2659114402Sru} 2660114402Sru 2661114402Sru 2662114402Sru#ifdef CONFIG_MESH 2663114402Sru 2664114402Srustatic int wpa_supplicant_ctrl_iface_mesh_interface_add( 2665114402Sru struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) 2666114402Sru{ 2667151497Sru char *pos, ifname[IFNAMSIZ + 1]; 2668151497Sru 2669151497Sru ifname[0] = '\0'; 2670151497Sru 2671151497Sru pos = os_strstr(cmd, "ifname="); 2672151497Sru if (pos) { 2673114402Sru pos += 7; 2674114402Sru os_strlcpy(ifname, pos, sizeof(ifname)); 2675114402Sru } 2676114402Sru 2677114402Sru if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0) 2678114402Sru return -1; 2679114402Sru 2680114402Sru os_strlcpy(reply, ifname, max_len); 2681114402Sru return os_strlen(ifname); 2682114402Sru} 2683114402Sru 2684114402Sru 2685114402Srustatic int wpa_supplicant_ctrl_iface_mesh_group_add( 2686114402Sru struct wpa_supplicant *wpa_s, char *cmd) 2687114402Sru{ 2688114402Sru int id; 2689114402Sru struct wpa_ssid *ssid; 2690114402Sru 2691114402Sru id = atoi(cmd); 2692114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id); 2693114402Sru 2694114402Sru ssid = wpa_config_get_network(wpa_s->conf, id); 2695114402Sru if (ssid == NULL) { 2696114402Sru wpa_printf(MSG_DEBUG, 2697114402Sru "CTRL_IFACE: Could not find network id=%d", id); 2698151497Sru return -1; 2699151497Sru } 2700151497Sru if (ssid->mode != WPAS_MODE_MESH) { 2701151497Sru wpa_printf(MSG_DEBUG, 2702114402Sru "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network"); 2703114402Sru return -1; 2704151497Sru } 2705114402Sru if (ssid->key_mgmt != WPA_KEY_MGMT_NONE && 2706114402Sru ssid->key_mgmt != WPA_KEY_MGMT_SAE) { 2707114402Sru wpa_printf(MSG_ERROR, 2708114402Sru "CTRL_IFACE: key_mgmt for mesh network should be open or SAE"); 2709151497Sru return -1; 2710151497Sru } 2711114402Sru 2712114402Sru /* 2713114402Sru * TODO: If necessary write our own group_add function, 2714114402Sru * for now we can reuse select_network 2715114402Sru */ 2716114402Sru wpa_supplicant_select_network(wpa_s, ssid); 2717114402Sru 2718114402Sru return 0; 2719114402Sru} 2720114402Sru 2721114402Sru 2722114402Srustatic int wpa_supplicant_ctrl_iface_mesh_group_remove( 2723114402Sru struct wpa_supplicant *wpa_s, char *cmd) 2724114402Sru{ 2725114402Sru struct wpa_supplicant *orig; 2726114402Sru struct wpa_global *global; 2727114402Sru int found = 0; 2728114402Sru 2729151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd); 2730151497Sru 2731151497Sru global = wpa_s->global; 2732151497Sru orig = wpa_s; 2733151497Sru 2734151497Sru for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 2735151497Sru if (os_strcmp(wpa_s->ifname, cmd) == 0) { 2736151497Sru found = 1; 2737151497Sru break; 2738151497Sru } 2739151497Sru } 2740151497Sru if (!found) { 2741151497Sru wpa_printf(MSG_ERROR, 2742151497Sru "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found", 2743151497Sru cmd); 2744151497Sru return -1; 2745151497Sru } 2746151497Sru if (wpa_s->mesh_if_created && wpa_s == orig) { 2747151497Sru wpa_printf(MSG_ERROR, 2748151497Sru "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself"); 2749151497Sru return -1; 2750151497Sru } 2751151497Sru 2752151497Sru wpa_s->reassociate = 0; 2753151497Sru wpa_s->disconnected = 1; 2754151497Sru wpa_supplicant_cancel_sched_scan(wpa_s); 2755151497Sru wpa_supplicant_cancel_scan(wpa_s); 2756151497Sru 2757151497Sru /* 2758151497Sru * TODO: If necessary write our own group_remove function, 2759151497Sru * for now we can reuse deauthenticate 2760151497Sru */ 2761151497Sru wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 2762151497Sru 2763114402Sru if (wpa_s->mesh_if_created) 2764114402Sru wpa_supplicant_remove_iface(global, wpa_s, 0); 2765114402Sru 2766114402Sru return 0; 2767114402Sru} 2768114402Sru 2769151497Sru 2770114402Srustatic int wpa_supplicant_ctrl_iface_mesh_peer_remove( 2771151497Sru struct wpa_supplicant *wpa_s, char *cmd) 2772151497Sru{ 2773151497Sru u8 addr[ETH_ALEN]; 2774114402Sru 2775114402Sru if (hwaddr_aton(cmd, addr) < 0) 2776114402Sru return -1; 2777114402Sru 2778151497Sru return wpas_mesh_peer_remove(wpa_s, addr); 2779114402Sru} 2780114402Sru 2781114402Sru 2782114402Srustatic int wpa_supplicant_ctrl_iface_mesh_peer_add( 2783114402Sru struct wpa_supplicant *wpa_s, char *cmd) 2784114402Sru{ 2785114402Sru u8 addr[ETH_ALEN]; 2786114402Sru int duration; 2787114402Sru char *pos; 2788114402Sru 2789114402Sru pos = os_strstr(cmd, " duration="); 2790114402Sru if (pos) { 2791114402Sru *pos = '\0'; 2792114402Sru duration = atoi(pos + 10); 2793114402Sru } else { 2794114402Sru duration = -1; 2795151497Sru } 2796114402Sru 2797114402Sru if (hwaddr_aton(cmd, addr)) 2798114402Sru return -1; 2799151497Sru 2800151497Sru return wpas_mesh_peer_add(wpa_s, addr, duration); 2801151497Sru} 2802151497Sru 2803151497Sru#endif /* CONFIG_MESH */ 2804151497Sru 2805151497Sru 2806151497Srustatic int wpa_supplicant_ctrl_iface_select_network( 2807151497Sru struct wpa_supplicant *wpa_s, char *cmd) 2808151497Sru{ 2809151497Sru int id; 2810151497Sru struct wpa_ssid *ssid; 2811151497Sru char *pos; 2812151497Sru 2813151497Sru /* cmd: "<network id>" or "any" */ 2814151497Sru if (os_strncmp(cmd, "any", 3) == 0) { 2815151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any"); 2816151497Sru ssid = NULL; 2817151497Sru } else { 2818151497Sru id = atoi(cmd); 2819151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id); 2820151497Sru 2821151497Sru ssid = wpa_config_get_network(wpa_s->conf, id); 2822151497Sru if (ssid == NULL) { 2823151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 2824151497Sru "network id=%d", id); 2825151497Sru return -1; 2826151497Sru } 2827151497Sru if (ssid->disabled == 2) { 2828151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 2829151497Sru "SELECT_NETWORK with persistent P2P group"); 2830151497Sru return -1; 2831151497Sru } 2832151497Sru } 2833151497Sru 2834151497Sru pos = os_strstr(cmd, " freq="); 2835151497Sru if (pos) { 2836151497Sru int *freqs = freq_range_to_channel_list(wpa_s, pos + 6); 2837151497Sru if (freqs) { 2838151497Sru wpa_s->scan_req = MANUAL_SCAN_REQ; 2839151497Sru os_free(wpa_s->manual_scan_freqs); 2840151497Sru wpa_s->manual_scan_freqs = freqs; 2841151497Sru } 2842151497Sru } 2843151497Sru 2844151497Sru wpa_s->scan_min_time.sec = 0; 2845114402Sru wpa_s->scan_min_time.usec = 0; 2846114402Sru wpa_supplicant_select_network(wpa_s, ssid); 2847114402Sru 2848114402Sru return 0; 2849114402Sru} 2850114402Sru 2851114402Sru 2852114402Srustatic int wpa_supplicant_ctrl_iface_enable_network( 2853114402Sru struct wpa_supplicant *wpa_s, char *cmd) 2854114402Sru{ 2855114402Sru int id; 2856114402Sru struct wpa_ssid *ssid; 2857114402Sru 2858114402Sru /* cmd: "<network id>" or "all" */ 2859114402Sru if (os_strcmp(cmd, "all") == 0) { 2860114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all"); 2861114402Sru ssid = NULL; 2862114402Sru } else { 2863114402Sru id = atoi(cmd); 2864114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id); 2865114402Sru 2866114402Sru ssid = wpa_config_get_network(wpa_s->conf, id); 2867114402Sru if (ssid == NULL) { 2868114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 2869114402Sru "network id=%d", id); 2870114402Sru return -1; 2871114402Sru } 2872114402Sru if (ssid->disabled == 2) { 2873114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 2874114402Sru "ENABLE_NETWORK with persistent P2P group"); 2875114402Sru return -1; 2876114402Sru } 2877114402Sru 2878151497Sru if (os_strstr(cmd, " no-connect")) { 2879114402Sru ssid->disabled = 0; 2880114402Sru return 0; 2881151497Sru } 2882114402Sru } 2883114402Sru wpa_s->scan_min_time.sec = 0; 2884114402Sru wpa_s->scan_min_time.usec = 0; 2885114402Sru wpa_supplicant_enable_network(wpa_s, ssid); 2886151497Sru 2887151497Sru return 0; 2888151497Sru} 2889151497Sru 2890151497Sru 2891151497Srustatic int wpa_supplicant_ctrl_iface_disable_network( 2892151497Sru struct wpa_supplicant *wpa_s, char *cmd) 2893151497Sru{ 2894151497Sru int id; 2895151497Sru struct wpa_ssid *ssid; 2896151497Sru 2897151497Sru /* cmd: "<network id>" or "all" */ 2898151497Sru if (os_strcmp(cmd, "all") == 0) { 2899151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all"); 2900151497Sru ssid = NULL; 2901151497Sru } else { 2902151497Sru id = atoi(cmd); 2903151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id); 2904151497Sru 2905151497Sru ssid = wpa_config_get_network(wpa_s->conf, id); 2906151497Sru if (ssid == NULL) { 2907151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 2908151497Sru "network id=%d", id); 2909151497Sru return -1; 2910151497Sru } 2911151497Sru if (ssid->disabled == 2) { 2912151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " 2913151497Sru "DISABLE_NETWORK with persistent P2P " 2914151497Sru "group"); 2915151497Sru return -1; 2916151497Sru } 2917151497Sru } 2918151497Sru wpa_supplicant_disable_network(wpa_s, ssid); 2919151497Sru 2920151497Sru return 0; 2921151497Sru} 2922151497Sru 2923151497Sru 2924151497Srustatic int wpa_supplicant_ctrl_iface_add_network( 2925151497Sru struct wpa_supplicant *wpa_s, char *buf, size_t buflen) 2926151497Sru{ 2927151497Sru struct wpa_ssid *ssid; 2928151497Sru int ret; 2929151497Sru 2930151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); 2931151497Sru 2932151497Sru ssid = wpa_supplicant_add_network(wpa_s); 2933151497Sru if (ssid == NULL) 2934114402Sru return -1; 2935151497Sru 2936151497Sru ret = os_snprintf(buf, buflen, "%d\n", ssid->id); 2937151497Sru if (os_snprintf_error(buflen, ret)) 2938114402Sru return -1; 2939114402Sru return ret; 2940114402Sru} 2941114402Sru 2942151497Sru 2943151497Srustatic int wpa_supplicant_ctrl_iface_remove_network( 2944114402Sru struct wpa_supplicant *wpa_s, char *cmd) 2945114402Sru{ 2946114402Sru int id; 2947151497Sru struct wpa_ssid *ssid; 2948151497Sru int result; 2949114402Sru 2950151497Sru /* cmd: "<network id>" or "all" */ 2951151497Sru if (os_strcmp(cmd, "all") == 0) { 2952151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); 2953151497Sru if (wpa_s->sched_scanning) 2954151497Sru wpa_supplicant_cancel_sched_scan(wpa_s); 2955151497Sru 2956151497Sru eapol_sm_invalidate_cached_session(wpa_s->eapol); 2957151497Sru if (wpa_s->current_ssid) { 2958151497Sru#ifdef CONFIG_SME 2959151497Sru wpa_s->sme.prev_bssid_set = 0; 2960151497Sru#endif /* CONFIG_SME */ 2961151497Sru wpa_sm_set_config(wpa_s->wpa, NULL); 2962151497Sru eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); 2963151497Sru if (wpa_s->wpa_state >= WPA_AUTHENTICATING) 2964114402Sru wpa_s->own_disconnect_req = 1; 2965114402Sru wpa_supplicant_deauthenticate( 2966114402Sru wpa_s, WLAN_REASON_DEAUTH_LEAVING); 2967151497Sru } 2968151497Sru ssid = wpa_s->conf->ssid; 2969151497Sru while (ssid) { 2970151497Sru struct wpa_ssid *remove_ssid = ssid; 2971151497Sru id = ssid->id; 2972151497Sru ssid = ssid->next; 2973151497Sru if (wpa_s->last_ssid == remove_ssid) 2974151497Sru wpa_s->last_ssid = NULL; 2975151497Sru wpas_notify_network_removed(wpa_s, remove_ssid); 2976151497Sru wpa_config_remove_network(wpa_s->conf, id); 2977151497Sru } 2978151497Sru return 0; 2979151497Sru } 2980151497Sru 2981151497Sru id = atoi(cmd); 2982151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); 2983151497Sru 2984151497Sru result = wpa_supplicant_remove_network(wpa_s, id); 2985114402Sru if (result == -1) { 2986114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " 2987114402Sru "id=%d", id); 2988114402Sru return -1; 2989114402Sru } 2990114402Sru if (result == -2) { 2991114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the " 2992114402Sru "network id=%d", id); 2993114402Sru return -1; 2994151497Sru } 2995114402Sru return 0; 2996114402Sru} 2997151497Sru 2998114402Sru 2999151497Srustatic int wpa_supplicant_ctrl_iface_update_network( 3000114402Sru struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, 3001151497Sru char *name, char *value) 3002114402Sru{ 3003114402Sru int ret; 3004114402Sru 3005151497Sru ret = wpa_config_set(ssid, name, value, 0); 3006151497Sru if (ret < 0) { 3007151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " 3008114402Sru "variable '%s'", name); 3009151497Sru return -1; 3010151497Sru } 3011151497Sru if (ret == 1) 3012114402Sru return 0; /* No change to the previously configured value */ 3013114402Sru 3014114402Sru if (os_strcmp(name, "bssid") != 0 && 3015114402Sru os_strcmp(name, "priority") != 0) { 3016114402Sru wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); 3017114402Sru 3018114402Sru if (wpa_s->current_ssid == ssid || 3019114402Sru wpa_s->current_ssid == NULL) { 3020114402Sru /* 3021114402Sru * Invalidate the EAP session cache if anything in the 3022114402Sru * current or previously used configuration changes. 3023114402Sru */ 3024114402Sru eapol_sm_invalidate_cached_session(wpa_s->eapol); 3025151497Sru } 3026114402Sru } 3027114402Sru 3028114402Sru if ((os_strcmp(name, "psk") == 0 && 3029114402Sru value[0] == '"' && ssid->ssid_len) || 3030151497Sru (os_strcmp(name, "ssid") == 0 && ssid->passphrase)) 3031114402Sru wpa_config_update_psk(ssid); 3032114402Sru else if (os_strcmp(name, "priority") == 0) 3033114402Sru wpa_config_update_prio_list(wpa_s->conf); 3034151497Sru 3035114402Sru return 0; 3036114402Sru} 3037114402Sru 3038114402Sru 3039114402Srustatic int wpa_supplicant_ctrl_iface_set_network( 3040114402Sru struct wpa_supplicant *wpa_s, char *cmd) 3041114402Sru{ 3042114402Sru int id, ret, prev_bssid_set, prev_disabled; 3043151497Sru struct wpa_ssid *ssid; 3044114402Sru char *name, *value; 3045114402Sru u8 prev_bssid[ETH_ALEN]; 3046114402Sru 3047114402Sru /* cmd: "<network id> <variable name> <value>" */ 3048114402Sru name = os_strchr(cmd, ' '); 3049114402Sru if (name == NULL) 3050114402Sru return -1; 3051114402Sru *name++ = '\0'; 3052151497Sru 3053114402Sru value = os_strchr(name, ' '); 3054114402Sru if (value == NULL) 3055114402Sru return -1; 3056114402Sru *value++ = '\0'; 3057114402Sru 3058151497Sru id = atoi(cmd); 3059114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'", 3060114402Sru id, name); 3061114402Sru wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 3062114402Sru (u8 *) value, os_strlen(value)); 3063114402Sru 3064114402Sru ssid = wpa_config_get_network(wpa_s->conf, id); 3065114402Sru if (ssid == NULL) { 3066114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " 3067114402Sru "id=%d", id); 3068114402Sru return -1; 3069114402Sru } 3070114402Sru 3071114402Sru prev_bssid_set = ssid->bssid_set; 3072114402Sru prev_disabled = ssid->disabled; 3073151497Sru os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN); 3074151497Sru ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, 3075151497Sru value); 3076151497Sru if (ret == 0 && 3077114402Sru (ssid->bssid_set != prev_bssid_set || 3078151497Sru os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0)) 3079151497Sru wpas_notify_network_bssid_set_changed(wpa_s, ssid); 3080114402Sru 3081114402Sru if (prev_disabled != ssid->disabled && 3082114402Sru (prev_disabled == 2 || ssid->disabled == 2)) 3083114402Sru wpas_notify_network_type_changed(wpa_s, ssid); 3084151497Sru 3085151497Sru return ret; 3086114402Sru} 3087114402Sru 3088114402Sru 3089114402Srustatic int wpa_supplicant_ctrl_iface_get_network( 3090114402Sru struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 3091151497Sru{ 3092114402Sru int id; 3093151497Sru size_t res; 3094114402Sru struct wpa_ssid *ssid; 3095151497Sru char *name, *value; 3096151497Sru 3097151497Sru /* cmd: "<network id> <variable name>" */ 3098114402Sru name = os_strchr(cmd, ' '); 3099114402Sru if (name == NULL || buflen == 0) 3100114402Sru return -1; 3101114402Sru *name++ = '\0'; 3102151497Sru 3103151497Sru id = atoi(cmd); 3104114402Sru wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'", 3105151497Sru id, name); 3106151497Sru 3107114402Sru ssid = wpa_config_get_network(wpa_s->conf, id); 3108114402Sru if (ssid == NULL) { 3109114402Sru wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network " 3110114402Sru "id=%d", id); 3111114402Sru return -1; 3112114402Sru } 3113114402Sru 3114114402Sru value = wpa_config_get_no_key(ssid, name); 3115114402Sru if (value == NULL) { 3116114402Sru wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network " 3117114402Sru "variable '%s'", name); 3118114402Sru return -1; 3119114402Sru } 3120114402Sru 3121151497Sru res = os_strlcpy(buf, value, buflen); 3122114402Sru if (res >= buflen) { 3123114402Sru os_free(value); 3124114402Sru return -1; 3125114402Sru } 3126114402Sru 3127114402Sru os_free(value); 3128114402Sru 3129114402Sru return res; 3130151497Sru} 3131151497Sru 3132114402Sru 3133114402Srustatic int wpa_supplicant_ctrl_iface_dup_network( 3134114402Sru struct wpa_supplicant *wpa_s, char *cmd, 3135114402Sru struct wpa_supplicant *dst_wpa_s) 3136114402Sru{ 3137114402Sru struct wpa_ssid *ssid_s, *ssid_d; 3138114402Sru char *name, *id, *value; 3139114402Sru int id_s, id_d, ret; 3140114402Sru 3141114402Sru /* cmd: "<src network id> <dst network id> <variable name>" */ 3142114402Sru id = os_strchr(cmd, ' '); 3143114402Sru if (id == NULL) 3144114402Sru return -1; 3145114402Sru *id++ = '\0'; 3146114402Sru 3147114402Sru name = os_strchr(id, ' '); 3148114402Sru if (name == NULL) 3149114402Sru return -1; 3150114402Sru *name++ = '\0'; 3151114402Sru 3152114402Sru id_s = atoi(cmd); 3153114402Sru id_d = atoi(id); 3154114402Sru 3155151497Sru wpa_printf(MSG_DEBUG, 3156151497Sru "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'", 3157151497Sru wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name); 3158151497Sru 3159151497Sru ssid_s = wpa_config_get_network(wpa_s->conf, id_s); 3160151497Sru if (ssid_s == NULL) { 3161114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3162114402Sru "network id=%d", id_s); 3163114402Sru return -1; 3164114402Sru } 3165114402Sru 3166114402Sru ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d); 3167114402Sru if (ssid_d == NULL) { 3168114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 3169114402Sru "network id=%d", id_d); 3170114402Sru return -1; 3171114402Sru } 3172114402Sru 3173114402Sru value = wpa_config_get(ssid_s, name); 3174114402Sru if (value == NULL) { 3175114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " 3176114402Sru "variable '%s'", name); 3177114402Sru return -1; 3178114402Sru } 3179114402Sru 3180114402Sru ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name, 3181114402Sru value); 3182114402Sru 3183114402Sru os_free(value); 3184151497Sru 3185151497Sru return ret; 3186114402Sru} 3187114402Sru 3188114402Sru 3189114402Srustatic int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s, 3190114402Sru char *buf, size_t buflen) 3191114402Sru{ 3192114402Sru char *pos, *end; 3193114402Sru struct wpa_cred *cred; 3194114402Sru int ret; 3195114402Sru 3196114402Sru pos = buf; 3197114402Sru end = buf + buflen; 3198114402Sru ret = os_snprintf(pos, end - pos, 3199114402Sru "cred id / realm / username / domain / imsi\n"); 3200151497Sru if (os_snprintf_error(end - pos, ret)) 3201151497Sru return pos - buf; 3202151497Sru pos += ret; 3203151497Sru 3204151497Sru cred = wpa_s->conf->cred; 3205114402Sru while (cred) { 3206151497Sru ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n", 3207151497Sru cred->id, cred->realm ? cred->realm : "", 3208114402Sru cred->username ? cred->username : "", 3209114402Sru cred->domain ? cred->domain[0] : "", 3210114402Sru cred->imsi ? cred->imsi : ""); 3211151497Sru if (os_snprintf_error(end - pos, ret)) 3212114402Sru return pos - buf; 3213151497Sru pos += ret; 3214114402Sru 3215151497Sru cred = cred->next; 3216151497Sru } 3217151497Sru 3218151497Sru return pos - buf; 3219151497Sru} 3220114402Sru 3221114402Sru 3222151497Srustatic int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, 3223151497Sru char *buf, size_t buflen) 3224151497Sru{ 3225114402Sru struct wpa_cred *cred; 3226114402Sru int ret; 3227114402Sru 3228114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED"); 3229114402Sru 3230114402Sru cred = wpa_config_add_cred(wpa_s->conf); 3231114402Sru if (cred == NULL) 3232114402Sru return -1; 3233114402Sru 3234114402Sru wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id); 3235114402Sru 3236114402Sru ret = os_snprintf(buf, buflen, "%d\n", cred->id); 3237114402Sru if (os_snprintf_error(buflen, ret)) 3238114402Sru return -1; 3239114402Sru return ret; 3240114402Sru} 3241114402Sru 3242114402Sru 3243151497Srustatic int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s, 3244151497Sru struct wpa_cred *cred) 3245114402Sru{ 3246151497Sru struct wpa_ssid *ssid; 3247151497Sru char str[20]; 3248151497Sru int id; 3249114402Sru 3250151497Sru if (cred == NULL) { 3251114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); 3252151497Sru return -1; 3253114402Sru } 3254114402Sru 3255114402Sru id = cred->id; 3256114402Sru if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { 3257114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); 3258114402Sru return -1; 3259114402Sru } 3260114402Sru 3261114402Sru wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); 3262114402Sru 3263151497Sru /* Remove any network entry created based on the removed credential */ 3264114402Sru ssid = wpa_s->conf->ssid; 3265114402Sru while (ssid) { 3266114402Sru if (ssid->parent_cred == cred) { 3267151497Sru int res; 3268151497Sru 3269151497Sru wpa_printf(MSG_DEBUG, "Remove network id %d since it " 3270151497Sru "used the removed credential", ssid->id); 3271151497Sru res = os_snprintf(str, sizeof(str), "%d", ssid->id); 3272114402Sru if (os_snprintf_error(sizeof(str), res)) 3273114402Sru str[sizeof(str) - 1] = '\0'; 3274114402Sru ssid = ssid->next; 3275114402Sru wpa_supplicant_ctrl_iface_remove_network(wpa_s, str); 3276114402Sru } else 3277114402Sru ssid = ssid->next; 3278114402Sru } 3279114402Sru 3280114402Sru return 0; 3281114402Sru} 3282151497Sru 3283114402Sru 3284114402Srustatic int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, 3285114402Sru char *cmd) 3286114402Sru{ 3287151497Sru int id; 3288114402Sru struct wpa_cred *cred, *prev; 3289151497Sru 3290151497Sru /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or 3291114402Sru * "provisioning_sp=<FQDN> */ 3292114402Sru if (os_strcmp(cmd, "all") == 0) { 3293114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); 3294114402Sru cred = wpa_s->conf->cred; 3295114402Sru while (cred) { 3296114402Sru prev = cred; 3297114402Sru cred = cred->next; 3298114402Sru wpas_ctrl_remove_cred(wpa_s, prev); 3299114402Sru } 3300114402Sru return 0; 3301114402Sru } 3302114402Sru 3303114402Sru if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) { 3304114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'", 3305114402Sru cmd + 8); 3306114402Sru cred = wpa_s->conf->cred; 3307114402Sru while (cred) { 3308114402Sru prev = cred; 3309114402Sru cred = cred->next; 3310151497Sru if (prev->domain) { 3311114402Sru size_t i; 3312114402Sru for (i = 0; i < prev->num_domain; i++) { 3313114402Sru if (os_strcmp(prev->domain[i], cmd + 8) 3314114402Sru != 0) 3315114402Sru continue; 3316114402Sru wpas_ctrl_remove_cred(wpa_s, prev); 3317114402Sru break; 3318114402Sru } 3319114402Sru } 3320114402Sru } 3321114402Sru return 0; 3322114402Sru } 3323114402Sru 3324114402Sru if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) { 3325114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'", 3326114402Sru cmd + 16); 3327114402Sru cred = wpa_s->conf->cred; 3328114402Sru while (cred) { 3329114402Sru prev = cred; 3330151497Sru cred = cred->next; 3331114402Sru if (prev->provisioning_sp && 3332114402Sru os_strcmp(prev->provisioning_sp, cmd + 16) == 0) 3333114402Sru wpas_ctrl_remove_cred(wpa_s, prev); 3334114402Sru } 3335114402Sru return 0; 3336114402Sru } 3337114402Sru 3338114402Sru id = atoi(cmd); 3339114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); 3340114402Sru 3341114402Sru cred = wpa_config_get_cred(wpa_s->conf, id); 3342114402Sru return wpas_ctrl_remove_cred(wpa_s, cred); 3343114402Sru} 3344114402Sru 3345114402Sru 3346151497Srustatic int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s, 3347114402Sru char *cmd) 3348114402Sru{ 3349114402Sru int id; 3350114402Sru struct wpa_cred *cred; 3351114402Sru char *name, *value; 3352114402Sru 3353114402Sru /* cmd: "<cred id> <variable name> <value>" */ 3354114402Sru name = os_strchr(cmd, ' '); 3355114402Sru if (name == NULL) 3356114402Sru return -1; 3357114402Sru *name++ = '\0'; 3358114402Sru 3359114402Sru value = os_strchr(name, ' '); 3360114402Sru if (value == NULL) 3361114402Sru return -1; 3362114402Sru *value++ = '\0'; 3363114402Sru 3364114402Sru id = atoi(cmd); 3365114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'", 3366114402Sru id, name); 3367114402Sru wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", 3368114402Sru (u8 *) value, os_strlen(value)); 3369114402Sru 3370114402Sru cred = wpa_config_get_cred(wpa_s->conf, id); 3371114402Sru if (cred == NULL) { 3372114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", 3373114402Sru id); 3374114402Sru return -1; 3375114402Sru } 3376114402Sru 3377114402Sru if (wpa_config_set_cred(cred, name, value, 0) < 0) { 3378114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred " 3379114402Sru "variable '%s'", name); 3380114402Sru return -1; 3381114402Sru } 3382114402Sru 3383114402Sru wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name); 3384114402Sru 3385114402Sru return 0; 3386114402Sru} 3387114402Sru 3388151497Sru 3389114402Srustatic int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s, 3390114402Sru char *cmd, char *buf, 3391114402Sru size_t buflen) 3392151497Sru{ 3393114402Sru int id; 3394114402Sru size_t res; 3395114402Sru struct wpa_cred *cred; 3396114402Sru char *name, *value; 3397114402Sru 3398114402Sru /* cmd: "<cred id> <variable name>" */ 3399114402Sru name = os_strchr(cmd, ' '); 3400114402Sru if (name == NULL) 3401114402Sru return -1; 3402151497Sru *name++ = '\0'; 3403151497Sru 3404114402Sru id = atoi(cmd); 3405114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'", 3406114402Sru id, name); 3407114402Sru 3408114402Sru cred = wpa_config_get_cred(wpa_s->conf, id); 3409114402Sru if (cred == NULL) { 3410114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", 3411114402Sru id); 3412114402Sru return -1; 3413114402Sru } 3414114402Sru 3415114402Sru value = wpa_config_get_cred_no_key(cred, name); 3416114402Sru if (value == NULL) { 3417114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'", 3418114402Sru name); 3419151497Sru return -1; 3420114402Sru } 3421114402Sru 3422114402Sru res = os_strlcpy(buf, value, buflen); 3423151497Sru if (res >= buflen) { 3424114402Sru os_free(value); 3425114402Sru return -1; 3426114402Sru } 3427114402Sru 3428114402Sru os_free(value); 3429114402Sru 3430114402Sru return res; 3431114402Sru} 3432114402Sru 3433114402Sru 3434114402Sru#ifndef CONFIG_NO_CONFIG_WRITE 3435114402Srustatic int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) 3436151497Sru{ 3437114402Sru int ret; 3438114402Sru 3439114402Sru if (!wpa_s->conf->update_config) { 3440114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed " 3441114402Sru "to update configuration (update_config=0)"); 3442114402Sru return -1; 3443114402Sru } 3444114402Sru 3445114402Sru ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 3446114402Sru if (ret) { 3447114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to " 3448114402Sru "update configuration"); 3449114402Sru } else { 3450114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration" 3451114402Sru " updated"); 3452114402Sru } 3453114402Sru 3454114402Sru return ret; 3455114402Sru} 3456114402Sru#endif /* CONFIG_NO_CONFIG_WRITE */ 3457114402Sru 3458114402Sru 3459114402Srustruct cipher_info { 3460114402Sru unsigned int capa; 3461114402Sru const char *name; 3462114402Sru int group_only; 3463114402Sru}; 3464114402Sru 3465114402Srustatic const struct cipher_info ciphers[] = { 3466114402Sru { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 }, 3467114402Sru { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 }, 3468114402Sru { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 }, 3469114402Sru { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, 3470114402Sru { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, 3471114402Sru { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, 3472114402Sru { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, 3473114402Sru { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } 3474114402Sru}; 3475114402Sru 3476114402Srustatic const struct cipher_info ciphers_group_mgmt[] = { 3477114402Sru { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 }, 3478114402Sru { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 }, 3479114402Sru { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 }, 3480114402Sru { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 }, 3481114402Sru}; 3482114402Sru 3483114402Sru 3484114402Srustatic int ctrl_iface_get_capability_pairwise(int res, char *strict, 3485114402Sru struct wpa_driver_capa *capa, 3486114402Sru char *buf, size_t buflen) 3487114402Sru{ 3488114402Sru int ret; 3489114402Sru char *pos, *end; 3490114402Sru size_t len; 3491114402Sru unsigned int i; 3492114402Sru 3493114402Sru pos = buf; 3494114402Sru end = pos + buflen; 3495114402Sru 3496114402Sru if (res < 0) { 3497114402Sru if (strict) 3498114402Sru return 0; 3499114402Sru len = os_strlcpy(buf, "CCMP TKIP NONE", buflen); 3500114402Sru if (len >= buflen) 3501114402Sru return -1; 3502114402Sru return len; 3503114402Sru } 3504151497Sru 3505151497Sru for (i = 0; i < ARRAY_SIZE(ciphers); i++) { 3506114402Sru if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) { 3507114402Sru ret = os_snprintf(pos, end - pos, "%s%s", 3508114402Sru pos == buf ? "" : " ", 3509114402Sru ciphers[i].name); 3510114402Sru if (os_snprintf_error(end - pos, ret)) 3511114402Sru return pos - buf; 3512114402Sru pos += ret; 3513114402Sru } 3514114402Sru } 3515114402Sru 3516114402Sru return pos - buf; 3517114402Sru} 3518114402Sru 3519151497Sru 3520151497Srustatic int ctrl_iface_get_capability_group(int res, char *strict, 3521151497Sru struct wpa_driver_capa *capa, 3522114402Sru char *buf, size_t buflen) 3523114402Sru{ 3524114402Sru int ret; 3525114402Sru char *pos, *end; 3526114402Sru size_t len; 3527114402Sru unsigned int i; 3528114402Sru 3529114402Sru pos = buf; 3530114402Sru end = pos + buflen; 3531114402Sru 3532114402Sru if (res < 0) { 3533151497Sru if (strict) 3534114402Sru return 0; 3535151497Sru len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen); 3536151497Sru if (len >= buflen) 3537151497Sru return -1; 3538151497Sru return len; 3539151497Sru } 3540151497Sru 3541151497Sru for (i = 0; i < ARRAY_SIZE(ciphers); i++) { 3542151497Sru if (capa->enc & ciphers[i].capa) { 3543151497Sru ret = os_snprintf(pos, end - pos, "%s%s", 3544151497Sru pos == buf ? "" : " ", 3545151497Sru ciphers[i].name); 3546151497Sru if (os_snprintf_error(end - pos, ret)) 3547151497Sru return pos - buf; 3548151497Sru pos += ret; 3549151497Sru } 3550151497Sru } 3551151497Sru 3552151497Sru return pos - buf; 3553151497Sru} 3554151497Sru 3555114402Sru 3556114402Srustatic int ctrl_iface_get_capability_group_mgmt(int res, char *strict, 3557114402Sru struct wpa_driver_capa *capa, 3558114402Sru char *buf, size_t buflen) 3559114402Sru{ 3560114402Sru int ret; 3561114402Sru char *pos, *end; 3562114402Sru unsigned int i; 3563114402Sru 3564114402Sru pos = buf; 3565114402Sru end = pos + buflen; 3566114402Sru 3567114402Sru if (res < 0) 3568114402Sru return 0; 3569114402Sru 3570114402Sru for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) { 3571151497Sru if (capa->enc & ciphers_group_mgmt[i].capa) { 3572151497Sru ret = os_snprintf(pos, end - pos, "%s%s", 3573114402Sru pos == buf ? "" : " ", 3574114402Sru ciphers_group_mgmt[i].name); 3575151497Sru if (os_snprintf_error(end - pos, ret)) 3576114402Sru return pos - buf; 3577114402Sru pos += ret; 3578114402Sru } 3579114402Sru } 3580114402Sru 3581114402Sru return pos - buf; 3582114402Sru} 3583114402Sru 3584114402Sru 3585114402Srustatic int ctrl_iface_get_capability_key_mgmt(int res, char *strict, 3586114402Sru struct wpa_driver_capa *capa, 3587114402Sru char *buf, size_t buflen) 3588114402Sru{ 3589151497Sru int ret; 3590151497Sru char *pos, *end; 3591151497Sru size_t len; 3592114402Sru 3593151497Sru pos = buf; 3594114402Sru end = pos + buflen; 3595114402Sru 3596114402Sru if (res < 0) { 3597114402Sru if (strict) 3598151497Sru return 0; 3599151497Sru len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE " 3600114402Sru "NONE", buflen); 3601114402Sru if (len >= buflen) 3602114402Sru return -1; 3603114402Sru return len; 3604114402Sru } 3605151497Sru 3606114402Sru ret = os_snprintf(pos, end - pos, "NONE IEEE8021X"); 3607114402Sru if (os_snprintf_error(end - pos, ret)) 3608114402Sru return pos - buf; 3609114402Sru pos += ret; 3610151497Sru 3611114402Sru if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 3612114402Sru WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { 3613114402Sru ret = os_snprintf(pos, end - pos, " WPA-EAP"); 3614114402Sru if (os_snprintf_error(end - pos, ret)) 3615114402Sru return pos - buf; 3616114402Sru pos += ret; 3617114402Sru } 3618114402Sru 3619114402Sru if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 3620114402Sru WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 3621114402Sru ret = os_snprintf(pos, end - pos, " WPA-PSK"); 3622114402Sru if (os_snprintf_error(end - pos, ret)) 3623114402Sru return pos - buf; 3624151497Sru pos += ret; 3625151497Sru } 3626114402Sru 3627114402Sru if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { 3628114402Sru ret = os_snprintf(pos, end - pos, " WPA-NONE"); 3629114402Sru if (os_snprintf_error(end - pos, ret)) 3630151497Sru return pos - buf; 3631151497Sru pos += ret; 3632151497Sru } 3633151497Sru 3634151497Sru#ifdef CONFIG_SUITEB 3635114402Sru if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) { 3636114402Sru ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B"); 3637151497Sru if (os_snprintf_error(end - pos, ret)) 3638151497Sru return pos - buf; 3639114402Sru pos += ret; 3640114402Sru } 3641114402Sru#endif /* CONFIG_SUITEB */ 3642114402Sru#ifdef CONFIG_SUITEB192 3643151497Sru if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) { 3644114402Sru ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192"); 3645114402Sru if (os_snprintf_error(end - pos, ret)) 3646114402Sru return pos - buf; 3647114402Sru pos += ret; 3648114402Sru } 3649151497Sru#endif /* CONFIG_SUITEB192 */ 3650114402Sru 3651114402Sru return pos - buf; 3652114402Sru} 3653114402Sru 3654114402Sru 3655151497Srustatic int ctrl_iface_get_capability_proto(int res, char *strict, 3656151497Sru struct wpa_driver_capa *capa, 3657114402Sru char *buf, size_t buflen) 3658114402Sru{ 3659114402Sru int ret; 3660114402Sru char *pos, *end; 3661114402Sru size_t len; 3662114402Sru 3663114402Sru pos = buf; 3664114402Sru end = pos + buflen; 3665114402Sru 3666114402Sru if (res < 0) { 3667151497Sru if (strict) 3668114402Sru return 0; 3669114402Sru len = os_strlcpy(buf, "RSN WPA", buflen); 3670114402Sru if (len >= buflen) 3671114402Sru return -1; 3672151497Sru return len; 3673114402Sru } 3674114402Sru 3675114402Sru if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 3676114402Sru WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 3677114402Sru ret = os_snprintf(pos, end - pos, "%sRSN", 3678114402Sru pos == buf ? "" : " "); 3679151497Sru if (os_snprintf_error(end - pos, ret)) 3680114402Sru return pos - buf; 3681114402Sru pos += ret; 3682114402Sru } 3683114402Sru 3684114402Sru if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 3685114402Sru WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { 3686114402Sru ret = os_snprintf(pos, end - pos, "%sWPA", 3687114402Sru pos == buf ? "" : " "); 3688114402Sru if (os_snprintf_error(end - pos, ret)) 3689114402Sru return pos - buf; 3690114402Sru pos += ret; 3691114402Sru } 3692114402Sru 3693114402Sru return pos - buf; 3694114402Sru} 3695114402Sru 3696114402Sru 3697114402Srustatic int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s, 3698114402Sru int res, char *strict, 3699114402Sru struct wpa_driver_capa *capa, 3700114402Sru char *buf, size_t buflen) 3701114402Sru{ 3702114402Sru int ret; 3703151497Sru char *pos, *end; 3704151497Sru size_t len; 3705114402Sru 3706114402Sru pos = buf; 3707114402Sru end = pos + buflen; 3708151497Sru 3709151497Sru if (res < 0) { 3710151497Sru if (strict) 3711151497Sru return 0; 3712114402Sru len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen); 3713114402Sru if (len >= buflen) 3714114402Sru return -1; 3715151497Sru return len; 3716151497Sru } 3717114402Sru 3718114402Sru if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) { 3719114402Sru ret = os_snprintf(pos, end - pos, "%sOPEN", 3720114402Sru pos == buf ? "" : " "); 3721114402Sru if (os_snprintf_error(end - pos, ret)) 3722114402Sru return pos - buf; 3723114402Sru pos += ret; 3724114402Sru } 3725114402Sru 3726114402Sru if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) { 3727114402Sru ret = os_snprintf(pos, end - pos, "%sSHARED", 3728114402Sru pos == buf ? "" : " "); 3729114402Sru if (os_snprintf_error(end - pos, ret)) 3730114402Sru return pos - buf; 3731114402Sru pos += ret; 3732114402Sru } 3733114402Sru 3734114402Sru if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) { 3735114402Sru ret = os_snprintf(pos, end - pos, "%sLEAP", 3736114402Sru pos == buf ? "" : " "); 3737114402Sru if (os_snprintf_error(end - pos, ret)) 3738114402Sru return pos - buf; 3739114402Sru pos += ret; 3740114402Sru } 3741114402Sru 3742114402Sru#ifdef CONFIG_SAE 3743114402Sru if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) { 3744114402Sru ret = os_snprintf(pos, end - pos, "%sSAE", 3745114402Sru pos == buf ? "" : " "); 3746114402Sru if (os_snprintf_error(end - pos, ret)) 3747114402Sru return pos - buf; 3748114402Sru pos += ret; 3749114402Sru } 3750114402Sru#endif /* CONFIG_SAE */ 3751114402Sru 3752114402Sru return pos - buf; 3753114402Sru} 3754114402Sru 3755114402Sru 3756114402Srustatic int ctrl_iface_get_capability_modes(int res, char *strict, 3757114402Sru struct wpa_driver_capa *capa, 3758114402Sru char *buf, size_t buflen) 3759114402Sru{ 3760114402Sru int ret; 3761114402Sru char *pos, *end; 3762114402Sru size_t len; 3763114402Sru 3764151497Sru pos = buf; 3765151497Sru end = pos + buflen; 3766151497Sru 3767151497Sru if (res < 0) { 3768151497Sru if (strict) 3769151497Sru return 0; 3770151497Sru len = os_strlcpy(buf, "IBSS AP", buflen); 3771151497Sru if (len >= buflen) 3772151497Sru return -1; 3773151497Sru return len; 3774151497Sru } 3775151497Sru 3776151497Sru if (capa->flags & WPA_DRIVER_FLAGS_IBSS) { 3777151497Sru ret = os_snprintf(pos, end - pos, "%sIBSS", 3778151497Sru pos == buf ? "" : " "); 3779151497Sru if (os_snprintf_error(end - pos, ret)) 3780151497Sru return pos - buf; 3781151497Sru pos += ret; 3782151497Sru } 3783151497Sru 3784151497Sru if (capa->flags & WPA_DRIVER_FLAGS_AP) { 3785151497Sru ret = os_snprintf(pos, end - pos, "%sAP", 3786151497Sru pos == buf ? "" : " "); 3787151497Sru if (os_snprintf_error(end - pos, ret)) 3788151497Sru return pos - buf; 3789151497Sru pos += ret; 3790151497Sru } 3791151497Sru 3792151497Sru#ifdef CONFIG_MESH 3793151497Sru if (capa->flags & WPA_DRIVER_FLAGS_MESH) { 3794151497Sru ret = os_snprintf(pos, end - pos, "%sMESH", 3795114402Sru pos == buf ? "" : " "); 3796114402Sru if (os_snprintf_error(end - pos, ret)) 3797114402Sru return pos - buf; 3798114402Sru pos += ret; 3799114402Sru } 3800114402Sru#endif /* CONFIG_MESH */ 3801114402Sru 3802114402Sru return pos - buf; 3803114402Sru} 3804114402Sru 3805151497Sru 3806114402Srustatic int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, 3807114402Sru char *buf, size_t buflen) 3808114402Sru{ 3809114402Sru struct hostapd_channel_data *chnl; 3810114402Sru int ret, i, j; 3811114402Sru char *pos, *end, *hmode; 3812114402Sru 3813114402Sru pos = buf; 3814114402Sru end = pos + buflen; 3815114402Sru 3816114402Sru for (j = 0; j < wpa_s->hw.num_modes; j++) { 3817114402Sru switch (wpa_s->hw.modes[j].mode) { 3818114402Sru case HOSTAPD_MODE_IEEE80211B: 3819114402Sru hmode = "B"; 3820114402Sru break; 3821114402Sru case HOSTAPD_MODE_IEEE80211G: 3822114402Sru hmode = "G"; 3823114402Sru break; 3824114402Sru case HOSTAPD_MODE_IEEE80211A: 3825114402Sru hmode = "A"; 3826114402Sru break; 3827114402Sru case HOSTAPD_MODE_IEEE80211AD: 3828114402Sru hmode = "AD"; 3829114402Sru break; 3830114402Sru default: 3831114402Sru continue; 3832114402Sru } 3833114402Sru ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode); 3834114402Sru if (os_snprintf_error(end - pos, ret)) 3835114402Sru return pos - buf; 3836114402Sru pos += ret; 3837114402Sru chnl = wpa_s->hw.modes[j].channels; 3838114402Sru for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { 3839114402Sru if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) 3840114402Sru continue; 3841114402Sru ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan); 3842114402Sru if (os_snprintf_error(end - pos, ret)) 3843114402Sru return pos - buf; 3844114402Sru pos += ret; 3845114402Sru } 3846114402Sru ret = os_snprintf(pos, end - pos, "\n"); 3847114402Sru if (os_snprintf_error(end - pos, ret)) 3848114402Sru return pos - buf; 3849114402Sru pos += ret; 3850114402Sru } 3851114402Sru 3852114402Sru return pos - buf; 3853114402Sru} 3854151497Sru 3855151497Sru 3856114402Srustatic int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s, 3857114402Sru char *buf, size_t buflen) 3858114402Sru{ 3859114402Sru struct hostapd_channel_data *chnl; 3860151497Sru int ret, i, j; 3861151497Sru char *pos, *end, *hmode; 3862114402Sru 3863114402Sru pos = buf; 3864114402Sru end = pos + buflen; 3865114402Sru 3866114402Sru for (j = 0; j < wpa_s->hw.num_modes; j++) { 3867151497Sru switch (wpa_s->hw.modes[j].mode) { 3868151497Sru case HOSTAPD_MODE_IEEE80211B: 3869114402Sru hmode = "B"; 3870114402Sru break; 3871114402Sru case HOSTAPD_MODE_IEEE80211G: 3872114402Sru hmode = "G"; 3873114402Sru break; 3874151497Sru case HOSTAPD_MODE_IEEE80211A: 3875151497Sru hmode = "A"; 3876114402Sru break; 3877114402Sru case HOSTAPD_MODE_IEEE80211AD: 3878114402Sru hmode = "AD"; 3879114402Sru break; 3880114402Sru default: 3881114402Sru continue; 3882114402Sru } 3883114402Sru ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n", 3884114402Sru hmode); 3885114402Sru if (os_snprintf_error(end - pos, ret)) 3886114402Sru return pos - buf; 3887114402Sru pos += ret; 3888114402Sru chnl = wpa_s->hw.modes[j].channels; 3889114402Sru for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { 3890114402Sru if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) 3891114402Sru continue; 3892114402Sru ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n", 3893114402Sru chnl[i].chan, chnl[i].freq, 3894114402Sru chnl[i].flag & HOSTAPD_CHAN_NO_IR ? 3895114402Sru " (NO_IR)" : "", 3896114402Sru chnl[i].flag & HOSTAPD_CHAN_RADAR ? 3897114402Sru " (DFS)" : ""); 3898114402Sru 3899114402Sru if (os_snprintf_error(end - pos, ret)) 3900114402Sru return pos - buf; 3901114402Sru pos += ret; 3902114402Sru } 3903114402Sru ret = os_snprintf(pos, end - pos, "\n"); 3904114402Sru if (os_snprintf_error(end - pos, ret)) 3905114402Sru return pos - buf; 3906114402Sru pos += ret; 3907114402Sru } 3908114402Sru 3909114402Sru return pos - buf; 3910114402Sru} 3911114402Sru 3912114402Sru 3913114402Srustatic int wpa_supplicant_ctrl_iface_get_capability( 3914114402Sru struct wpa_supplicant *wpa_s, const char *_field, char *buf, 3915114402Sru size_t buflen) 3916114402Sru{ 3917114402Sru struct wpa_driver_capa capa; 3918114402Sru int res; 3919114402Sru char *strict; 3920114402Sru char field[30]; 3921114402Sru size_t len; 3922114402Sru 3923114402Sru /* Determine whether or not strict checking was requested */ 3924114402Sru len = os_strlcpy(field, _field, sizeof(field)); 3925114402Sru if (len >= sizeof(field)) 3926114402Sru return -1; 3927114402Sru strict = os_strchr(field, ' '); 3928114402Sru if (strict != NULL) { 3929114402Sru *strict++ = '\0'; 3930114402Sru if (os_strcmp(strict, "strict") != 0) 3931114402Sru return -1; 3932114402Sru } 3933114402Sru 3934114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s", 3935114402Sru field, strict ? strict : ""); 3936114402Sru 3937114402Sru if (os_strcmp(field, "eap") == 0) { 3938114402Sru return eap_get_names(buf, buflen); 3939114402Sru } 3940114402Sru 3941114402Sru res = wpa_drv_get_capa(wpa_s, &capa); 3942114402Sru 3943114402Sru if (os_strcmp(field, "pairwise") == 0) 3944114402Sru return ctrl_iface_get_capability_pairwise(res, strict, &capa, 3945114402Sru buf, buflen); 3946114402Sru 3947114402Sru if (os_strcmp(field, "group") == 0) 3948114402Sru return ctrl_iface_get_capability_group(res, strict, &capa, 3949114402Sru buf, buflen); 3950114402Sru 3951114402Sru if (os_strcmp(field, "group_mgmt") == 0) 3952114402Sru return ctrl_iface_get_capability_group_mgmt(res, strict, &capa, 3953114402Sru buf, buflen); 3954114402Sru 3955114402Sru if (os_strcmp(field, "key_mgmt") == 0) 3956114402Sru return ctrl_iface_get_capability_key_mgmt(res, strict, &capa, 3957114402Sru buf, buflen); 3958114402Sru 3959114402Sru if (os_strcmp(field, "proto") == 0) 3960114402Sru return ctrl_iface_get_capability_proto(res, strict, &capa, 3961114402Sru buf, buflen); 3962114402Sru 3963114402Sru if (os_strcmp(field, "auth_alg") == 0) 3964114402Sru return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict, 3965114402Sru &capa, buf, buflen); 3966114402Sru 3967114402Sru if (os_strcmp(field, "modes") == 0) 3968114402Sru return ctrl_iface_get_capability_modes(res, strict, &capa, 3969114402Sru buf, buflen); 3970114402Sru 3971114402Sru if (os_strcmp(field, "channels") == 0) 3972114402Sru return ctrl_iface_get_capability_channels(wpa_s, buf, buflen); 3973114402Sru 3974114402Sru if (os_strcmp(field, "freq") == 0) 3975114402Sru return ctrl_iface_get_capability_freq(wpa_s, buf, buflen); 3976114402Sru 3977114402Sru#ifdef CONFIG_TDLS 3978114402Sru if (os_strcmp(field, "tdls") == 0) 3979114402Sru return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen); 3980114402Sru#endif /* CONFIG_TDLS */ 3981114402Sru 3982114402Sru#ifdef CONFIG_ERP 3983114402Sru if (os_strcmp(field, "erp") == 0) { 3984114402Sru res = os_snprintf(buf, buflen, "ERP"); 3985114402Sru if (os_snprintf_error(buflen, res)) 3986114402Sru return -1; 3987114402Sru return res; 3988114402Sru } 3989114402Sru#endif /* CONFIG_EPR */ 3990114402Sru 3991114402Sru#ifdef CONFIG_FIPS 3992114402Sru if (os_strcmp(field, "fips") == 0) { 3993114402Sru res = os_snprintf(buf, buflen, "FIPS"); 3994114402Sru if (os_snprintf_error(buflen, res)) 3995114402Sru return -1; 3996114402Sru return res; 3997114402Sru } 3998114402Sru#endif /* CONFIG_FIPS */ 3999114402Sru 4000114402Sru#ifdef CONFIG_ACS 4001114402Sru if (os_strcmp(field, "acs") == 0) { 4002114402Sru res = os_snprintf(buf, buflen, "ACS"); 4003114402Sru if (os_snprintf_error(buflen, res)) 4004114402Sru return -1; 4005114402Sru return res; 4006114402Sru } 4007114402Sru#endif /* CONFIG_ACS */ 4008114402Sru 4009114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", 4010114402Sru field); 4011114402Sru 4012114402Sru return -1; 4013114402Sru} 4014114402Sru 4015114402Sru 4016114402Sru#ifdef CONFIG_INTERWORKING 4017114402Srustatic char * anqp_add_hex(char *pos, char *end, const char *title, 4018114402Sru struct wpabuf *data) 4019114402Sru{ 4020114402Sru char *start = pos; 4021114402Sru size_t i; 4022114402Sru int ret; 4023114402Sru const u8 *d; 4024114402Sru 4025114402Sru if (data == NULL) 4026114402Sru return start; 4027114402Sru 4028151497Sru ret = os_snprintf(pos, end - pos, "%s=", title); 4029151497Sru if (os_snprintf_error(end - pos, ret)) 4030151497Sru return start; 4031151497Sru pos += ret; 4032151497Sru 4033151497Sru d = wpabuf_head_u8(data); 4034151497Sru for (i = 0; i < wpabuf_len(data); i++) { 4035151497Sru ret = os_snprintf(pos, end - pos, "%02x", *d++); 4036151497Sru if (os_snprintf_error(end - pos, ret)) 4037151497Sru return start; 4038151497Sru pos += ret; 4039151497Sru } 4040151497Sru 4041151497Sru ret = os_snprintf(pos, end - pos, "\n"); 4042151497Sru if (os_snprintf_error(end - pos, ret)) 4043151497Sru return start; 4044151497Sru pos += ret; 4045114402Sru 4046114402Sru return pos; 4047114402Sru} 4048114402Sru#endif /* CONFIG_INTERWORKING */ 4049114402Sru 4050114402Sru 4051114402Srustatic int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 4052114402Sru unsigned long mask, char *buf, size_t buflen) 4053114402Sru{ 4054114402Sru size_t i; 4055114402Sru int ret; 4056114402Sru char *pos, *end; 4057114402Sru const u8 *ie, *ie2, *osen_ie; 4058114402Sru 4059114402Sru pos = buf; 4060114402Sru end = buf + buflen; 4061114402Sru 4062114402Sru if (mask & WPA_BSS_MASK_ID) { 4063114402Sru ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id); 4064114402Sru if (os_snprintf_error(end - pos, ret)) 4065114402Sru return 0; 4066114402Sru pos += ret; 4067114402Sru } 4068151497Sru 4069114402Sru if (mask & WPA_BSS_MASK_BSSID) { 4070114402Sru ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", 4071114402Sru MAC2STR(bss->bssid)); 4072114402Sru if (os_snprintf_error(end - pos, ret)) 4073114402Sru return 0; 4074114402Sru pos += ret; 4075114402Sru } 4076114402Sru 4077114402Sru if (mask & WPA_BSS_MASK_FREQ) { 4078114402Sru ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq); 4079114402Sru if (os_snprintf_error(end - pos, ret)) 4080114402Sru return 0; 4081114402Sru pos += ret; 4082114402Sru } 4083114402Sru 4084114402Sru if (mask & WPA_BSS_MASK_BEACON_INT) { 4085114402Sru ret = os_snprintf(pos, end - pos, "beacon_int=%d\n", 4086114402Sru bss->beacon_int); 4087114402Sru if (os_snprintf_error(end - pos, ret)) 4088114402Sru return 0; 4089114402Sru pos += ret; 4090114402Sru } 4091114402Sru 4092114402Sru if (mask & WPA_BSS_MASK_CAPABILITIES) { 4093114402Sru ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n", 4094114402Sru bss->caps); 4095114402Sru if (os_snprintf_error(end - pos, ret)) 4096114402Sru return 0; 4097114402Sru pos += ret; 4098114402Sru } 4099114402Sru 4100114402Sru if (mask & WPA_BSS_MASK_QUAL) { 4101114402Sru ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual); 4102114402Sru if (os_snprintf_error(end - pos, ret)) 4103114402Sru return 0; 4104114402Sru pos += ret; 4105114402Sru } 4106114402Sru 4107114402Sru if (mask & WPA_BSS_MASK_NOISE) { 4108114402Sru ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise); 4109114402Sru if (os_snprintf_error(end - pos, ret)) 4110114402Sru return 0; 4111114402Sru pos += ret; 4112114402Sru } 4113114402Sru 4114114402Sru if (mask & WPA_BSS_MASK_LEVEL) { 4115114402Sru ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level); 4116114402Sru if (os_snprintf_error(end - pos, ret)) 4117114402Sru return 0; 4118114402Sru pos += ret; 4119114402Sru } 4120114402Sru 4121114402Sru if (mask & WPA_BSS_MASK_TSF) { 4122114402Sru ret = os_snprintf(pos, end - pos, "tsf=%016llu\n", 4123114402Sru (unsigned long long) bss->tsf); 4124114402Sru if (os_snprintf_error(end - pos, ret)) 4125114402Sru return 0; 4126114402Sru pos += ret; 4127114402Sru } 4128114402Sru 4129114402Sru if (mask & WPA_BSS_MASK_AGE) { 4130114402Sru struct os_reltime now; 4131114402Sru 4132114402Sru os_get_reltime(&now); 4133114402Sru ret = os_snprintf(pos, end - pos, "age=%d\n", 4134114402Sru (int) (now.sec - bss->last_update.sec)); 4135114402Sru if (os_snprintf_error(end - pos, ret)) 4136114402Sru return 0; 4137114402Sru pos += ret; 4138114402Sru } 4139114402Sru 4140114402Sru if (mask & WPA_BSS_MASK_IE) { 4141114402Sru ret = os_snprintf(pos, end - pos, "ie="); 4142114402Sru if (os_snprintf_error(end - pos, ret)) 4143114402Sru return 0; 4144114402Sru pos += ret; 4145114402Sru 4146114402Sru ie = (const u8 *) (bss + 1); 4147114402Sru for (i = 0; i < bss->ie_len; i++) { 4148114402Sru ret = os_snprintf(pos, end - pos, "%02x", *ie++); 4149114402Sru if (os_snprintf_error(end - pos, ret)) 4150114402Sru return 0; 4151114402Sru pos += ret; 4152114402Sru } 4153114402Sru 4154114402Sru ret = os_snprintf(pos, end - pos, "\n"); 4155114402Sru if (os_snprintf_error(end - pos, ret)) 4156114402Sru return 0; 4157114402Sru pos += ret; 4158114402Sru } 4159114402Sru 4160114402Sru if (mask & WPA_BSS_MASK_FLAGS) { 4161114402Sru ret = os_snprintf(pos, end - pos, "flags="); 4162114402Sru if (os_snprintf_error(end - pos, ret)) 4163114402Sru return 0; 4164114402Sru pos += ret; 4165114402Sru 4166114402Sru ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 4167114402Sru if (ie) 4168114402Sru pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 4169114402Sru 2 + ie[1]); 4170114402Sru ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); 4171114402Sru if (ie2) 4172114402Sru pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 4173114402Sru 2 + ie2[1]); 4174114402Sru osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); 4175114402Sru if (osen_ie) 4176114402Sru pos = wpa_supplicant_ie_txt(pos, end, "OSEN", 4177114402Sru osen_ie, 2 + osen_ie[1]); 4178114402Sru pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); 4179151497Sru if (!ie && !ie2 && !osen_ie && 4180151497Sru (bss->caps & IEEE80211_CAP_PRIVACY)) { 4181151497Sru ret = os_snprintf(pos, end - pos, "[WEP]"); 4182151497Sru if (os_snprintf_error(end - pos, ret)) 4183114402Sru return 0; 4184151497Sru pos += ret; 4185151497Sru } 4186151497Sru if (bss_is_dmg(bss)) { 4187151497Sru const char *s; 4188151497Sru ret = os_snprintf(pos, end - pos, "[DMG]"); 4189151497Sru if (os_snprintf_error(end - pos, ret)) 4190151497Sru return 0; 4191151497Sru pos += ret; 4192151497Sru switch (bss->caps & IEEE80211_CAP_DMG_MASK) { 4193151497Sru case IEEE80211_CAP_DMG_IBSS: 4194151497Sru s = "[IBSS]"; 4195151497Sru break; 4196151497Sru case IEEE80211_CAP_DMG_AP: 4197114402Sru s = "[ESS]"; 4198114402Sru break; 4199114402Sru case IEEE80211_CAP_DMG_PBSS: 4200114402Sru s = "[PBSS]"; 4201114402Sru break; 4202114402Sru default: 4203114402Sru s = ""; 4204114402Sru break; 4205114402Sru } 4206114402Sru ret = os_snprintf(pos, end - pos, "%s", s); 4207114402Sru if (os_snprintf_error(end - pos, ret)) 4208114402Sru return 0; 4209114402Sru pos += ret; 4210114402Sru } else { 4211114402Sru if (bss->caps & IEEE80211_CAP_IBSS) { 4212114402Sru ret = os_snprintf(pos, end - pos, "[IBSS]"); 4213114402Sru if (os_snprintf_error(end - pos, ret)) 4214114402Sru return 0; 4215114402Sru pos += ret; 4216114402Sru } 4217114402Sru if (bss->caps & IEEE80211_CAP_ESS) { 4218114402Sru ret = os_snprintf(pos, end - pos, "[ESS]"); 4219114402Sru if (os_snprintf_error(end - pos, ret)) 4220114402Sru return 0; 4221114402Sru pos += ret; 4222114402Sru } 4223114402Sru } 4224114402Sru if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || 4225114402Sru wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { 4226114402Sru ret = os_snprintf(pos, end - pos, "[P2P]"); 4227114402Sru if (os_snprintf_error(end - pos, ret)) 4228114402Sru return 0; 4229114402Sru pos += ret; 4230114402Sru } 4231151497Sru#ifdef CONFIG_HS20 4232114402Sru if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { 4233114402Sru ret = os_snprintf(pos, end - pos, "[HS20]"); 4234114402Sru if (os_snprintf_error(end - pos, ret)) 4235114402Sru return 0; 4236114402Sru pos += ret; 4237151497Sru } 4238114402Sru#endif /* CONFIG_HS20 */ 4239114402Sru 4240151497Sru ret = os_snprintf(pos, end - pos, "\n"); 4241151497Sru if (os_snprintf_error(end - pos, ret)) 4242114402Sru return 0; 4243114402Sru pos += ret; 4244114402Sru } 4245114402Sru 4246114402Sru if (mask & WPA_BSS_MASK_SSID) { 4247114402Sru ret = os_snprintf(pos, end - pos, "ssid=%s\n", 4248114402Sru wpa_ssid_txt(bss->ssid, bss->ssid_len)); 4249114402Sru if (os_snprintf_error(end - pos, ret)) 4250114402Sru return 0; 4251114402Sru pos += ret; 4252114402Sru } 4253114402Sru 4254114402Sru#ifdef CONFIG_WPS 4255114402Sru if (mask & WPA_BSS_MASK_WPS_SCAN) { 4256114402Sru ie = (const u8 *) (bss + 1); 4257151497Sru ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end); 4258114402Sru if (ret >= end - pos) 4259114402Sru return 0; 4260114402Sru if (ret > 0) 4261114402Sru pos += ret; 4262114402Sru } 4263114402Sru#endif /* CONFIG_WPS */ 4264114402Sru 4265114402Sru#ifdef CONFIG_P2P 4266114402Sru if (mask & WPA_BSS_MASK_P2P_SCAN) { 4267151497Sru ie = (const u8 *) (bss + 1); 4268114402Sru ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); 4269114402Sru if (ret >= end - pos) 4270114402Sru return 0; 4271114402Sru if (ret > 0) 4272114402Sru pos += ret; 4273114402Sru } 4274114402Sru#endif /* CONFIG_P2P */ 4275114402Sru 4276114402Sru#ifdef CONFIG_WIFI_DISPLAY 4277114402Sru if (mask & WPA_BSS_MASK_WIFI_DISPLAY) { 4278114402Sru struct wpabuf *wfd; 4279151497Sru ie = (const u8 *) (bss + 1); 4280114402Sru wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len, 4281114402Sru WFD_IE_VENDOR_TYPE); 4282114402Sru if (wfd) { 4283114402Sru ret = os_snprintf(pos, end - pos, "wfd_subelems="); 4284114402Sru if (os_snprintf_error(end - pos, ret)) { 4285114402Sru wpabuf_free(wfd); 4286114402Sru return 0; 4287114402Sru } 4288114402Sru pos += ret; 4289114402Sru 4290114402Sru pos += wpa_snprintf_hex(pos, end - pos, 4291114402Sru wpabuf_head(wfd), 4292114402Sru wpabuf_len(wfd)); 4293114402Sru wpabuf_free(wfd); 4294114402Sru 4295114402Sru ret = os_snprintf(pos, end - pos, "\n"); 4296151497Sru if (os_snprintf_error(end - pos, ret)) 4297114402Sru return 0; 4298114402Sru pos += ret; 4299114402Sru } 4300114402Sru } 4301151497Sru#endif /* CONFIG_WIFI_DISPLAY */ 4302151497Sru 4303114402Sru#ifdef CONFIG_INTERWORKING 4304114402Sru if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { 4305114402Sru struct wpa_bss_anqp *anqp = bss->anqp; 4306151497Sru struct wpa_bss_anqp_elem *elem; 4307151497Sru 4308114402Sru pos = anqp_add_hex(pos, end, "anqp_capability_list", 4309114402Sru anqp->capability_list); 4310114402Sru pos = anqp_add_hex(pos, end, "anqp_venue_name", 4311114402Sru anqp->venue_name); 4312114402Sru pos = anqp_add_hex(pos, end, "anqp_network_auth_type", 4313114402Sru anqp->network_auth_type); 4314114402Sru pos = anqp_add_hex(pos, end, "anqp_roaming_consortium", 4315114402Sru anqp->roaming_consortium); 4316114402Sru pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability", 4317114402Sru anqp->ip_addr_type_availability); 4318114402Sru pos = anqp_add_hex(pos, end, "anqp_nai_realm", 4319114402Sru anqp->nai_realm); 4320151497Sru pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp); 4321114402Sru pos = anqp_add_hex(pos, end, "anqp_domain_name", 4322114402Sru anqp->domain_name); 4323114402Sru#ifdef CONFIG_HS20 4324114402Sru pos = anqp_add_hex(pos, end, "hs20_capability_list", 4325114402Sru anqp->hs20_capability_list); 4326114402Sru pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name", 4327114402Sru anqp->hs20_operator_friendly_name); 4328114402Sru pos = anqp_add_hex(pos, end, "hs20_wan_metrics", 4329114402Sru anqp->hs20_wan_metrics); 4330151497Sru pos = anqp_add_hex(pos, end, "hs20_connection_capability", 4331114402Sru anqp->hs20_connection_capability); 4332114402Sru pos = anqp_add_hex(pos, end, "hs20_operating_class", 4333114402Sru anqp->hs20_operating_class); 4334114402Sru pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", 4335114402Sru anqp->hs20_osu_providers_list); 4336114402Sru#endif /* CONFIG_HS20 */ 4337114402Sru 4338114402Sru dl_list_for_each(elem, &anqp->anqp_elems, 4339151497Sru struct wpa_bss_anqp_elem, list) { 4340114402Sru char title[20]; 4341114402Sru 4342114402Sru os_snprintf(title, sizeof(title), "anqp[%u]", 4343114402Sru elem->infoid); 4344114402Sru pos = anqp_add_hex(pos, end, title, elem->payload); 4345114402Sru } 4346114402Sru } 4347114402Sru#endif /* CONFIG_INTERWORKING */ 4348151497Sru 4349151497Sru#ifdef CONFIG_MESH 4350151497Sru if (mask & WPA_BSS_MASK_MESH_SCAN) { 4351114402Sru ie = (const u8 *) (bss + 1); 4352114402Sru ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end); 4353151497Sru if (ret >= end - pos) 4354151497Sru return 0; 4355114402Sru if (ret > 0) 4356114402Sru pos += ret; 4357114402Sru } 4358114402Sru#endif /* CONFIG_MESH */ 4359114402Sru 4360114402Sru if (mask & WPA_BSS_MASK_SNR) { 4361114402Sru ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr); 4362114402Sru if (os_snprintf_error(end - pos, ret)) 4363114402Sru return 0; 4364114402Sru pos += ret; 4365114402Sru } 4366114402Sru 4367114402Sru if (mask & WPA_BSS_MASK_EST_THROUGHPUT) { 4368151497Sru ret = os_snprintf(pos, end - pos, "est_throughput=%d\n", 4369151497Sru bss->est_throughput); 4370114402Sru if (os_snprintf_error(end - pos, ret)) 4371114402Sru return 0; 4372114402Sru pos += ret; 4373114402Sru } 4374114402Sru 4375114402Sru#ifdef CONFIG_FST 4376114402Sru if (mask & WPA_BSS_MASK_FST) { 4377114402Sru ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos); 4378114402Sru if (ret < 0 || ret >= end - pos) 4379114402Sru return 0; 4380114402Sru pos += ret; 4381114402Sru } 4382114402Sru#endif /* CONFIG_FST */ 4383114402Sru 4384114402Sru if (mask & WPA_BSS_MASK_DELIM) { 4385114402Sru ret = os_snprintf(pos, end - pos, "====\n"); 4386114402Sru if (os_snprintf_error(end - pos, ret)) 4387114402Sru return 0; 4388114402Sru pos += ret; 4389114402Sru } 4390114402Sru 4391114402Sru return pos - buf; 4392114402Sru} 4393114402Sru 4394114402Sru 4395114402Srustatic int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, 4396114402Sru const char *cmd, char *buf, 4397114402Sru size_t buflen) 4398114402Sru{ 4399114402Sru u8 bssid[ETH_ALEN]; 4400114402Sru size_t i; 4401114402Sru struct wpa_bss *bss; 4402114402Sru struct wpa_bss *bsslast = NULL; 4403114402Sru struct dl_list *next; 4404114402Sru int ret = 0; 4405114402Sru int len; 4406114402Sru char *ctmp, *end = buf + buflen; 4407114402Sru unsigned long mask = WPA_BSS_MASK_ALL; 4408114402Sru 4409114402Sru if (os_strncmp(cmd, "RANGE=", 6) == 0) { 4410114402Sru if (os_strncmp(cmd + 6, "ALL", 3) == 0) { 4411114402Sru bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, 4412114402Sru list_id); 4413114402Sru bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss, 4414114402Sru list_id); 4415151497Sru } else { /* N1-N2 */ 4416114402Sru unsigned int id1, id2; 4417114402Sru 4418114402Sru if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) { 4419114402Sru wpa_printf(MSG_INFO, "Wrong BSS range " 4420114402Sru "format"); 4421151497Sru return 0; 4422151497Sru } 4423151497Sru 4424151497Sru if (*(cmd + 6) == '-') 4425151497Sru id1 = 0; 4426151497Sru else 4427151497Sru id1 = atoi(cmd + 6); 4428151497Sru ctmp++; 4429151497Sru if (*ctmp >= '0' && *ctmp <= '9') 4430151497Sru id2 = atoi(ctmp); 4431151497Sru else 4432151497Sru id2 = (unsigned int) -1; 4433151497Sru bss = wpa_bss_get_id_range(wpa_s, id1, id2); 4434151497Sru if (id2 == (unsigned int) -1) 4435151497Sru bsslast = dl_list_last(&wpa_s->bss_id, 4436151497Sru struct wpa_bss, 4437151497Sru list_id); 4438151497Sru else { 4439151497Sru bsslast = wpa_bss_get_id(wpa_s, id2); 4440151497Sru if (bsslast == NULL && bss && id2 > id1) { 4441151497Sru struct wpa_bss *tmp = bss; 4442151497Sru for (;;) { 4443151497Sru next = tmp->list_id.next; 4444151497Sru if (next == &wpa_s->bss_id) 4445151497Sru break; 4446151497Sru tmp = dl_list_entry( 4447151497Sru next, struct wpa_bss, 4448151497Sru list_id); 4449151497Sru if (tmp->id > id2) 4450151497Sru break; 4451151497Sru bsslast = tmp; 4452151497Sru } 4453114402Sru } 4454114402Sru } 4455114402Sru } 4456114402Sru } else if (os_strncmp(cmd, "FIRST", 5) == 0) 4457114402Sru bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id); 4458114402Sru else if (os_strncmp(cmd, "LAST", 4) == 0) 4459114402Sru bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id); 4460114402Sru else if (os_strncmp(cmd, "ID-", 3) == 0) { 4461114402Sru i = atoi(cmd + 3); 4462114402Sru bss = wpa_bss_get_id(wpa_s, i); 4463114402Sru } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { 4464114402Sru i = atoi(cmd + 5); 4465114402Sru bss = wpa_bss_get_id(wpa_s, i); 4466114402Sru if (bss) { 4467114402Sru next = bss->list_id.next; 4468114402Sru if (next == &wpa_s->bss_id) 4469114402Sru bss = NULL; 4470114402Sru else 4471114402Sru bss = dl_list_entry(next, struct wpa_bss, 4472114402Sru list_id); 4473114402Sru } 4474114402Sru#ifdef CONFIG_P2P 4475114402Sru } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { 4476114402Sru if (hwaddr_aton(cmd + 13, bssid) == 0) 4477114402Sru bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid); 4478114402Sru else 4479114402Sru bss = NULL; 4480114402Sru#endif /* CONFIG_P2P */ 4481114402Sru } else if (hwaddr_aton(cmd, bssid) == 0) 4482114402Sru bss = wpa_bss_get_bssid(wpa_s, bssid); 4483114402Sru else { 4484114402Sru struct wpa_bss *tmp; 4485114402Sru i = atoi(cmd); 4486114402Sru bss = NULL; 4487114402Sru dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id) 4488114402Sru { 4489114402Sru if (i-- == 0) { 4490114402Sru bss = tmp; 4491114402Sru break; 4492114402Sru } 4493114402Sru } 4494114402Sru } 4495114402Sru 4496114402Sru if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) { 4497114402Sru mask = strtoul(ctmp + 5, NULL, 0x10); 4498114402Sru if (mask == 0) 4499114402Sru mask = WPA_BSS_MASK_ALL; 4500114402Sru } 4501114402Sru 4502114402Sru if (bss == NULL) 4503114402Sru return 0; 4504114402Sru 4505151497Sru if (bsslast == NULL) 4506151497Sru bsslast = bss; 4507114402Sru do { 4508114402Sru len = print_bss_info(wpa_s, bss, mask, buf, buflen); 4509114402Sru ret += len; 4510114402Sru buf += len; 4511114402Sru buflen -= len; 4512114402Sru if (bss == bsslast) { 4513114402Sru if ((mask & WPA_BSS_MASK_DELIM) && len && 4514114402Sru (bss == dl_list_last(&wpa_s->bss_id, 4515114402Sru struct wpa_bss, list_id))) { 4516114402Sru int res; 4517114402Sru 4518114402Sru res = os_snprintf(buf - 5, end - buf + 5, 4519114402Sru "####\n"); 4520114402Sru if (os_snprintf_error(end - buf + 5, res)) { 4521114402Sru wpa_printf(MSG_DEBUG, 4522114402Sru "Could not add end delim"); 4523114402Sru } 4524114402Sru } 4525114402Sru break; 4526114402Sru } 4527114402Sru next = bss->list_id.next; 4528114402Sru if (next == &wpa_s->bss_id) 4529114402Sru break; 4530114402Sru bss = dl_list_entry(next, struct wpa_bss, list_id); 4531114402Sru } while (bss && len); 4532114402Sru 4533114402Sru return ret; 4534114402Sru} 4535114402Sru 4536114402Sru 4537114402Srustatic int wpa_supplicant_ctrl_iface_ap_scan( 4538151497Sru struct wpa_supplicant *wpa_s, char *cmd) 4539151497Sru{ 4540151497Sru int ap_scan = atoi(cmd); 4541151497Sru return wpa_supplicant_set_ap_scan(wpa_s, ap_scan); 4542151497Sru} 4543151497Sru 4544151497Sru 4545151497Srustatic int wpa_supplicant_ctrl_iface_scan_interval( 4546151497Sru struct wpa_supplicant *wpa_s, char *cmd) 4547151497Sru{ 4548151497Sru int scan_int = atoi(cmd); 4549151497Sru return wpa_supplicant_set_scan_interval(wpa_s, scan_int); 4550151497Sru} 4551151497Sru 4552151497Sru 4553151497Srustatic int wpa_supplicant_ctrl_iface_bss_expire_age( 4554151497Sru struct wpa_supplicant *wpa_s, char *cmd) 4555151497Sru{ 4556151497Sru int expire_age = atoi(cmd); 4557151497Sru return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age); 4558151497Sru} 4559151497Sru 4560151497Sru 4561151497Srustatic int wpa_supplicant_ctrl_iface_bss_expire_count( 4562151497Sru struct wpa_supplicant *wpa_s, char *cmd) 4563151497Sru{ 4564151497Sru int expire_count = atoi(cmd); 4565151497Sru return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count); 4566151497Sru} 4567151497Sru 4568151497Sru 4569151497Srustatic void wpa_supplicant_ctrl_iface_bss_flush( 4570151497Sru struct wpa_supplicant *wpa_s, char *cmd) 4571151497Sru{ 4572151497Sru int flush_age = atoi(cmd); 4573151497Sru 4574151497Sru if (flush_age == 0) 4575151497Sru wpa_bss_flush(wpa_s); 4576151497Sru else 4577151497Sru wpa_bss_flush_by_age(wpa_s, flush_age); 4578151497Sru} 4579151497Sru 4580151497Sru 4581151497Sru#ifdef CONFIG_TESTING_OPTIONS 4582151497Srustatic void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) 4583151497Sru{ 4584151497Sru wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); 4585151497Sru /* MLME-DELETEKEYS.request */ 4586151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); 4587151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); 4588151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); 4589151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); 4590151497Sru#ifdef CONFIG_IEEE80211W 4591151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); 4592151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); 4593151497Sru#endif /* CONFIG_IEEE80211W */ 4594151497Sru 4595151497Sru wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, 4596151497Sru 0); 4597151497Sru /* MLME-SETPROTECTION.request(None) */ 4598151497Sru wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, 4599151497Sru MLME_SETPROTECTION_PROTECT_TYPE_NONE, 4600151497Sru MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); 4601151497Sru wpa_sm_drop_sa(wpa_s->wpa); 4602151497Sru} 4603151497Sru#endif /* CONFIG_TESTING_OPTIONS */ 4604151497Sru 4605151497Sru 4606151497Srustatic int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s, 4607151497Sru char *addr) 4608151497Sru{ 4609151497Sru#ifdef CONFIG_NO_SCAN_PROCESSING 4610151497Sru return -1; 4611151497Sru#else /* CONFIG_NO_SCAN_PROCESSING */ 4612151497Sru u8 bssid[ETH_ALEN]; 4613151497Sru struct wpa_bss *bss; 4614151497Sru struct wpa_ssid *ssid = wpa_s->current_ssid; 4615151497Sru 4616151497Sru if (hwaddr_aton(addr, bssid)) { 4617151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid " 4618151497Sru "address '%s'", addr); 4619151497Sru return -1; 4620151497Sru } 4621151497Sru 4622151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid)); 4623151497Sru 4624151497Sru if (!ssid) { 4625151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network " 4626151497Sru "configuration known for the target AP"); 4627151497Sru return -1; 4628151497Sru } 4629151497Sru 4630151497Sru bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); 4631151497Sru if (!bss) { 4632151497Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found " 4633151497Sru "from BSS table"); 4634151497Sru return -1; 4635151497Sru } 4636151497Sru 4637151497Sru /* 4638151497Sru * TODO: Find best network configuration block from configuration to 4639151497Sru * allow roaming to other networks 4640151497Sru */ 4641151497Sru 4642151497Sru wpa_s->reassociate = 1; 4643151497Sru wpa_supplicant_connect(wpa_s, bss, ssid); 4644151497Sru 4645151497Sru return 0; 4646151497Sru#endif /* CONFIG_NO_SCAN_PROCESSING */ 4647151497Sru} 4648151497Sru 4649151497Sru 4650151497Sru#ifdef CONFIG_P2P 4651151497Srustatic int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) 4652151497Sru{ 4653151497Sru unsigned int timeout = atoi(cmd); 4654151497Sru enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; 4655151497Sru u8 dev_id[ETH_ALEN], *_dev_id = NULL; 4656151497Sru u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL; 4657151497Sru char *pos; 4658151497Sru unsigned int search_delay; 4659151497Sru const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL; 4660151497Sru u8 seek_count = 0; 4661151497Sru int freq = 0; 4662151497Sru 4663151497Sru if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 4664151497Sru wpa_dbg(wpa_s, MSG_INFO, 4665114402Sru "Reject P2P_FIND since interface is disabled"); 4666114402Sru return -1; 4667114402Sru } 4668114402Sru if (os_strstr(cmd, "type=social")) 4669114402Sru type = P2P_FIND_ONLY_SOCIAL; 4670114402Sru else if (os_strstr(cmd, "type=progressive")) 4671114402Sru type = P2P_FIND_PROGRESSIVE; 4672114402Sru 4673114402Sru pos = os_strstr(cmd, "dev_id="); 4674114402Sru if (pos) { 4675114402Sru pos += 7; 4676114402Sru if (hwaddr_aton(pos, dev_id)) 4677114402Sru return -1; 4678114402Sru _dev_id = dev_id; 4679114402Sru } 4680114402Sru 4681114402Sru pos = os_strstr(cmd, "dev_type="); 4682114402Sru if (pos) { 4683114402Sru pos += 9; 4684114402Sru if (wps_dev_type_str2bin(pos, dev_type) < 0) 4685114402Sru return -1; 4686114402Sru _dev_type = dev_type; 4687151497Sru } 4688114402Sru 4689114402Sru pos = os_strstr(cmd, "delay="); 4690151497Sru if (pos) { 4691151497Sru pos += 6; 4692114402Sru search_delay = atoi(pos); 4693114402Sru } else 4694114402Sru search_delay = wpas_p2p_search_delay(wpa_s); 4695114402Sru 4696114402Sru pos = os_strstr(cmd, "freq="); 4697114402Sru if (pos) { 4698114402Sru pos += 5; 4699114402Sru freq = atoi(pos); 4700114402Sru if (freq <= 0) 4701114402Sru return -1; 4702114402Sru } 4703151497Sru 4704151497Sru /* Must be searched for last, because it adds nul termination */ 4705151497Sru pos = os_strstr(cmd, " seek="); 4706151497Sru if (pos) 4707151497Sru pos += 6; 4708151497Sru while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) { 4709151497Sru char *term; 4710151497Sru 4711151497Sru _seek[seek_count++] = pos; 4712114402Sru seek = _seek; 4713114402Sru term = os_strchr(pos, ' '); 4714114402Sru if (!term) 4715114402Sru break; 4716151497Sru *term = '\0'; 4717151497Sru pos = os_strstr(term + 1, "seek="); 4718114402Sru if (pos) 4719114402Sru pos += 5; 4720151497Sru } 4721151497Sru if (seek_count > P2P_MAX_QUERY_HASH) { 4722151497Sru seek[0] = NULL; 4723151497Sru seek_count = 1; 4724151497Sru } 4725151497Sru 4726151497Sru return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type, 4727151497Sru _dev_id, search_delay, seek_count, seek, freq); 4728151497Sru} 4729151497Sru 4730151497Sru 4731151497Srustatic int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt) 4732151497Sru{ 4733151497Sru const char *last = NULL; 4734151497Sru const char *token; 4735151497Sru long int token_len; 4736151497Sru unsigned int i; 4737151497Sru 4738151497Sru /* Expected predefined CPT names delimited by ':' */ 4739151497Sru for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) { 4740151497Sru if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) { 4741151497Sru wpa_printf(MSG_ERROR, 4742151497Sru "P2PS: CPT name list is too long, expected up to %d names", 4743151497Sru P2PS_FEATURE_CAPAB_CPT_MAX); 4744151497Sru cpt[0] = 0; 4745151497Sru return -1; 4746151497Sru } 4747151497Sru 4748151497Sru token_len = last - token; 4749151497Sru 4750151497Sru if (token_len == 3 && 4751151497Sru os_memcmp(token, "UDP", token_len) == 0) { 4752151497Sru cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 4753151497Sru } else if (token_len == 3 && 4754151497Sru os_memcmp(token, "MAC", token_len) == 0) { 4755151497Sru cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT; 4756151497Sru } else { 4757151497Sru wpa_printf(MSG_ERROR, 4758151497Sru "P2PS: Unsupported CPT name '%s'", token); 4759151497Sru cpt[0] = 0; 4760151497Sru return -1; 4761151497Sru } 4762151497Sru 4763151497Sru if (isblank((unsigned char) *last)) { 4764151497Sru i++; 4765151497Sru break; 4766151497Sru } 4767151497Sru } 4768151497Sru cpt[i] = 0; 4769151497Sru return 0; 4770151497Sru} 4771151497Sru 4772151497Sru 4773151497Srustatic struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd) 4774151497Sru{ 4775151497Sru struct p2ps_provision *p2ps_prov; 4776151497Sru char *pos; 4777151497Sru size_t info_len = 0; 4778151497Sru char *info = NULL; 4779151497Sru u8 role = P2PS_SETUP_NONE; 4780151497Sru long long unsigned val; 4781151497Sru int i; 4782151497Sru 4783151497Sru pos = os_strstr(cmd, "info="); 4784151497Sru if (pos) { 4785151497Sru pos += 5; 4786151497Sru info_len = os_strlen(pos); 4787151497Sru 4788151497Sru if (info_len) { 4789151497Sru info = os_malloc(info_len + 1); 4790151497Sru if (info) { 4791151497Sru info_len = utf8_unescape(pos, info_len, 4792151497Sru info, info_len + 1); 4793151497Sru } else 4794151497Sru info_len = 0; 4795151497Sru } 4796151497Sru } 4797151497Sru 4798151497Sru p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1); 4799151497Sru if (p2ps_prov == NULL) { 4800151497Sru os_free(info); 4801151497Sru return NULL; 4802151497Sru } 4803151497Sru 4804151497Sru if (info) { 4805151497Sru os_memcpy(p2ps_prov->info, info, info_len); 4806151497Sru p2ps_prov->info[info_len] = '\0'; 4807151497Sru os_free(info); 4808151497Sru } 4809151497Sru 4810151497Sru pos = os_strstr(cmd, "status="); 4811151497Sru if (pos) 4812151497Sru p2ps_prov->status = atoi(pos + 7); 4813151497Sru else 4814151497Sru p2ps_prov->status = -1; 4815151497Sru 4816151497Sru pos = os_strstr(cmd, "adv_id="); 4817151497Sru if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL) 4818151497Sru goto invalid_args; 4819151497Sru p2ps_prov->adv_id = val; 4820151497Sru 4821151497Sru pos = os_strstr(cmd, "method="); 4822151497Sru if (pos) 4823151497Sru p2ps_prov->method = strtol(pos + 7, NULL, 16); 4824151497Sru else 4825151497Sru p2ps_prov->method = 0; 4826151497Sru 4827151497Sru pos = os_strstr(cmd, "session="); 4828151497Sru if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL) 4829151497Sru goto invalid_args; 4830114402Sru p2ps_prov->session_id = val; 4831114402Sru 4832114402Sru pos = os_strstr(cmd, "adv_mac="); 4833114402Sru if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac)) 4834114402Sru goto invalid_args; 4835114402Sru 4836114402Sru pos = os_strstr(cmd, "session_mac="); 4837114402Sru if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac)) 4838114402Sru goto invalid_args; 4839114402Sru 4840114402Sru pos = os_strstr(cmd, "cpt="); 4841114402Sru if (pos) { 4842114402Sru if (p2ps_ctrl_parse_cpt_priority(pos + 4, 4843114402Sru p2ps_prov->cpt_priority)) 4844114402Sru goto invalid_args; 4845114402Sru } else { 4846114402Sru p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 4847114402Sru } 4848114402Sru 4849114402Sru for (i = 0; p2ps_prov->cpt_priority[i]; i++) 4850114402Sru p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i]; 4851114402Sru 4852114402Sru /* force conncap with tstCap (no sanity checks) */ 4853114402Sru pos = os_strstr(cmd, "tstCap="); 4854114402Sru if (pos) { 4855114402Sru role = strtol(pos + 7, NULL, 16); 4856114402Sru } else { 4857114402Sru pos = os_strstr(cmd, "role="); 4858151497Sru if (pos) { 4859151497Sru role = strtol(pos + 5, NULL, 16); 4860114402Sru if (role != P2PS_SETUP_CLIENT && 4861114402Sru role != P2PS_SETUP_GROUP_OWNER) 4862151497Sru role = P2PS_SETUP_NONE; 4863151497Sru } 4864151497Sru } 4865151497Sru p2ps_prov->role = role; 4866114402Sru 4867151497Sru return p2ps_prov; 4868151497Sru 4869151497Sruinvalid_args: 4870151497Sru os_free(p2ps_prov); 4871151497Sru return NULL; 4872151497Sru} 4873151497Sru 4874151497Sru 4875151497Srustatic int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd) 4876151497Sru{ 4877151497Sru u8 addr[ETH_ALEN]; 4878151497Sru struct p2ps_provision *p2ps_prov; 4879151497Sru char *pos; 4880151497Sru 4881151497Sru /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */ 4882151497Sru 4883151497Sru wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); 4884151497Sru 4885151497Sru if (hwaddr_aton(cmd, addr)) 4886151497Sru return -1; 4887151497Sru 4888151497Sru pos = cmd + 17; 4889151497Sru if (*pos != ' ') 4890151497Sru return -1; 4891151497Sru 4892114402Sru p2ps_prov = p2p_parse_asp_provision_cmd(pos); 4893114402Sru if (!p2ps_prov) 4894151497Sru return -1; 4895114402Sru 4896114402Sru if (p2ps_prov->status < 0) { 4897151497Sru os_free(p2ps_prov); 4898151497Sru return -1; 4899151497Sru } 4900151497Sru 4901151497Sru return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, 4902151497Sru p2ps_prov); 4903151497Sru} 4904151497Sru 4905151497Sru 4906151497Srustatic int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd) 4907151497Sru{ 4908151497Sru u8 addr[ETH_ALEN]; 4909151497Sru struct p2ps_provision *p2ps_prov; 4910151497Sru char *pos; 4911151497Sru 4912151497Sru /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap> 4913151497Sru * session=<ses_id> mac=<ses_mac> [info=<infodata>] 4914151497Sru */ 4915151497Sru 4916151497Sru wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd); 4917151497Sru if (hwaddr_aton(cmd, addr)) 4918151497Sru return -1; 4919151497Sru 4920151497Sru pos = cmd + 17; 4921151497Sru if (*pos != ' ') 4922151497Sru return -1; 4923151497Sru 4924151497Sru p2ps_prov = p2p_parse_asp_provision_cmd(pos); 4925151497Sru if (!p2ps_prov) 4926151497Sru return -1; 4927114402Sru 4928114402Sru p2ps_prov->pd_seeker = 1; 4929114402Sru 4930114402Sru return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP, 4931114402Sru p2ps_prov); 4932114402Sru} 4933114402Sru 4934114402Sru 4935151497Srustatic int parse_freq(int chwidth, int freq2) 4936151497Sru{ 4937151497Sru if (freq2 < 0) 4938151497Sru return -1; 4939151497Sru if (freq2) 4940151497Sru return VHT_CHANWIDTH_80P80MHZ; 4941151497Sru 4942151497Sru switch (chwidth) { 4943151497Sru case 0: 4944151497Sru case 20: 4945151497Sru case 40: 4946151497Sru return VHT_CHANWIDTH_USE_HT; 4947151497Sru case 80: 4948151497Sru return VHT_CHANWIDTH_80MHZ; 4949151497Sru case 160: 4950151497Sru return VHT_CHANWIDTH_160MHZ; 4951151497Sru default: 4952151497Sru wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", 4953151497Sru chwidth); 4954151497Sru return -1; 4955114402Sru } 4956114402Sru} 4957114402Sru 4958114402Sru 4959114402Srustatic int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, 4960114402Sru char *buf, size_t buflen) 4961114402Sru{ 4962114402Sru u8 addr[ETH_ALEN]; 4963114402Sru char *pos, *pos2; 4964114402Sru char *pin = NULL; 4965114402Sru enum p2p_wps_method wps_method; 4966151497Sru int new_pin; 4967151497Sru int ret; 4968114402Sru int persistent_group, persistent_id = -1; 4969114402Sru int join; 4970114402Sru int auth; 4971114402Sru int automatic; 4972114402Sru int go_intent = -1; 4973114402Sru int freq = 0; 4974114402Sru int pd; 4975114402Sru int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; 4976114402Sru u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL; 4977114402Sru size_t group_ssid_len = 0; 4978151497Sru 4979151497Sru if (!wpa_s->global->p2p_init_wpa_s) 4980151497Sru return -1; 4981151497Sru if (wpa_s->global->p2p_init_wpa_s != wpa_s) { 4982151497Sru wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s", 4983151497Sru wpa_s->global->p2p_init_wpa_s->ifname); 4984114402Sru wpa_s = wpa_s->global->p2p_init_wpa_s; 4985114402Sru } 4986114402Sru 4987151497Sru /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] 4988151497Sru * [persistent|persistent=<network id>] 4989114402Sru * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] 4990114402Sru * [ht40] [vht] [auto] [ssid=<hexdump>] */ 4991114402Sru 4992114402Sru if (hwaddr_aton(cmd, addr)) 4993114402Sru return -1; 4994114402Sru 4995114402Sru pos = cmd + 17; 4996114402Sru if (*pos != ' ') 4997114402Sru return -1; 4998114402Sru pos++; 4999114402Sru 5000151497Sru persistent_group = os_strstr(pos, " persistent") != NULL; 5001151497Sru pos2 = os_strstr(pos, " persistent="); 5002151497Sru if (pos2) { 5003114402Sru struct wpa_ssid *ssid; 5004151497Sru persistent_id = atoi(pos2 + 12); 5005151497Sru ssid = wpa_config_get_network(wpa_s->conf, persistent_id); 5006151497Sru if (ssid == NULL || ssid->disabled != 2 || 5007114402Sru ssid->mode != WPAS_MODE_P2P_GO) { 5008114402Sru wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " 5009114402Sru "SSID id=%d for persistent P2P group (GO)", 5010151497Sru persistent_id); 5011151497Sru return -1; 5012151497Sru } 5013151497Sru } 5014151497Sru join = os_strstr(pos, " join") != NULL; 5015151497Sru auth = os_strstr(pos, " auth") != NULL; 5016151497Sru automatic = os_strstr(pos, " auto") != NULL; 5017151497Sru pd = os_strstr(pos, " provdisc") != NULL; 5018151497Sru vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; 5019151497Sru ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || 5020151497Sru vht; 5021151497Sru 5022151497Sru pos2 = os_strstr(pos, " go_intent="); 5023151497Sru if (pos2) { 5024151497Sru pos2 += 11; 5025151497Sru go_intent = atoi(pos2); 5026151497Sru if (go_intent < 0 || go_intent > 15) 5027151497Sru return -1; 5028151497Sru } 5029114402Sru 5030114402Sru pos2 = os_strstr(pos, " freq="); 5031114402Sru if (pos2) { 5032114402Sru pos2 += 6; 5033114402Sru freq = atoi(pos2); 5034114402Sru if (freq <= 0) 5035114402Sru return -1; 5036114402Sru } 5037114402Sru 5038114402Sru pos2 = os_strstr(pos, " freq2="); 5039114402Sru if (pos2) 5040114402Sru freq2 = atoi(pos2 + 7); 5041114402Sru 5042114402Sru pos2 = os_strstr(pos, " max_oper_chwidth="); 5043114402Sru if (pos2) 5044114402Sru chwidth = atoi(pos2 + 18); 5045114402Sru 5046114402Sru max_oper_chwidth = parse_freq(chwidth, freq2); 5047114402Sru if (max_oper_chwidth < 0) 5048114402Sru return -1; 5049114402Sru 5050114402Sru pos2 = os_strstr(pos, " ssid="); 5051114402Sru if (pos2) { 5052114402Sru char *end; 5053114402Sru 5054 pos2 += 6; 5055 end = os_strchr(pos2, ' '); 5056 if (!end) 5057 group_ssid_len = os_strlen(pos2) / 2; 5058 else 5059 group_ssid_len = (end - pos2) / 2; 5060 if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN || 5061 hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0) 5062 return -1; 5063 group_ssid = _group_ssid; 5064 } 5065 5066 if (os_strncmp(pos, "pin", 3) == 0) { 5067 /* Request random PIN (to be displayed) and enable the PIN */ 5068 wps_method = WPS_PIN_DISPLAY; 5069 } else if (os_strncmp(pos, "pbc", 3) == 0) { 5070 wps_method = WPS_PBC; 5071 } else if (os_strstr(pos, "p2ps") != NULL) { 5072 wps_method = WPS_P2PS; 5073 } else { 5074 pin = pos; 5075 pos = os_strchr(pin, ' '); 5076 wps_method = WPS_PIN_KEYPAD; 5077 if (pos) { 5078 *pos++ = '\0'; 5079 if (os_strncmp(pos, "display", 7) == 0) 5080 wps_method = WPS_PIN_DISPLAY; 5081 } 5082 if (!wps_pin_str_valid(pin)) { 5083 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17); 5084 return 17; 5085 } 5086 } 5087 5088 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, 5089 persistent_group, automatic, join, 5090 auth, go_intent, freq, freq2, persistent_id, 5091 pd, ht40, vht, max_oper_chwidth, 5092 group_ssid, group_ssid_len); 5093 if (new_pin == -2) { 5094 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); 5095 return 25; 5096 } 5097 if (new_pin == -3) { 5098 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25); 5099 return 25; 5100 } 5101 if (new_pin < 0) 5102 return -1; 5103 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) { 5104 ret = os_snprintf(buf, buflen, "%08d", new_pin); 5105 if (os_snprintf_error(buflen, ret)) 5106 return -1; 5107 return ret; 5108 } 5109 5110 os_memcpy(buf, "OK\n", 3); 5111 return 3; 5112} 5113 5114 5115static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd) 5116{ 5117 unsigned int timeout = atoi(cmd); 5118 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 5119 wpa_dbg(wpa_s, MSG_INFO, 5120 "Reject P2P_LISTEN since interface is disabled"); 5121 return -1; 5122 } 5123 return wpas_p2p_listen(wpa_s, timeout); 5124} 5125 5126 5127static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) 5128{ 5129 u8 addr[ETH_ALEN]; 5130 char *pos; 5131 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG; 5132 5133 /* <addr> <config method> [join|auto] */ 5134 5135 if (hwaddr_aton(cmd, addr)) 5136 return -1; 5137 5138 pos = cmd + 17; 5139 if (*pos != ' ') 5140 return -1; 5141 pos++; 5142 5143 if (os_strstr(pos, " join") != NULL) 5144 use = WPAS_P2P_PD_FOR_JOIN; 5145 else if (os_strstr(pos, " auto") != NULL) 5146 use = WPAS_P2P_PD_AUTO; 5147 5148 return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL); 5149} 5150 5151 5152static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf, 5153 size_t buflen) 5154{ 5155 struct wpa_ssid *ssid = wpa_s->current_ssid; 5156 5157 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || 5158 ssid->passphrase == NULL) 5159 return -1; 5160 5161 os_strlcpy(buf, ssid->passphrase, buflen); 5162 return os_strlen(buf); 5163} 5164 5165 5166static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, 5167 char *buf, size_t buflen) 5168{ 5169 u64 ref; 5170 int res; 5171 u8 dst_buf[ETH_ALEN], *dst; 5172 struct wpabuf *tlvs; 5173 char *pos; 5174 size_t len; 5175 5176 if (hwaddr_aton(cmd, dst_buf)) 5177 return -1; 5178 dst = dst_buf; 5179 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && 5180 dst[3] == 0 && dst[4] == 0 && dst[5] == 0) 5181 dst = NULL; 5182 pos = cmd + 17; 5183 if (*pos != ' ') 5184 return -1; 5185 pos++; 5186 5187 if (os_strncmp(pos, "upnp ", 5) == 0) { 5188 u8 version; 5189 pos += 5; 5190 if (hexstr2bin(pos, &version, 1) < 0) 5191 return -1; 5192 pos += 2; 5193 if (*pos != ' ') 5194 return -1; 5195 pos++; 5196 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); 5197#ifdef CONFIG_WIFI_DISPLAY 5198 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) { 5199 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13); 5200#endif /* CONFIG_WIFI_DISPLAY */ 5201 } else if (os_strncmp(pos, "asp ", 4) == 0) { 5202 char *svc_str; 5203 char *svc_info = NULL; 5204 u32 id; 5205 5206 pos += 4; 5207 if (sscanf(pos, "%x", &id) != 1 || id > 0xff) 5208 return -1; 5209 5210 pos = os_strchr(pos, ' '); 5211 if (pos == NULL || pos[1] == '\0' || pos[1] == ' ') 5212 return -1; 5213 5214 svc_str = pos + 1; 5215 5216 pos = os_strchr(svc_str, ' '); 5217 5218 if (pos) 5219 *pos++ = '\0'; 5220 5221 /* All remaining data is the svc_info string */ 5222 if (pos && pos[0] && pos[0] != ' ') { 5223 len = os_strlen(pos); 5224 5225 /* Unescape in place */ 5226 len = utf8_unescape(pos, len, pos, len); 5227 if (len > 0xff) 5228 return -1; 5229 5230 svc_info = pos; 5231 } 5232 5233 ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id, 5234 svc_str, svc_info); 5235 } else { 5236 len = os_strlen(pos); 5237 if (len & 1) 5238 return -1; 5239 len /= 2; 5240 tlvs = wpabuf_alloc(len); 5241 if (tlvs == NULL) 5242 return -1; 5243 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) { 5244 wpabuf_free(tlvs); 5245 return -1; 5246 } 5247 5248 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs); 5249 wpabuf_free(tlvs); 5250 } 5251 if (ref == 0) 5252 return -1; 5253 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref); 5254 if (os_snprintf_error(buflen, res)) 5255 return -1; 5256 return res; 5257} 5258 5259 5260static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s, 5261 char *cmd) 5262{ 5263 long long unsigned val; 5264 u64 req; 5265 if (sscanf(cmd, "%llx", &val) != 1) 5266 return -1; 5267 req = val; 5268 return wpas_p2p_sd_cancel_request(wpa_s, req); 5269} 5270 5271 5272static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd) 5273{ 5274 int freq; 5275 u8 dst[ETH_ALEN]; 5276 u8 dialog_token; 5277 struct wpabuf *resp_tlvs; 5278 char *pos, *pos2; 5279 size_t len; 5280 5281 pos = os_strchr(cmd, ' '); 5282 if (pos == NULL) 5283 return -1; 5284 *pos++ = '\0'; 5285 freq = atoi(cmd); 5286 if (freq == 0) 5287 return -1; 5288 5289 if (hwaddr_aton(pos, dst)) 5290 return -1; 5291 pos += 17; 5292 if (*pos != ' ') 5293 return -1; 5294 pos++; 5295 5296 pos2 = os_strchr(pos, ' '); 5297 if (pos2 == NULL) 5298 return -1; 5299 *pos2++ = '\0'; 5300 dialog_token = atoi(pos); 5301 5302 len = os_strlen(pos2); 5303 if (len & 1) 5304 return -1; 5305 len /= 2; 5306 resp_tlvs = wpabuf_alloc(len); 5307 if (resp_tlvs == NULL) 5308 return -1; 5309 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) { 5310 wpabuf_free(resp_tlvs); 5311 return -1; 5312 } 5313 5314 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs); 5315 wpabuf_free(resp_tlvs); 5316 return 0; 5317} 5318 5319 5320static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s, 5321 char *cmd) 5322{ 5323 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1")) 5324 return -1; 5325 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd); 5326 return 0; 5327} 5328 5329 5330static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, 5331 char *cmd) 5332{ 5333 char *pos; 5334 size_t len; 5335 struct wpabuf *query, *resp; 5336 5337 pos = os_strchr(cmd, ' '); 5338 if (pos == NULL) 5339 return -1; 5340 *pos++ = '\0'; 5341 5342 len = os_strlen(cmd); 5343 if (len & 1) 5344 return -1; 5345 len /= 2; 5346 query = wpabuf_alloc(len); 5347 if (query == NULL) 5348 return -1; 5349 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { 5350 wpabuf_free(query); 5351 return -1; 5352 } 5353 5354 len = os_strlen(pos); 5355 if (len & 1) { 5356 wpabuf_free(query); 5357 return -1; 5358 } 5359 len /= 2; 5360 resp = wpabuf_alloc(len); 5361 if (resp == NULL) { 5362 wpabuf_free(query); 5363 return -1; 5364 } 5365 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { 5366 wpabuf_free(query); 5367 wpabuf_free(resp); 5368 return -1; 5369 } 5370 5371 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { 5372 wpabuf_free(query); 5373 wpabuf_free(resp); 5374 return -1; 5375 } 5376 return 0; 5377} 5378 5379 5380static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd) 5381{ 5382 char *pos; 5383 u8 version; 5384 5385 pos = os_strchr(cmd, ' '); 5386 if (pos == NULL) 5387 return -1; 5388 *pos++ = '\0'; 5389 5390 if (hexstr2bin(cmd, &version, 1) < 0) 5391 return -1; 5392 5393 return wpas_p2p_service_add_upnp(wpa_s, version, pos); 5394} 5395 5396 5397static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s, 5398 u8 replace, char *cmd) 5399{ 5400 char *pos; 5401 char *adv_str; 5402 u32 auto_accept, adv_id, svc_state, config_methods; 5403 char *svc_info = NULL; 5404 char *cpt_prio_str; 5405 u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1]; 5406 5407 pos = os_strchr(cmd, ' '); 5408 if (pos == NULL) 5409 return -1; 5410 *pos++ = '\0'; 5411 5412 /* Auto-Accept value is mandatory, and must be one of the 5413 * single values (0, 1, 2, 4) */ 5414 auto_accept = atoi(cmd); 5415 switch (auto_accept) { 5416 case P2PS_SETUP_NONE: /* No auto-accept */ 5417 case P2PS_SETUP_NEW: 5418 case P2PS_SETUP_CLIENT: 5419 case P2PS_SETUP_GROUP_OWNER: 5420 break; 5421 default: 5422 return -1; 5423 } 5424 5425 /* Advertisement ID is mandatory */ 5426 cmd = pos; 5427 pos = os_strchr(cmd, ' '); 5428 if (pos == NULL) 5429 return -1; 5430 *pos++ = '\0'; 5431 5432 /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */ 5433 if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0) 5434 return -1; 5435 5436 /* Only allow replacements if exist, and adds if not */ 5437 if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) { 5438 if (!replace) 5439 return -1; 5440 } else { 5441 if (replace) 5442 return -1; 5443 } 5444 5445 /* svc_state between 0 - 0xff is mandatory */ 5446 if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff) 5447 return -1; 5448 5449 pos = os_strchr(pos, ' '); 5450 if (pos == NULL) 5451 return -1; 5452 5453 /* config_methods is mandatory */ 5454 pos++; 5455 if (sscanf(pos, "%x", &config_methods) != 1) 5456 return -1; 5457 5458 if (!(config_methods & 5459 (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS))) 5460 return -1; 5461 5462 pos = os_strchr(pos, ' '); 5463 if (pos == NULL) 5464 return -1; 5465 5466 pos++; 5467 adv_str = pos; 5468 5469 /* Advertisement string is mandatory */ 5470 if (!pos[0] || pos[0] == ' ') 5471 return -1; 5472 5473 /* Terminate svc string */ 5474 pos = os_strchr(pos, ' '); 5475 if (pos != NULL) 5476 *pos++ = '\0'; 5477 5478 cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL; 5479 if (cpt_prio_str) { 5480 pos = os_strchr(pos, ' '); 5481 if (pos != NULL) 5482 *pos++ = '\0'; 5483 5484 if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio)) 5485 return -1; 5486 } else { 5487 cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; 5488 cpt_prio[1] = 0; 5489 } 5490 5491 /* Service and Response Information are optional */ 5492 if (pos && pos[0]) { 5493 size_t len; 5494 5495 /* Note the bare ' included, which cannot exist legally 5496 * in unescaped string. */ 5497 svc_info = os_strstr(pos, "svc_info='"); 5498 5499 if (svc_info) { 5500 svc_info += 9; 5501 len = os_strlen(svc_info); 5502 utf8_unescape(svc_info, len, svc_info, len); 5503 } 5504 } 5505 5506 return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str, 5507 (u8) svc_state, (u16) config_methods, 5508 svc_info, cpt_prio); 5509} 5510 5511 5512static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd) 5513{ 5514 char *pos; 5515 5516 pos = os_strchr(cmd, ' '); 5517 if (pos == NULL) 5518 return -1; 5519 *pos++ = '\0'; 5520 5521 if (os_strcmp(cmd, "bonjour") == 0) 5522 return p2p_ctrl_service_add_bonjour(wpa_s, pos); 5523 if (os_strcmp(cmd, "upnp") == 0) 5524 return p2p_ctrl_service_add_upnp(wpa_s, pos); 5525 if (os_strcmp(cmd, "asp") == 0) 5526 return p2p_ctrl_service_add_asp(wpa_s, 0, pos); 5527 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 5528 return -1; 5529} 5530 5531 5532static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s, 5533 char *cmd) 5534{ 5535 size_t len; 5536 struct wpabuf *query; 5537 int ret; 5538 5539 len = os_strlen(cmd); 5540 if (len & 1) 5541 return -1; 5542 len /= 2; 5543 query = wpabuf_alloc(len); 5544 if (query == NULL) 5545 return -1; 5546 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { 5547 wpabuf_free(query); 5548 return -1; 5549 } 5550 5551 ret = wpas_p2p_service_del_bonjour(wpa_s, query); 5552 wpabuf_free(query); 5553 return ret; 5554} 5555 5556 5557static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd) 5558{ 5559 char *pos; 5560 u8 version; 5561 5562 pos = os_strchr(cmd, ' '); 5563 if (pos == NULL) 5564 return -1; 5565 *pos++ = '\0'; 5566 5567 if (hexstr2bin(cmd, &version, 1) < 0) 5568 return -1; 5569 5570 return wpas_p2p_service_del_upnp(wpa_s, version, pos); 5571} 5572 5573 5574static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd) 5575{ 5576 u32 adv_id; 5577 5578 if (os_strcmp(cmd, "all") == 0) { 5579 wpas_p2p_service_flush_asp(wpa_s); 5580 return 0; 5581 } 5582 5583 if (sscanf(cmd, "%x", &adv_id) != 1) 5584 return -1; 5585 5586 return wpas_p2p_service_del_asp(wpa_s, adv_id); 5587} 5588 5589 5590static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd) 5591{ 5592 char *pos; 5593 5594 pos = os_strchr(cmd, ' '); 5595 if (pos == NULL) 5596 return -1; 5597 *pos++ = '\0'; 5598 5599 if (os_strcmp(cmd, "bonjour") == 0) 5600 return p2p_ctrl_service_del_bonjour(wpa_s, pos); 5601 if (os_strcmp(cmd, "upnp") == 0) 5602 return p2p_ctrl_service_del_upnp(wpa_s, pos); 5603 if (os_strcmp(cmd, "asp") == 0) 5604 return p2p_ctrl_service_del_asp(wpa_s, pos); 5605 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 5606 return -1; 5607} 5608 5609 5610static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd) 5611{ 5612 char *pos; 5613 5614 pos = os_strchr(cmd, ' '); 5615 if (pos == NULL) 5616 return -1; 5617 *pos++ = '\0'; 5618 5619 if (os_strcmp(cmd, "asp") == 0) 5620 return p2p_ctrl_service_add_asp(wpa_s, 1, pos); 5621 5622 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); 5623 return -1; 5624} 5625 5626 5627static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd) 5628{ 5629 u8 addr[ETH_ALEN]; 5630 5631 /* <addr> */ 5632 5633 if (hwaddr_aton(cmd, addr)) 5634 return -1; 5635 5636 return wpas_p2p_reject(wpa_s, addr); 5637} 5638 5639 5640static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) 5641{ 5642 char *pos; 5643 int id; 5644 struct wpa_ssid *ssid; 5645 u8 *_peer = NULL, peer[ETH_ALEN]; 5646 int freq = 0, pref_freq = 0; 5647 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; 5648 5649 id = atoi(cmd); 5650 pos = os_strstr(cmd, " peer="); 5651 if (pos) { 5652 pos += 6; 5653 if (hwaddr_aton(pos, peer)) 5654 return -1; 5655 _peer = peer; 5656 } 5657 ssid = wpa_config_get_network(wpa_s->conf, id); 5658 if (ssid == NULL || ssid->disabled != 2) { 5659 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 5660 "for persistent P2P group", 5661 id); 5662 return -1; 5663 } 5664 5665 pos = os_strstr(cmd, " freq="); 5666 if (pos) { 5667 pos += 6; 5668 freq = atoi(pos); 5669 if (freq <= 0) 5670 return -1; 5671 } 5672 5673 pos = os_strstr(cmd, " pref="); 5674 if (pos) { 5675 pos += 6; 5676 pref_freq = atoi(pos); 5677 if (pref_freq <= 0) 5678 return -1; 5679 } 5680 5681 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; 5682 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || 5683 vht; 5684 5685 pos = os_strstr(cmd, "freq2="); 5686 if (pos) 5687 freq2 = atoi(pos + 6); 5688 5689 pos = os_strstr(cmd, " max_oper_chwidth="); 5690 if (pos) 5691 chwidth = atoi(pos + 18); 5692 5693 max_oper_chwidth = parse_freq(chwidth, freq2); 5694 if (max_oper_chwidth < 0) 5695 return -1; 5696 5697 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, 5698 max_oper_chwidth, pref_freq); 5699} 5700 5701 5702static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) 5703{ 5704 char *pos; 5705 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; 5706 5707 pos = os_strstr(cmd, " peer="); 5708 if (!pos) 5709 return -1; 5710 5711 *pos = '\0'; 5712 pos += 6; 5713 if (hwaddr_aton(pos, peer)) { 5714 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); 5715 return -1; 5716 } 5717 5718 pos = os_strstr(pos, " go_dev_addr="); 5719 if (pos) { 5720 pos += 13; 5721 if (hwaddr_aton(pos, go_dev_addr)) { 5722 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", 5723 pos); 5724 return -1; 5725 } 5726 go_dev = go_dev_addr; 5727 } 5728 5729 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); 5730} 5731 5732 5733static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) 5734{ 5735 if (os_strncmp(cmd, "persistent=", 11) == 0) 5736 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11); 5737 if (os_strncmp(cmd, "group=", 6) == 0) 5738 return p2p_ctrl_invite_group(wpa_s, cmd + 6); 5739 5740 return -1; 5741} 5742 5743 5744static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, 5745 int id, int freq, int vht_center_freq2, 5746 int ht40, int vht, int vht_chwidth) 5747{ 5748 struct wpa_ssid *ssid; 5749 5750 ssid = wpa_config_get_network(wpa_s->conf, id); 5751 if (ssid == NULL || ssid->disabled != 2) { 5752 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " 5753 "for persistent P2P group", 5754 id); 5755 return -1; 5756 } 5757 5758 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 5759 vht_center_freq2, 0, ht40, vht, 5760 vht_chwidth, NULL, 0, 0); 5761} 5762 5763 5764static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) 5765{ 5766 int freq = 0, persistent = 0, group_id = -1; 5767 int vht = wpa_s->conf->p2p_go_vht; 5768 int ht40 = wpa_s->conf->p2p_go_ht40 || vht; 5769 int max_oper_chwidth, chwidth = 0, freq2 = 0; 5770 char *token, *context = NULL; 5771 5772 while ((token = str_token(cmd, " ", &context))) { 5773 if (sscanf(token, "freq=%d", &freq) == 1 || 5774 sscanf(token, "freq2=%d", &freq2) == 1 || 5775 sscanf(token, "persistent=%d", &group_id) == 1 || 5776 sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) { 5777 continue; 5778 } else if (os_strcmp(token, "ht40") == 0) { 5779 ht40 = 1; 5780 } else if (os_strcmp(token, "vht") == 0) { 5781 vht = 1; 5782 ht40 = 1; 5783 } else if (os_strcmp(token, "persistent") == 0) { 5784 persistent = 1; 5785 } else { 5786 wpa_printf(MSG_DEBUG, 5787 "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'", 5788 token); 5789 return -1; 5790 } 5791 } 5792 5793 max_oper_chwidth = parse_freq(chwidth, freq2); 5794 if (max_oper_chwidth < 0) 5795 return -1; 5796 5797 if (group_id >= 0) 5798 return p2p_ctrl_group_add_persistent(wpa_s, group_id, 5799 freq, freq2, ht40, vht, 5800 max_oper_chwidth); 5801 5802 return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, 5803 max_oper_chwidth); 5804} 5805 5806 5807static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, 5808 char *buf, size_t buflen) 5809{ 5810 u8 dev_addr[ETH_ALEN]; 5811 struct wpa_ssid *ssid; 5812 int res; 5813 const u8 *iaddr; 5814 5815 ssid = wpa_s->current_ssid; 5816 if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO || 5817 hwaddr_aton(cmd, dev_addr)) 5818 return -1; 5819 5820 iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr); 5821 if (!iaddr) 5822 return -1; 5823 res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr)); 5824 if (os_snprintf_error(buflen, res)) 5825 return -1; 5826 return res; 5827} 5828 5829 5830static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, 5831 char *buf, size_t buflen) 5832{ 5833 u8 addr[ETH_ALEN], *addr_ptr; 5834 int next, res; 5835 const struct p2p_peer_info *info; 5836 char *pos, *end; 5837 char devtype[WPS_DEV_TYPE_BUFSIZE]; 5838 struct wpa_ssid *ssid; 5839 size_t i; 5840 5841 if (!wpa_s->global->p2p) 5842 return -1; 5843 5844 if (os_strcmp(cmd, "FIRST") == 0) { 5845 addr_ptr = NULL; 5846 next = 0; 5847 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { 5848 if (hwaddr_aton(cmd + 5, addr) < 0) 5849 return -1; 5850 addr_ptr = addr; 5851 next = 1; 5852 } else { 5853 if (hwaddr_aton(cmd, addr) < 0) 5854 return -1; 5855 addr_ptr = addr; 5856 next = 0; 5857 } 5858 5859 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next); 5860 if (info == NULL) 5861 return -1; 5862 5863 pos = buf; 5864 end = buf + buflen; 5865 5866 res = os_snprintf(pos, end - pos, MACSTR "\n" 5867 "pri_dev_type=%s\n" 5868 "device_name=%s\n" 5869 "manufacturer=%s\n" 5870 "model_name=%s\n" 5871 "model_number=%s\n" 5872 "serial_number=%s\n" 5873 "config_methods=0x%x\n" 5874 "dev_capab=0x%x\n" 5875 "group_capab=0x%x\n" 5876 "level=%d\n", 5877 MAC2STR(info->p2p_device_addr), 5878 wps_dev_type_bin2str(info->pri_dev_type, 5879 devtype, sizeof(devtype)), 5880 info->device_name, 5881 info->manufacturer, 5882 info->model_name, 5883 info->model_number, 5884 info->serial_number, 5885 info->config_methods, 5886 info->dev_capab, 5887 info->group_capab, 5888 info->level); 5889 if (os_snprintf_error(end - pos, res)) 5890 return pos - buf; 5891 pos += res; 5892 5893 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++) 5894 { 5895 const u8 *t; 5896 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN]; 5897 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n", 5898 wps_dev_type_bin2str(t, devtype, 5899 sizeof(devtype))); 5900 if (os_snprintf_error(end - pos, res)) 5901 return pos - buf; 5902 pos += res; 5903 } 5904 5905 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0); 5906 if (ssid) { 5907 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id); 5908 if (os_snprintf_error(end - pos, res)) 5909 return pos - buf; 5910 pos += res; 5911 } 5912 5913 res = p2p_get_peer_info_txt(info, pos, end - pos); 5914 if (res < 0) 5915 return pos - buf; 5916 pos += res; 5917 5918 if (info->vendor_elems) { 5919 res = os_snprintf(pos, end - pos, "vendor_elems="); 5920 if (os_snprintf_error(end - pos, res)) 5921 return pos - buf; 5922 pos += res; 5923 5924 pos += wpa_snprintf_hex(pos, end - pos, 5925 wpabuf_head(info->vendor_elems), 5926 wpabuf_len(info->vendor_elems)); 5927 5928 res = os_snprintf(pos, end - pos, "\n"); 5929 if (os_snprintf_error(end - pos, res)) 5930 return pos - buf; 5931 pos += res; 5932 } 5933 5934 return pos - buf; 5935} 5936 5937 5938static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s, 5939 const char *param) 5940{ 5941 unsigned int i; 5942 5943 if (wpa_s->global->p2p == NULL) 5944 return -1; 5945 5946 if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0) 5947 return -1; 5948 5949 for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) { 5950 struct wpa_freq_range *freq; 5951 freq = &wpa_s->global->p2p_disallow_freq.range[i]; 5952 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u", 5953 freq->min, freq->max); 5954 } 5955 5956 wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW); 5957 return 0; 5958} 5959 5960 5961static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) 5962{ 5963 char *param; 5964 5965 if (wpa_s->global->p2p == NULL) 5966 return -1; 5967 5968 param = os_strchr(cmd, ' '); 5969 if (param == NULL) 5970 return -1; 5971 *param++ = '\0'; 5972 5973 if (os_strcmp(cmd, "discoverability") == 0) { 5974 p2p_set_client_discoverability(wpa_s->global->p2p, 5975 atoi(param)); 5976 return 0; 5977 } 5978 5979 if (os_strcmp(cmd, "managed") == 0) { 5980 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param)); 5981 return 0; 5982 } 5983 5984 if (os_strcmp(cmd, "listen_channel") == 0) { 5985 char *pos; 5986 u8 channel, op_class; 5987 5988 channel = atoi(param); 5989 pos = os_strchr(param, ' '); 5990 op_class = pos ? atoi(pos) : 81; 5991 5992 return p2p_set_listen_channel(wpa_s->global->p2p, op_class, 5993 channel, 1); 5994 } 5995 5996 if (os_strcmp(cmd, "ssid_postfix") == 0) { 5997 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param, 5998 os_strlen(param)); 5999 } 6000 6001 if (os_strcmp(cmd, "noa") == 0) { 6002 char *pos; 6003 int count, start, duration; 6004 /* GO NoA parameters: count,start_offset(ms),duration(ms) */ 6005 count = atoi(param); 6006 pos = os_strchr(param, ','); 6007 if (pos == NULL) 6008 return -1; 6009 pos++; 6010 start = atoi(pos); 6011 pos = os_strchr(pos, ','); 6012 if (pos == NULL) 6013 return -1; 6014 pos++; 6015 duration = atoi(pos); 6016 if (count < 0 || count > 255 || start < 0 || duration < 0) 6017 return -1; 6018 if (count == 0 && duration > 0) 6019 return -1; 6020 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " 6021 "start=%d duration=%d", count, start, duration); 6022 return wpas_p2p_set_noa(wpa_s, count, start, duration); 6023 } 6024 6025 if (os_strcmp(cmd, "ps") == 0) 6026 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1); 6027 6028 if (os_strcmp(cmd, "oppps") == 0) 6029 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1); 6030 6031 if (os_strcmp(cmd, "ctwindow") == 0) 6032 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param)); 6033 6034 if (os_strcmp(cmd, "disabled") == 0) { 6035 wpa_s->global->p2p_disabled = atoi(param); 6036 wpa_printf(MSG_DEBUG, "P2P functionality %s", 6037 wpa_s->global->p2p_disabled ? 6038 "disabled" : "enabled"); 6039 if (wpa_s->global->p2p_disabled) { 6040 wpas_p2p_stop_find(wpa_s); 6041 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); 6042 p2p_flush(wpa_s->global->p2p); 6043 } 6044 return 0; 6045 } 6046 6047 if (os_strcmp(cmd, "conc_pref") == 0) { 6048 if (os_strcmp(param, "sta") == 0) 6049 wpa_s->global->conc_pref = WPA_CONC_PREF_STA; 6050 else if (os_strcmp(param, "p2p") == 0) 6051 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P; 6052 else { 6053 wpa_printf(MSG_INFO, "Invalid conc_pref value"); 6054 return -1; 6055 } 6056 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: " 6057 "%s", param); 6058 return 0; 6059 } 6060 6061 if (os_strcmp(cmd, "force_long_sd") == 0) { 6062 wpa_s->force_long_sd = atoi(param); 6063 return 0; 6064 } 6065 6066 if (os_strcmp(cmd, "peer_filter") == 0) { 6067 u8 addr[ETH_ALEN]; 6068 if (hwaddr_aton(param, addr)) 6069 return -1; 6070 p2p_set_peer_filter(wpa_s->global->p2p, addr); 6071 return 0; 6072 } 6073 6074 if (os_strcmp(cmd, "cross_connect") == 0) 6075 return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); 6076 6077 if (os_strcmp(cmd, "go_apsd") == 0) { 6078 if (os_strcmp(param, "disable") == 0) 6079 wpa_s->set_ap_uapsd = 0; 6080 else { 6081 wpa_s->set_ap_uapsd = 1; 6082 wpa_s->ap_uapsd = atoi(param); 6083 } 6084 return 0; 6085 } 6086 6087 if (os_strcmp(cmd, "client_apsd") == 0) { 6088 if (os_strcmp(param, "disable") == 0) 6089 wpa_s->set_sta_uapsd = 0; 6090 else { 6091 int be, bk, vi, vo; 6092 char *pos; 6093 /* format: BE,BK,VI,VO;max SP Length */ 6094 be = atoi(param); 6095 pos = os_strchr(param, ','); 6096 if (pos == NULL) 6097 return -1; 6098 pos++; 6099 bk = atoi(pos); 6100 pos = os_strchr(pos, ','); 6101 if (pos == NULL) 6102 return -1; 6103 pos++; 6104 vi = atoi(pos); 6105 pos = os_strchr(pos, ','); 6106 if (pos == NULL) 6107 return -1; 6108 pos++; 6109 vo = atoi(pos); 6110 /* ignore max SP Length for now */ 6111 6112 wpa_s->set_sta_uapsd = 1; 6113 wpa_s->sta_uapsd = 0; 6114 if (be) 6115 wpa_s->sta_uapsd |= BIT(0); 6116 if (bk) 6117 wpa_s->sta_uapsd |= BIT(1); 6118 if (vi) 6119 wpa_s->sta_uapsd |= BIT(2); 6120 if (vo) 6121 wpa_s->sta_uapsd |= BIT(3); 6122 } 6123 return 0; 6124 } 6125 6126 if (os_strcmp(cmd, "disallow_freq") == 0) 6127 return p2p_ctrl_disallow_freq(wpa_s, param); 6128 6129 if (os_strcmp(cmd, "disc_int") == 0) { 6130 int min_disc_int, max_disc_int, max_disc_tu; 6131 char *pos; 6132 6133 pos = param; 6134 6135 min_disc_int = atoi(pos); 6136 pos = os_strchr(pos, ' '); 6137 if (pos == NULL) 6138 return -1; 6139 *pos++ = '\0'; 6140 6141 max_disc_int = atoi(pos); 6142 pos = os_strchr(pos, ' '); 6143 if (pos == NULL) 6144 return -1; 6145 *pos++ = '\0'; 6146 6147 max_disc_tu = atoi(pos); 6148 6149 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int, 6150 max_disc_int, max_disc_tu); 6151 } 6152 6153 if (os_strcmp(cmd, "per_sta_psk") == 0) { 6154 wpa_s->global->p2p_per_sta_psk = !!atoi(param); 6155 return 0; 6156 } 6157 6158#ifdef CONFIG_WPS_NFC 6159 if (os_strcmp(cmd, "nfc_tag") == 0) 6160 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param)); 6161#endif /* CONFIG_WPS_NFC */ 6162 6163 if (os_strcmp(cmd, "disable_ip_addr_req") == 0) { 6164 wpa_s->p2p_disable_ip_addr_req = !!atoi(param); 6165 return 0; 6166 } 6167 6168 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", 6169 cmd); 6170 6171 return -1; 6172} 6173 6174 6175static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s) 6176{ 6177 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); 6178 wpa_s->force_long_sd = 0; 6179 wpas_p2p_stop_find(wpa_s); 6180 wpa_s->parent->p2ps_method_config_any = 0; 6181 if (wpa_s->global->p2p) 6182 p2p_flush(wpa_s->global->p2p); 6183} 6184 6185 6186static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd) 6187{ 6188 char *pos, *pos2; 6189 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; 6190 6191 if (cmd[0]) { 6192 pos = os_strchr(cmd, ' '); 6193 if (pos == NULL) 6194 return -1; 6195 *pos++ = '\0'; 6196 dur1 = atoi(cmd); 6197 6198 pos2 = os_strchr(pos, ' '); 6199 if (pos2) 6200 *pos2++ = '\0'; 6201 int1 = atoi(pos); 6202 } else 6203 pos2 = NULL; 6204 6205 if (pos2) { 6206 pos = os_strchr(pos2, ' '); 6207 if (pos == NULL) 6208 return -1; 6209 *pos++ = '\0'; 6210 dur2 = atoi(pos2); 6211 int2 = atoi(pos); 6212 } 6213 6214 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2); 6215} 6216 6217 6218static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd) 6219{ 6220 char *pos; 6221 unsigned int period = 0, interval = 0; 6222 6223 if (cmd[0]) { 6224 pos = os_strchr(cmd, ' '); 6225 if (pos == NULL) 6226 return -1; 6227 *pos++ = '\0'; 6228 period = atoi(cmd); 6229 interval = atoi(pos); 6230 } 6231 6232 return wpas_p2p_ext_listen(wpa_s, period, interval); 6233} 6234 6235 6236static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) 6237{ 6238 const char *pos; 6239 u8 peer[ETH_ALEN]; 6240 int iface_addr = 0; 6241 6242 pos = cmd; 6243 if (os_strncmp(pos, "iface=", 6) == 0) { 6244 iface_addr = 1; 6245 pos += 6; 6246 } 6247 if (hwaddr_aton(pos, peer)) 6248 return -1; 6249 6250 wpas_p2p_remove_client(wpa_s, peer, iface_addr); 6251 return 0; 6252} 6253 6254 6255static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd) 6256{ 6257 int freq = 0, period = 0, interval = 0, count = 0; 6258 6259 if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4) 6260 { 6261 wpa_printf(MSG_DEBUG, 6262 "CTRL: Invalid P2P LO Start parameter: '%s'", cmd); 6263 return -1; 6264 } 6265 6266 return wpas_p2p_lo_start(wpa_s, freq, period, interval, count); 6267} 6268 6269#endif /* CONFIG_P2P */ 6270 6271 6272static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val) 6273{ 6274 struct wpa_freq_range_list ranges; 6275 int *freqs = NULL; 6276 struct hostapd_hw_modes *mode; 6277 u16 i; 6278 6279 if (wpa_s->hw.modes == NULL) 6280 return NULL; 6281 6282 os_memset(&ranges, 0, sizeof(ranges)); 6283 if (freq_range_list_parse(&ranges, val) < 0) 6284 return NULL; 6285 6286 for (i = 0; i < wpa_s->hw.num_modes; i++) { 6287 int j; 6288 6289 mode = &wpa_s->hw.modes[i]; 6290 for (j = 0; j < mode->num_channels; j++) { 6291 unsigned int freq; 6292 6293 if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) 6294 continue; 6295 6296 freq = mode->channels[j].freq; 6297 if (!freq_range_list_includes(&ranges, freq)) 6298 continue; 6299 6300 int_array_add_unique(&freqs, freq); 6301 } 6302 } 6303 6304 os_free(ranges.range); 6305 return freqs; 6306} 6307 6308 6309#ifdef CONFIG_INTERWORKING 6310 6311static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) 6312{ 6313 int auto_sel = 0; 6314 int *freqs = NULL; 6315 6316 if (param) { 6317 char *pos; 6318 6319 auto_sel = os_strstr(param, "auto") != NULL; 6320 6321 pos = os_strstr(param, "freq="); 6322 if (pos) { 6323 freqs = freq_range_to_channel_list(wpa_s, pos + 5); 6324 if (freqs == NULL) 6325 return -1; 6326 } 6327 6328 } 6329 6330 return interworking_select(wpa_s, auto_sel, freqs); 6331} 6332 6333 6334static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst, 6335 int only_add) 6336{ 6337 u8 bssid[ETH_ALEN]; 6338 struct wpa_bss *bss; 6339 6340 if (hwaddr_aton(dst, bssid)) { 6341 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst); 6342 return -1; 6343 } 6344 6345 bss = wpa_bss_get_bssid(wpa_s, bssid); 6346 if (bss == NULL) { 6347 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR, 6348 MAC2STR(bssid)); 6349 return -1; 6350 } 6351 6352 if (bss->ssid_len == 0) { 6353 int found = 0; 6354 6355 wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR 6356 " does not have SSID information", MAC2STR(bssid)); 6357 6358 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, 6359 list) { 6360 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && 6361 bss->ssid_len > 0) { 6362 found = 1; 6363 break; 6364 } 6365 } 6366 6367 if (!found) 6368 return -1; 6369 wpa_printf(MSG_DEBUG, 6370 "Found another matching BSS entry with SSID"); 6371 } 6372 6373 return interworking_connect(wpa_s, bss, only_add); 6374} 6375 6376 6377static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) 6378{ 6379 u8 dst_addr[ETH_ALEN]; 6380 int used; 6381 char *pos; 6382#define MAX_ANQP_INFO_ID 100 6383 u16 id[MAX_ANQP_INFO_ID]; 6384 size_t num_id = 0; 6385 u32 subtypes = 0; 6386 int get_cell_pref = 0; 6387 6388 used = hwaddr_aton2(dst, dst_addr); 6389 if (used < 0) 6390 return -1; 6391 pos = dst + used; 6392 if (*pos == ' ') 6393 pos++; 6394 while (num_id < MAX_ANQP_INFO_ID) { 6395 if (os_strncmp(pos, "hs20:", 5) == 0) { 6396#ifdef CONFIG_HS20 6397 int num = atoi(pos + 5); 6398 if (num <= 0 || num > 31) 6399 return -1; 6400 subtypes |= BIT(num); 6401#else /* CONFIG_HS20 */ 6402 return -1; 6403#endif /* CONFIG_HS20 */ 6404 } else if (os_strncmp(pos, "mbo:", 4) == 0) { 6405#ifdef CONFIG_MBO 6406 int num = atoi(pos + 4); 6407 if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF) 6408 return -1; 6409 get_cell_pref = 1; 6410#else /* CONFIG_MBO */ 6411 return -1; 6412#endif /* CONFIG_MBO */ 6413 } else { 6414 id[num_id] = atoi(pos); 6415 if (id[num_id]) 6416 num_id++; 6417 } 6418 pos = os_strchr(pos + 1, ','); 6419 if (pos == NULL) 6420 break; 6421 pos++; 6422 } 6423 6424 if (num_id == 0) 6425 return -1; 6426 6427 return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, 6428 get_cell_pref); 6429} 6430 6431 6432static int gas_request(struct wpa_supplicant *wpa_s, char *cmd) 6433{ 6434 u8 dst_addr[ETH_ALEN]; 6435 struct wpabuf *advproto, *query = NULL; 6436 int used, ret = -1; 6437 char *pos, *end; 6438 size_t len; 6439 6440 used = hwaddr_aton2(cmd, dst_addr); 6441 if (used < 0) 6442 return -1; 6443 6444 pos = cmd + used; 6445 while (*pos == ' ') 6446 pos++; 6447 6448 /* Advertisement Protocol ID */ 6449 end = os_strchr(pos, ' '); 6450 if (end) 6451 len = end - pos; 6452 else 6453 len = os_strlen(pos); 6454 if (len & 0x01) 6455 return -1; 6456 len /= 2; 6457 if (len == 0) 6458 return -1; 6459 advproto = wpabuf_alloc(len); 6460 if (advproto == NULL) 6461 return -1; 6462 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0) 6463 goto fail; 6464 6465 if (end) { 6466 /* Optional Query Request */ 6467 pos = end + 1; 6468 while (*pos == ' ') 6469 pos++; 6470 6471 len = os_strlen(pos); 6472 if (len) { 6473 if (len & 0x01) 6474 goto fail; 6475 len /= 2; 6476 if (len == 0) 6477 goto fail; 6478 query = wpabuf_alloc(len); 6479 if (query == NULL) 6480 goto fail; 6481 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0) 6482 goto fail; 6483 } 6484 } 6485 6486 ret = gas_send_request(wpa_s, dst_addr, advproto, query); 6487 6488fail: 6489 wpabuf_free(advproto); 6490 wpabuf_free(query); 6491 6492 return ret; 6493} 6494 6495 6496static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, 6497 size_t buflen) 6498{ 6499 u8 addr[ETH_ALEN]; 6500 int dialog_token; 6501 int used; 6502 char *pos; 6503 size_t resp_len, start, requested_len; 6504 struct wpabuf *resp; 6505 int ret; 6506 6507 used = hwaddr_aton2(cmd, addr); 6508 if (used < 0) 6509 return -1; 6510 6511 pos = cmd + used; 6512 while (*pos == ' ') 6513 pos++; 6514 dialog_token = atoi(pos); 6515 6516 if (wpa_s->last_gas_resp && 6517 os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && 6518 dialog_token == wpa_s->last_gas_dialog_token) 6519 resp = wpa_s->last_gas_resp; 6520 else if (wpa_s->prev_gas_resp && 6521 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && 6522 dialog_token == wpa_s->prev_gas_dialog_token) 6523 resp = wpa_s->prev_gas_resp; 6524 else 6525 return -1; 6526 6527 resp_len = wpabuf_len(resp); 6528 start = 0; 6529 requested_len = resp_len; 6530 6531 pos = os_strchr(pos, ' '); 6532 if (pos) { 6533 start = atoi(pos); 6534 if (start > resp_len) 6535 return os_snprintf(buf, buflen, "FAIL-Invalid range"); 6536 pos = os_strchr(pos, ','); 6537 if (pos == NULL) 6538 return -1; 6539 pos++; 6540 requested_len = atoi(pos); 6541 if (start + requested_len > resp_len) 6542 return os_snprintf(buf, buflen, "FAIL-Invalid range"); 6543 } 6544 6545 if (requested_len * 2 + 1 > buflen) 6546 return os_snprintf(buf, buflen, "FAIL-Too long response"); 6547 6548 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, 6549 requested_len); 6550 6551 if (start + requested_len == resp_len) { 6552 /* 6553 * Free memory by dropping the response after it has been 6554 * fetched. 6555 */ 6556 if (resp == wpa_s->prev_gas_resp) { 6557 wpabuf_free(wpa_s->prev_gas_resp); 6558 wpa_s->prev_gas_resp = NULL; 6559 } else { 6560 wpabuf_free(wpa_s->last_gas_resp); 6561 wpa_s->last_gas_resp = NULL; 6562 } 6563 } 6564 6565 return ret; 6566} 6567#endif /* CONFIG_INTERWORKING */ 6568 6569 6570#ifdef CONFIG_HS20 6571 6572static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) 6573{ 6574 u8 dst_addr[ETH_ALEN]; 6575 int used; 6576 char *pos; 6577 u32 subtypes = 0; 6578 6579 used = hwaddr_aton2(dst, dst_addr); 6580 if (used < 0) 6581 return -1; 6582 pos = dst + used; 6583 if (*pos == ' ') 6584 pos++; 6585 for (;;) { 6586 int num = atoi(pos); 6587 if (num <= 0 || num > 31) 6588 return -1; 6589 subtypes |= BIT(num); 6590 pos = os_strchr(pos + 1, ','); 6591 if (pos == NULL) 6592 break; 6593 pos++; 6594 } 6595 6596 if (subtypes == 0) 6597 return -1; 6598 6599 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0); 6600} 6601 6602 6603static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, 6604 const u8 *addr, const char *realm) 6605{ 6606 u8 *buf; 6607 size_t rlen, len; 6608 int ret; 6609 6610 rlen = os_strlen(realm); 6611 len = 3 + rlen; 6612 buf = os_malloc(len); 6613 if (buf == NULL) 6614 return -1; 6615 buf[0] = 1; /* NAI Home Realm Count */ 6616 buf[1] = 0; /* Formatted in accordance with RFC 4282 */ 6617 buf[2] = rlen; 6618 os_memcpy(buf + 3, realm, rlen); 6619 6620 ret = hs20_anqp_send_req(wpa_s, addr, 6621 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), 6622 buf, len, 0); 6623 6624 os_free(buf); 6625 6626 return ret; 6627} 6628 6629 6630static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, 6631 char *dst) 6632{ 6633 struct wpa_cred *cred = wpa_s->conf->cred; 6634 u8 dst_addr[ETH_ALEN]; 6635 int used; 6636 u8 *buf; 6637 size_t len; 6638 int ret; 6639 6640 used = hwaddr_aton2(dst, dst_addr); 6641 if (used < 0) 6642 return -1; 6643 6644 while (dst[used] == ' ') 6645 used++; 6646 if (os_strncmp(dst + used, "realm=", 6) == 0) 6647 return hs20_nai_home_realm_list(wpa_s, dst_addr, 6648 dst + used + 6); 6649 6650 len = os_strlen(dst + used); 6651 6652 if (len == 0 && cred && cred->realm) 6653 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm); 6654 6655 if (len & 1) 6656 return -1; 6657 len /= 2; 6658 buf = os_malloc(len); 6659 if (buf == NULL) 6660 return -1; 6661 if (hexstr2bin(dst + used, buf, len) < 0) { 6662 os_free(buf); 6663 return -1; 6664 } 6665 6666 ret = hs20_anqp_send_req(wpa_s, dst_addr, 6667 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), 6668 buf, len, 0); 6669 os_free(buf); 6670 6671 return ret; 6672} 6673 6674 6675static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply, 6676 int buflen) 6677{ 6678 u8 dst_addr[ETH_ALEN]; 6679 int used; 6680 char *ctx = NULL, *icon, *poffset, *psize; 6681 6682 used = hwaddr_aton2(cmd, dst_addr); 6683 if (used < 0) 6684 return -1; 6685 cmd += used; 6686 6687 icon = str_token(cmd, " ", &ctx); 6688 poffset = str_token(cmd, " ", &ctx); 6689 psize = str_token(cmd, " ", &ctx); 6690 if (!icon || !poffset || !psize) 6691 return -1; 6692 6693 wpa_s->fetch_osu_icon_in_progress = 0; 6694 return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize), 6695 reply, buflen); 6696} 6697 6698 6699static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd) 6700{ 6701 u8 dst_addr[ETH_ALEN]; 6702 int used; 6703 char *icon; 6704 6705 if (!cmd[0]) 6706 return hs20_del_icon(wpa_s, NULL, NULL); 6707 6708 used = hwaddr_aton2(cmd, dst_addr); 6709 if (used < 0) 6710 return -1; 6711 6712 while (cmd[used] == ' ') 6713 used++; 6714 icon = cmd[used] ? &cmd[used] : NULL; 6715 6716 return hs20_del_icon(wpa_s, dst_addr, icon); 6717} 6718 6719 6720static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem) 6721{ 6722 u8 dst_addr[ETH_ALEN]; 6723 int used; 6724 char *icon; 6725 6726 used = hwaddr_aton2(cmd, dst_addr); 6727 if (used < 0) 6728 return -1; 6729 6730 while (cmd[used] == ' ') 6731 used++; 6732 icon = &cmd[used]; 6733 6734 wpa_s->fetch_osu_icon_in_progress = 0; 6735 return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), 6736 (u8 *) icon, os_strlen(icon), inmem); 6737} 6738 6739#endif /* CONFIG_HS20 */ 6740 6741 6742#ifdef CONFIG_AUTOSCAN 6743 6744static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, 6745 char *cmd) 6746{ 6747 enum wpa_states state = wpa_s->wpa_state; 6748 char *new_params = NULL; 6749 6750 if (os_strlen(cmd) > 0) { 6751 new_params = os_strdup(cmd); 6752 if (new_params == NULL) 6753 return -1; 6754 } 6755 6756 os_free(wpa_s->conf->autoscan); 6757 wpa_s->conf->autoscan = new_params; 6758 6759 if (wpa_s->conf->autoscan == NULL) 6760 autoscan_deinit(wpa_s); 6761 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) 6762 autoscan_init(wpa_s, 1); 6763 else if (state == WPA_SCANNING) 6764 wpa_supplicant_reinit_autoscan(wpa_s); 6765 6766 return 0; 6767} 6768 6769#endif /* CONFIG_AUTOSCAN */ 6770 6771 6772#ifdef CONFIG_WNM 6773 6774static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) 6775{ 6776 int enter; 6777 int intval = 0; 6778 char *pos; 6779 int ret; 6780 struct wpabuf *tfs_req = NULL; 6781 6782 if (os_strncmp(cmd, "enter", 5) == 0) 6783 enter = 1; 6784 else if (os_strncmp(cmd, "exit", 4) == 0) 6785 enter = 0; 6786 else 6787 return -1; 6788 6789 pos = os_strstr(cmd, " interval="); 6790 if (pos) 6791 intval = atoi(pos + 10); 6792 6793 pos = os_strstr(cmd, " tfs_req="); 6794 if (pos) { 6795 char *end; 6796 size_t len; 6797 pos += 9; 6798 end = os_strchr(pos, ' '); 6799 if (end) 6800 len = end - pos; 6801 else 6802 len = os_strlen(pos); 6803 if (len & 1) 6804 return -1; 6805 len /= 2; 6806 tfs_req = wpabuf_alloc(len); 6807 if (tfs_req == NULL) 6808 return -1; 6809 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) { 6810 wpabuf_free(tfs_req); 6811 return -1; 6812 } 6813 } 6814 6815 ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER : 6816 WNM_SLEEP_MODE_EXIT, intval, 6817 tfs_req); 6818 wpabuf_free(tfs_req); 6819 6820 return ret; 6821} 6822 6823 6824static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) 6825{ 6826 int query_reason, list = 0; 6827 6828 query_reason = atoi(cmd); 6829 6830 cmd = os_strchr(cmd, ' '); 6831 if (cmd) { 6832 cmd++; 6833 if (os_strncmp(cmd, "list", 4) == 0) { 6834 list = 1; 6835 } else { 6836 wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s", 6837 cmd); 6838 return -1; 6839 } 6840 } 6841 6842 wpa_printf(MSG_DEBUG, 6843 "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s", 6844 query_reason, list ? " candidate list" : ""); 6845 6846 return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list); 6847} 6848 6849#endif /* CONFIG_WNM */ 6850 6851 6852static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, 6853 size_t buflen) 6854{ 6855 struct wpa_signal_info si; 6856 int ret; 6857 char *pos, *end; 6858 6859 ret = wpa_drv_signal_poll(wpa_s, &si); 6860 if (ret) 6861 return -1; 6862 6863 pos = buf; 6864 end = buf + buflen; 6865 6866 ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n" 6867 "NOISE=%d\nFREQUENCY=%u\n", 6868 si.current_signal, si.current_txrate / 1000, 6869 si.current_noise, si.frequency); 6870 if (os_snprintf_error(end - pos, ret)) 6871 return -1; 6872 pos += ret; 6873 6874 if (si.chanwidth != CHAN_WIDTH_UNKNOWN) { 6875 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", 6876 channel_width_to_string(si.chanwidth)); 6877 if (os_snprintf_error(end - pos, ret)) 6878 return -1; 6879 pos += ret; 6880 } 6881 6882 if (si.center_frq1 > 0 && si.center_frq2 > 0) { 6883 ret = os_snprintf(pos, end - pos, 6884 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n", 6885 si.center_frq1, si.center_frq2); 6886 if (os_snprintf_error(end - pos, ret)) 6887 return -1; 6888 pos += ret; 6889 } 6890 6891 if (si.avg_signal) { 6892 ret = os_snprintf(pos, end - pos, 6893 "AVG_RSSI=%d\n", si.avg_signal); 6894 if (os_snprintf_error(end - pos, ret)) 6895 return -1; 6896 pos += ret; 6897 } 6898 6899 if (si.avg_beacon_signal) { 6900 ret = os_snprintf(pos, end - pos, 6901 "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal); 6902 if (os_snprintf_error(end - pos, ret)) 6903 return -1; 6904 pos += ret; 6905 } 6906 6907 return pos - buf; 6908} 6909 6910 6911static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, 6912 const char *cmd) 6913{ 6914 const char *pos; 6915 int threshold = 0; 6916 int hysteresis = 0; 6917 6918 if (wpa_s->bgscan && wpa_s->bgscan_priv) { 6919 wpa_printf(MSG_DEBUG, 6920 "Reject SIGNAL_MONITOR command - bgscan is active"); 6921 return -1; 6922 } 6923 pos = os_strstr(cmd, "THRESHOLD="); 6924 if (pos) 6925 threshold = atoi(pos + 10); 6926 pos = os_strstr(cmd, "HYSTERESIS="); 6927 if (pos) 6928 hysteresis = atoi(pos + 11); 6929 return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis); 6930} 6931 6932 6933static int wpas_ctrl_iface_get_pref_freq_list( 6934 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) 6935{ 6936 unsigned int freq_list[100], num = 100, i; 6937 int ret; 6938 enum wpa_driver_if_type iface_type; 6939 char *pos, *end; 6940 6941 pos = buf; 6942 end = buf + buflen; 6943 6944 /* buf: "<interface_type>" */ 6945 if (os_strcmp(cmd, "STATION") == 0) 6946 iface_type = WPA_IF_STATION; 6947 else if (os_strcmp(cmd, "AP") == 0) 6948 iface_type = WPA_IF_AP_BSS; 6949 else if (os_strcmp(cmd, "P2P_GO") == 0) 6950 iface_type = WPA_IF_P2P_GO; 6951 else if (os_strcmp(cmd, "P2P_CLIENT") == 0) 6952 iface_type = WPA_IF_P2P_CLIENT; 6953 else if (os_strcmp(cmd, "IBSS") == 0) 6954 iface_type = WPA_IF_IBSS; 6955 else if (os_strcmp(cmd, "TDLS") == 0) 6956 iface_type = WPA_IF_TDLS; 6957 else 6958 return -1; 6959 6960 wpa_printf(MSG_DEBUG, 6961 "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)", 6962 iface_type, buf); 6963 6964 ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list); 6965 if (ret) 6966 return -1; 6967 6968 for (i = 0; i < num; i++) { 6969 ret = os_snprintf(pos, end - pos, "%s%u", 6970 i > 0 ? "," : "", freq_list[i]); 6971 if (os_snprintf_error(end - pos, ret)) 6972 return -1; 6973 pos += ret; 6974 } 6975 6976 return pos - buf; 6977} 6978 6979 6980static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s, 6981 char *buf, size_t buflen) 6982{ 6983 int ret, i; 6984 char *pos, *end; 6985 6986 ret = os_snprintf(buf, buflen, "%016llX:\n", 6987 (long long unsigned) wpa_s->drv_flags); 6988 if (os_snprintf_error(buflen, ret)) 6989 return -1; 6990 6991 pos = buf + ret; 6992 end = buf + buflen; 6993 6994 for (i = 0; i < 64; i++) { 6995 if (wpa_s->drv_flags & (1LLU << i)) { 6996 ret = os_snprintf(pos, end - pos, "%s\n", 6997 driver_flag_to_string(1LLU << i)); 6998 if (os_snprintf_error(end - pos, ret)) 6999 return -1; 7000 pos += ret; 7001 } 7002 } 7003 7004 return pos - buf; 7005} 7006 7007 7008static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, 7009 size_t buflen) 7010{ 7011 struct hostap_sta_driver_data sta; 7012 int ret; 7013 7014 ret = wpa_drv_pktcnt_poll(wpa_s, &sta); 7015 if (ret) 7016 return -1; 7017 7018 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n", 7019 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets); 7020 if (os_snprintf_error(buflen, ret)) 7021 return -1; 7022 return ret; 7023} 7024 7025 7026#ifdef ANDROID 7027static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, 7028 char *buf, size_t buflen) 7029{ 7030 int ret; 7031 7032 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen); 7033 if (ret == 0) { 7034 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { 7035 struct p2p_data *p2p = wpa_s->global->p2p; 7036 if (p2p) { 7037 char country[3]; 7038 country[0] = cmd[8]; 7039 country[1] = cmd[9]; 7040 country[2] = 0x04; 7041 p2p_set_country(p2p, country); 7042 } 7043 } 7044 ret = os_snprintf(buf, buflen, "%s\n", "OK"); 7045 if (os_snprintf_error(buflen, ret)) 7046 ret = -1; 7047 } 7048 return ret; 7049} 7050#endif /* ANDROID */ 7051 7052 7053static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, 7054 char *buf, size_t buflen) 7055{ 7056 int ret; 7057 char *pos; 7058 u8 *data = NULL; 7059 unsigned int vendor_id, subcmd; 7060 struct wpabuf *reply; 7061 size_t data_len = 0; 7062 7063 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ 7064 vendor_id = strtoul(cmd, &pos, 16); 7065 if (!isblank((unsigned char) *pos)) 7066 return -EINVAL; 7067 7068 subcmd = strtoul(pos, &pos, 10); 7069 7070 if (*pos != '\0') { 7071 if (!isblank((unsigned char) *pos++)) 7072 return -EINVAL; 7073 data_len = os_strlen(pos); 7074 } 7075 7076 if (data_len) { 7077 data_len /= 2; 7078 data = os_malloc(data_len); 7079 if (!data) 7080 return -1; 7081 7082 if (hexstr2bin(pos, data, data_len)) { 7083 wpa_printf(MSG_DEBUG, 7084 "Vendor command: wrong parameter format"); 7085 os_free(data); 7086 return -EINVAL; 7087 } 7088 } 7089 7090 reply = wpabuf_alloc((buflen - 1) / 2); 7091 if (!reply) { 7092 os_free(data); 7093 return -1; 7094 } 7095 7096 ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len, 7097 reply); 7098 7099 if (ret == 0) 7100 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), 7101 wpabuf_len(reply)); 7102 7103 wpabuf_free(reply); 7104 os_free(data); 7105 7106 return ret; 7107} 7108 7109 7110static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) 7111{ 7112#ifdef CONFIG_P2P 7113 struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ? 7114 wpa_s->global->p2p_init_wpa_s : wpa_s; 7115#endif /* CONFIG_P2P */ 7116 7117 wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); 7118 7119 wpas_abort_ongoing_scan(wpa_s); 7120 7121 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { 7122 /* 7123 * Avoid possible auto connect re-connection on getting 7124 * disconnected due to state flush. 7125 */ 7126 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 7127 } 7128 7129#ifdef CONFIG_P2P 7130 wpas_p2p_group_remove(p2p_wpa_s, "*"); 7131 wpas_p2p_cancel(p2p_wpa_s); 7132 p2p_ctrl_flush(p2p_wpa_s); 7133 wpas_p2p_service_flush(p2p_wpa_s); 7134 p2p_wpa_s->global->p2p_disabled = 0; 7135 p2p_wpa_s->global->p2p_per_sta_psk = 0; 7136 p2p_wpa_s->conf->num_sec_device_types = 0; 7137 p2p_wpa_s->p2p_disable_ip_addr_req = 0; 7138 os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range); 7139 p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL; 7140 p2p_wpa_s->global->p2p_go_avoid_freq.num = 0; 7141 p2p_wpa_s->global->pending_p2ps_group = 0; 7142 p2p_wpa_s->global->pending_p2ps_group_freq = 0; 7143#endif /* CONFIG_P2P */ 7144 7145#ifdef CONFIG_WPS_TESTING 7146 wps_version_number = 0x20; 7147 wps_testing_dummy_cred = 0; 7148 wps_corrupt_pkhash = 0; 7149 wps_force_auth_types_in_use = 0; 7150 wps_force_encr_types_in_use = 0; 7151#endif /* CONFIG_WPS_TESTING */ 7152#ifdef CONFIG_WPS 7153 wpa_s->wps_fragment_size = 0; 7154 wpas_wps_cancel(wpa_s); 7155 wps_registrar_flush(wpa_s->wps->registrar); 7156#endif /* CONFIG_WPS */ 7157 wpa_s->after_wps = 0; 7158 wpa_s->known_wps_freq = 0; 7159 7160#ifdef CONFIG_TDLS 7161#ifdef CONFIG_TDLS_TESTING 7162 tdls_testing = 0; 7163#endif /* CONFIG_TDLS_TESTING */ 7164 wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); 7165 wpa_tdls_enable(wpa_s->wpa, 1); 7166#endif /* CONFIG_TDLS */ 7167 7168 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); 7169 wpa_supplicant_stop_countermeasures(wpa_s, NULL); 7170 7171 wpa_s->no_keep_alive = 0; 7172 wpa_s->own_disconnect_req = 0; 7173 7174 os_free(wpa_s->disallow_aps_bssid); 7175 wpa_s->disallow_aps_bssid = NULL; 7176 wpa_s->disallow_aps_bssid_count = 0; 7177 os_free(wpa_s->disallow_aps_ssid); 7178 wpa_s->disallow_aps_ssid = NULL; 7179 wpa_s->disallow_aps_ssid_count = 0; 7180 7181 wpa_s->set_sta_uapsd = 0; 7182 wpa_s->sta_uapsd = 0; 7183 7184 wpa_drv_radio_disable(wpa_s, 0); 7185 wpa_blacklist_clear(wpa_s); 7186 wpa_s->extra_blacklist_count = 0; 7187 wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all"); 7188 wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all"); 7189 wpa_config_flush_blobs(wpa_s->conf); 7190 wpa_s->conf->auto_interworking = 0; 7191 wpa_s->conf->okc = 0; 7192 7193 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); 7194 rsn_preauth_deinit(wpa_s->wpa); 7195 7196 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200); 7197 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70); 7198 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60); 7199 eapol_sm_notify_logoff(wpa_s->eapol, FALSE); 7200 7201 radio_remove_works(wpa_s, NULL, 1); 7202 wpa_s->ext_work_in_progress = 0; 7203 7204 wpa_s->next_ssid = NULL; 7205 7206#ifdef CONFIG_INTERWORKING 7207#ifdef CONFIG_HS20 7208 hs20_cancel_fetch_osu(wpa_s); 7209 hs20_del_icon(wpa_s, NULL, NULL); 7210#endif /* CONFIG_HS20 */ 7211#endif /* CONFIG_INTERWORKING */ 7212 7213 wpa_s->ext_mgmt_frame_handling = 0; 7214 wpa_s->ext_eapol_frame_io = 0; 7215#ifdef CONFIG_TESTING_OPTIONS 7216 wpa_s->extra_roc_dur = 0; 7217 wpa_s->test_failure = WPAS_TEST_FAILURE_NONE; 7218 wpa_s->p2p_go_csa_on_inv = 0; 7219 wpa_s->ignore_auth_resp = 0; 7220 wpa_s->ignore_assoc_disallow = 0; 7221 wpa_s->reject_btm_req_reason = 0; 7222 wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); 7223#endif /* CONFIG_TESTING_OPTIONS */ 7224 7225 wpa_s->disconnected = 0; 7226 os_free(wpa_s->next_scan_freqs); 7227 wpa_s->next_scan_freqs = NULL; 7228 7229 wpa_bss_flush(wpa_s); 7230 if (!dl_list_empty(&wpa_s->bss)) { 7231 wpa_printf(MSG_DEBUG, 7232 "BSS table not empty after flush: %u entries, current_bss=%p bssid=" 7233 MACSTR " pending_bssid=" MACSTR, 7234 dl_list_len(&wpa_s->bss), wpa_s->current_bss, 7235 MAC2STR(wpa_s->bssid), 7236 MAC2STR(wpa_s->pending_bssid)); 7237 } 7238 7239 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); 7240 wpa_s->wnmsleep_used = 0; 7241 7242#ifdef CONFIG_SME 7243 wpa_s->sme.last_unprot_disconnect.sec = 0; 7244#endif /* CONFIG_SME */ 7245} 7246 7247 7248static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, 7249 char *buf, size_t buflen) 7250{ 7251 struct wpa_radio_work *work; 7252 char *pos, *end; 7253 struct os_reltime now, diff; 7254 7255 pos = buf; 7256 end = buf + buflen; 7257 7258 os_get_reltime(&now); 7259 7260 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) 7261 { 7262 int ret; 7263 7264 os_reltime_sub(&now, &work->time, &diff); 7265 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", 7266 work->type, work->wpa_s->ifname, work->freq, 7267 work->started, diff.sec, diff.usec); 7268 if (os_snprintf_error(end - pos, ret)) 7269 break; 7270 pos += ret; 7271 } 7272 7273 return pos - buf; 7274} 7275 7276 7277static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx) 7278{ 7279 struct wpa_radio_work *work = eloop_ctx; 7280 struct wpa_external_work *ework = work->ctx; 7281 7282 wpa_dbg(work->wpa_s, MSG_DEBUG, 7283 "Timing out external radio work %u (%s)", 7284 ework->id, work->type); 7285 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id); 7286 work->wpa_s->ext_work_in_progress = 0; 7287 radio_work_done(work); 7288 os_free(ework); 7289} 7290 7291 7292static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) 7293{ 7294 struct wpa_external_work *ework = work->ctx; 7295 7296 if (deinit) { 7297 if (work->started) 7298 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, 7299 work, NULL); 7300 7301 /* 7302 * work->type points to a buffer in ework, so need to replace 7303 * that here with a fixed string to avoid use of freed memory 7304 * in debug prints. 7305 */ 7306 work->type = "freed-ext-work"; 7307 work->ctx = NULL; 7308 os_free(ework); 7309 return; 7310 } 7311 7312 wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)", 7313 ework->id, ework->type); 7314 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id); 7315 work->wpa_s->ext_work_in_progress = 1; 7316 if (!ework->timeout) 7317 ework->timeout = 10; 7318 eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout, 7319 work, NULL); 7320} 7321 7322 7323static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd, 7324 char *buf, size_t buflen) 7325{ 7326 struct wpa_external_work *ework; 7327 char *pos, *pos2; 7328 size_t type_len; 7329 int ret; 7330 unsigned int freq = 0; 7331 7332 /* format: <name> [freq=<MHz>] [timeout=<seconds>] */ 7333 7334 ework = os_zalloc(sizeof(*ework)); 7335 if (ework == NULL) 7336 return -1; 7337 7338 pos = os_strchr(cmd, ' '); 7339 if (pos) { 7340 type_len = pos - cmd; 7341 pos++; 7342 7343 pos2 = os_strstr(pos, "freq="); 7344 if (pos2) 7345 freq = atoi(pos2 + 5); 7346 7347 pos2 = os_strstr(pos, "timeout="); 7348 if (pos2) 7349 ework->timeout = atoi(pos2 + 8); 7350 } else { 7351 type_len = os_strlen(cmd); 7352 } 7353 if (4 + type_len >= sizeof(ework->type)) 7354 type_len = sizeof(ework->type) - 4 - 1; 7355 os_strlcpy(ework->type, "ext:", sizeof(ework->type)); 7356 os_memcpy(ework->type + 4, cmd, type_len); 7357 ework->type[4 + type_len] = '\0'; 7358 7359 wpa_s->ext_work_id++; 7360 if (wpa_s->ext_work_id == 0) 7361 wpa_s->ext_work_id++; 7362 ework->id = wpa_s->ext_work_id; 7363 7364 if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb, 7365 ework) < 0) { 7366 os_free(ework); 7367 return -1; 7368 } 7369 7370 ret = os_snprintf(buf, buflen, "%u", ework->id); 7371 if (os_snprintf_error(buflen, ret)) 7372 return -1; 7373 return ret; 7374} 7375 7376 7377static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd) 7378{ 7379 struct wpa_radio_work *work; 7380 unsigned int id = atoi(cmd); 7381 7382 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) 7383 { 7384 struct wpa_external_work *ework; 7385 7386 if (os_strncmp(work->type, "ext:", 4) != 0) 7387 continue; 7388 ework = work->ctx; 7389 if (id && ework->id != id) 7390 continue; 7391 wpa_dbg(wpa_s, MSG_DEBUG, 7392 "Completed external radio work %u (%s)", 7393 ework->id, ework->type); 7394 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); 7395 wpa_s->ext_work_in_progress = 0; 7396 radio_work_done(work); 7397 os_free(ework); 7398 return 3; /* "OK\n" */ 7399 } 7400 7401 return -1; 7402} 7403 7404 7405static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd, 7406 char *buf, size_t buflen) 7407{ 7408 if (os_strcmp(cmd, "show") == 0) 7409 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen); 7410 if (os_strncmp(cmd, "add ", 4) == 0) 7411 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen); 7412 if (os_strncmp(cmd, "done ", 5) == 0) 7413 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4); 7414 return -1; 7415} 7416 7417 7418void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) 7419{ 7420 struct wpa_radio_work *work, *tmp; 7421 7422 if (!wpa_s || !wpa_s->radio) 7423 return; 7424 7425 dl_list_for_each_safe(work, tmp, &wpa_s->radio->work, 7426 struct wpa_radio_work, list) { 7427 struct wpa_external_work *ework; 7428 7429 if (os_strncmp(work->type, "ext:", 4) != 0) 7430 continue; 7431 ework = work->ctx; 7432 wpa_dbg(wpa_s, MSG_DEBUG, 7433 "Flushing%s external radio work %u (%s)", 7434 work->started ? " started" : "", ework->id, 7435 ework->type); 7436 if (work->started) 7437 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, 7438 work, NULL); 7439 radio_work_done(work); 7440 os_free(ework); 7441 } 7442} 7443 7444 7445static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) 7446{ 7447 struct wpa_supplicant *wpa_s = eloop_ctx; 7448 eapol_sm_notify_ctrl_response(wpa_s->eapol); 7449} 7450 7451 7452static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value, 7453 unsigned int *scan_id_count, int scan_id[]) 7454{ 7455 const char *pos = value; 7456 7457 while (pos) { 7458 if (*pos == ' ' || *pos == '\0') 7459 break; 7460 if (*scan_id_count == MAX_SCAN_ID) 7461 return -1; 7462 scan_id[(*scan_id_count)++] = atoi(pos); 7463 pos = os_strchr(pos, ','); 7464 if (pos) 7465 pos++; 7466 } 7467 7468 return 0; 7469} 7470 7471 7472static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, 7473 char *reply, int reply_size, int *reply_len) 7474{ 7475 char *pos; 7476 unsigned int manual_scan_passive = 0; 7477 unsigned int manual_scan_use_id = 0; 7478 unsigned int manual_scan_only_new = 0; 7479 unsigned int scan_only = 0; 7480 unsigned int scan_id_count = 0; 7481 int scan_id[MAX_SCAN_ID]; 7482 void (*scan_res_handler)(struct wpa_supplicant *wpa_s, 7483 struct wpa_scan_results *scan_res); 7484 int *manual_scan_freqs = NULL; 7485 struct wpa_ssid_value *ssid = NULL, *ns; 7486 unsigned int ssid_count = 0; 7487 7488 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 7489 *reply_len = -1; 7490 return; 7491 } 7492 7493 if (radio_work_pending(wpa_s, "scan")) { 7494 wpa_printf(MSG_DEBUG, 7495 "Pending scan scheduled - reject new request"); 7496 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 7497 return; 7498 } 7499 7500#ifdef CONFIG_INTERWORKING 7501 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) { 7502 wpa_printf(MSG_DEBUG, 7503 "Interworking select in progress - reject new scan"); 7504 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 7505 return; 7506 } 7507#endif /* CONFIG_INTERWORKING */ 7508 7509 if (params) { 7510 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) 7511 scan_only = 1; 7512 7513 pos = os_strstr(params, "freq="); 7514 if (pos) { 7515 manual_scan_freqs = freq_range_to_channel_list(wpa_s, 7516 pos + 5); 7517 if (manual_scan_freqs == NULL) { 7518 *reply_len = -1; 7519 goto done; 7520 } 7521 } 7522 7523 pos = os_strstr(params, "passive="); 7524 if (pos) 7525 manual_scan_passive = !!atoi(pos + 8); 7526 7527 pos = os_strstr(params, "use_id="); 7528 if (pos) 7529 manual_scan_use_id = atoi(pos + 7); 7530 7531 pos = os_strstr(params, "only_new=1"); 7532 if (pos) 7533 manual_scan_only_new = 1; 7534 7535 pos = os_strstr(params, "scan_id="); 7536 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count, 7537 scan_id) < 0) { 7538 *reply_len = -1; 7539 goto done; 7540 } 7541 7542 pos = params; 7543 while (pos && *pos != '\0') { 7544 if (os_strncmp(pos, "ssid ", 5) == 0) { 7545 char *end; 7546 7547 pos += 5; 7548 end = pos; 7549 while (*end) { 7550 if (*end == '\0' || *end == ' ') 7551 break; 7552 end++; 7553 } 7554 7555 ns = os_realloc_array( 7556 ssid, ssid_count + 1, 7557 sizeof(struct wpa_ssid_value)); 7558 if (ns == NULL) { 7559 *reply_len = -1; 7560 goto done; 7561 } 7562 ssid = ns; 7563 7564 if ((end - pos) & 0x01 || 7565 end - pos > 2 * SSID_MAX_LEN || 7566 hexstr2bin(pos, ssid[ssid_count].ssid, 7567 (end - pos) / 2) < 0) { 7568 wpa_printf(MSG_DEBUG, 7569 "Invalid SSID value '%s'", 7570 pos); 7571 *reply_len = -1; 7572 goto done; 7573 } 7574 ssid[ssid_count].ssid_len = (end - pos) / 2; 7575 wpa_hexdump_ascii(MSG_DEBUG, "scan SSID", 7576 ssid[ssid_count].ssid, 7577 ssid[ssid_count].ssid_len); 7578 ssid_count++; 7579 pos = end; 7580 } 7581 7582 pos = os_strchr(pos, ' '); 7583 if (pos) 7584 pos++; 7585 } 7586 } 7587 7588 wpa_s->num_ssids_from_scan_req = ssid_count; 7589 os_free(wpa_s->ssids_from_scan_req); 7590 if (ssid_count) { 7591 wpa_s->ssids_from_scan_req = ssid; 7592 ssid = NULL; 7593 } else { 7594 wpa_s->ssids_from_scan_req = NULL; 7595 } 7596 7597 if (scan_only) 7598 scan_res_handler = scan_only_handler; 7599 else if (wpa_s->scan_res_handler == scan_only_handler) 7600 scan_res_handler = NULL; 7601 else 7602 scan_res_handler = wpa_s->scan_res_handler; 7603 7604 if (!wpa_s->sched_scanning && !wpa_s->scanning && 7605 ((wpa_s->wpa_state <= WPA_SCANNING) || 7606 (wpa_s->wpa_state == WPA_COMPLETED))) { 7607 wpa_s->manual_scan_passive = manual_scan_passive; 7608 wpa_s->manual_scan_use_id = manual_scan_use_id; 7609 wpa_s->manual_scan_only_new = manual_scan_only_new; 7610 wpa_s->scan_id_count = scan_id_count; 7611 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); 7612 wpa_s->scan_res_handler = scan_res_handler; 7613 os_free(wpa_s->manual_scan_freqs); 7614 wpa_s->manual_scan_freqs = manual_scan_freqs; 7615 manual_scan_freqs = NULL; 7616 7617 wpa_s->normal_scans = 0; 7618 wpa_s->scan_req = MANUAL_SCAN_REQ; 7619 wpa_s->after_wps = 0; 7620 wpa_s->known_wps_freq = 0; 7621 wpa_supplicant_req_scan(wpa_s, 0, 0); 7622 if (wpa_s->manual_scan_use_id) { 7623 wpa_s->manual_scan_id++; 7624 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", 7625 wpa_s->manual_scan_id); 7626 *reply_len = os_snprintf(reply, reply_size, "%u\n", 7627 wpa_s->manual_scan_id); 7628 } 7629 } else if (wpa_s->sched_scanning) { 7630 wpa_s->manual_scan_passive = manual_scan_passive; 7631 wpa_s->manual_scan_use_id = manual_scan_use_id; 7632 wpa_s->manual_scan_only_new = manual_scan_only_new; 7633 wpa_s->scan_id_count = scan_id_count; 7634 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); 7635 wpa_s->scan_res_handler = scan_res_handler; 7636 os_free(wpa_s->manual_scan_freqs); 7637 wpa_s->manual_scan_freqs = manual_scan_freqs; 7638 manual_scan_freqs = NULL; 7639 7640 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); 7641 wpa_supplicant_cancel_sched_scan(wpa_s); 7642 wpa_s->scan_req = MANUAL_SCAN_REQ; 7643 wpa_supplicant_req_scan(wpa_s, 0, 0); 7644 if (wpa_s->manual_scan_use_id) { 7645 wpa_s->manual_scan_id++; 7646 *reply_len = os_snprintf(reply, reply_size, "%u\n", 7647 wpa_s->manual_scan_id); 7648 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", 7649 wpa_s->manual_scan_id); 7650 } 7651 } else { 7652 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); 7653 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); 7654 } 7655 7656done: 7657 os_free(manual_scan_freqs); 7658 os_free(ssid); 7659} 7660 7661 7662#ifdef CONFIG_TESTING_OPTIONS 7663 7664static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s, 7665 unsigned int freq, const u8 *dst, 7666 const u8 *src, const u8 *bssid, 7667 const u8 *data, size_t data_len, 7668 enum offchannel_send_action_result 7669 result) 7670{ 7671 wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR 7672 " src=" MACSTR " bssid=" MACSTR " result=%s", 7673 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), 7674 result == OFFCHANNEL_SEND_ACTION_SUCCESS ? 7675 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? 7676 "NO_ACK" : "FAILED")); 7677} 7678 7679 7680static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd) 7681{ 7682 char *pos, *param; 7683 size_t len; 7684 u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN]; 7685 int res, used; 7686 int freq = 0, no_cck = 0, wait_time = 0; 7687 7688 /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1] 7689 * <action=Action frame payload> */ 7690 7691 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); 7692 7693 pos = cmd; 7694 used = hwaddr_aton2(pos, da); 7695 if (used < 0) 7696 return -1; 7697 pos += used; 7698 while (*pos == ' ') 7699 pos++; 7700 used = hwaddr_aton2(pos, bssid); 7701 if (used < 0) 7702 return -1; 7703 pos += used; 7704 7705 param = os_strstr(pos, " freq="); 7706 if (param) { 7707 param += 6; 7708 freq = atoi(param); 7709 } 7710 7711 param = os_strstr(pos, " no_cck="); 7712 if (param) { 7713 param += 8; 7714 no_cck = atoi(param); 7715 } 7716 7717 param = os_strstr(pos, " wait_time="); 7718 if (param) { 7719 param += 11; 7720 wait_time = atoi(param); 7721 } 7722 7723 param = os_strstr(pos, " action="); 7724 if (param == NULL) 7725 return -1; 7726 param += 8; 7727 7728 len = os_strlen(param); 7729 if (len & 1) 7730 return -1; 7731 len /= 2; 7732 7733 buf = os_malloc(len); 7734 if (buf == NULL) 7735 return -1; 7736 7737 if (hexstr2bin(param, buf, len) < 0) { 7738 os_free(buf); 7739 return -1; 7740 } 7741 7742 res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid, 7743 buf, len, wait_time, 7744 wpas_ctrl_iface_mgmt_tx_cb, no_cck); 7745 os_free(buf); 7746 return res; 7747} 7748 7749 7750static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) 7751{ 7752 wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting"); 7753 offchannel_send_action_done(wpa_s); 7754} 7755 7756 7757static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, 7758 char *cmd) 7759{ 7760 char *pos, *param; 7761 size_t len; 7762 u8 *buf; 7763 int freq = 0, datarate = 0, ssi_signal = 0; 7764 union wpa_event_data event; 7765 7766 if (!wpa_s->ext_mgmt_frame_handling) 7767 return -1; 7768 7769 /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */ 7770 7771 wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd); 7772 7773 pos = cmd; 7774 param = os_strstr(pos, "freq="); 7775 if (param) { 7776 param += 5; 7777 freq = atoi(param); 7778 } 7779 7780 param = os_strstr(pos, " datarate="); 7781 if (param) { 7782 param += 10; 7783 datarate = atoi(param); 7784 } 7785 7786 param = os_strstr(pos, " ssi_signal="); 7787 if (param) { 7788 param += 12; 7789 ssi_signal = atoi(param); 7790 } 7791 7792 param = os_strstr(pos, " frame="); 7793 if (param == NULL) 7794 return -1; 7795 param += 7; 7796 7797 len = os_strlen(param); 7798 if (len & 1) 7799 return -1; 7800 len /= 2; 7801 7802 buf = os_malloc(len); 7803 if (buf == NULL) 7804 return -1; 7805 7806 if (hexstr2bin(param, buf, len) < 0) { 7807 os_free(buf); 7808 return -1; 7809 } 7810 7811 os_memset(&event, 0, sizeof(event)); 7812 event.rx_mgmt.freq = freq; 7813 event.rx_mgmt.frame = buf; 7814 event.rx_mgmt.frame_len = len; 7815 event.rx_mgmt.ssi_signal = ssi_signal; 7816 event.rx_mgmt.datarate = datarate; 7817 wpa_s->ext_mgmt_frame_handling = 0; 7818 wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event); 7819 wpa_s->ext_mgmt_frame_handling = 1; 7820 7821 os_free(buf); 7822 7823 return 0; 7824} 7825 7826 7827static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) 7828{ 7829 char *pos, *param; 7830 union wpa_event_data event; 7831 enum wpa_event_type ev; 7832 7833 /* <event name> [parameters..] */ 7834 7835 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd); 7836 7837 pos = cmd; 7838 param = os_strchr(pos, ' '); 7839 if (param) 7840 *param++ = '\0'; 7841 7842 os_memset(&event, 0, sizeof(event)); 7843 7844 if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) { 7845 ev = EVENT_INTERFACE_ENABLED; 7846 } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) { 7847 ev = EVENT_INTERFACE_DISABLED; 7848 } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) { 7849 ev = EVENT_AVOID_FREQUENCIES; 7850 if (param == NULL) 7851 param = ""; 7852 if (freq_range_list_parse(&event.freq_range, param) < 0) 7853 return -1; 7854 wpa_supplicant_event(wpa_s, ev, &event); 7855 os_free(event.freq_range.range); 7856 return 0; 7857 } else { 7858 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", 7859 cmd); 7860 return -1; 7861 } 7862 7863 wpa_supplicant_event(wpa_s, ev, &event); 7864 7865 return 0; 7866} 7867 7868 7869static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd) 7870{ 7871 char *pos; 7872 u8 src[ETH_ALEN], *buf; 7873 int used; 7874 size_t len; 7875 7876 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); 7877 7878 pos = cmd; 7879 used = hwaddr_aton2(pos, src); 7880 if (used < 0) 7881 return -1; 7882 pos += used; 7883 while (*pos == ' ') 7884 pos++; 7885 7886 len = os_strlen(pos); 7887 if (len & 1) 7888 return -1; 7889 len /= 2; 7890 7891 buf = os_malloc(len); 7892 if (buf == NULL) 7893 return -1; 7894 7895 if (hexstr2bin(pos, buf, len) < 0) { 7896 os_free(buf); 7897 return -1; 7898 } 7899 7900 wpa_supplicant_rx_eapol(wpa_s, src, buf, len); 7901 os_free(buf); 7902 7903 return 0; 7904} 7905 7906 7907static u16 ipv4_hdr_checksum(const void *buf, size_t len) 7908{ 7909 size_t i; 7910 u32 sum = 0; 7911 const u16 *pos = buf; 7912 7913 for (i = 0; i < len / 2; i++) 7914 sum += *pos++; 7915 7916 while (sum >> 16) 7917 sum = (sum & 0xffff) + (sum >> 16); 7918 7919 return sum ^ 0xffff; 7920} 7921 7922 7923#define HWSIM_PACKETLEN 1500 7924#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) 7925 7926static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, 7927 size_t len) 7928{ 7929 struct wpa_supplicant *wpa_s = ctx; 7930 const struct ether_header *eth; 7931 struct iphdr ip; 7932 const u8 *pos; 7933 unsigned int i; 7934 7935 if (len != HWSIM_PACKETLEN) 7936 return; 7937 7938 eth = (const struct ether_header *) buf; 7939 os_memcpy(&ip, eth + 1, sizeof(ip)); 7940 pos = &buf[sizeof(*eth) + sizeof(ip)]; 7941 7942 if (ip.ihl != 5 || ip.version != 4 || 7943 ntohs(ip.tot_len) != HWSIM_IP_LEN) 7944 return; 7945 7946 for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) { 7947 if (*pos != (u8) i) 7948 return; 7949 pos++; 7950 } 7951 7952 wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR, 7953 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost)); 7954} 7955 7956 7957static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, 7958 char *cmd) 7959{ 7960 int enabled = atoi(cmd); 7961 char *pos; 7962 const char *ifname; 7963 7964 if (!enabled) { 7965 if (wpa_s->l2_test) { 7966 l2_packet_deinit(wpa_s->l2_test); 7967 wpa_s->l2_test = NULL; 7968 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled"); 7969 } 7970 return 0; 7971 } 7972 7973 if (wpa_s->l2_test) 7974 return 0; 7975 7976 pos = os_strstr(cmd, " ifname="); 7977 if (pos) 7978 ifname = pos + 8; 7979 else 7980 ifname = wpa_s->ifname; 7981 7982 wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr, 7983 ETHERTYPE_IP, wpas_data_test_rx, 7984 wpa_s, 1); 7985 if (wpa_s->l2_test == NULL) 7986 return -1; 7987 7988 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled"); 7989 7990 return 0; 7991} 7992 7993 7994static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) 7995{ 7996 u8 dst[ETH_ALEN], src[ETH_ALEN]; 7997 char *pos; 7998 int used; 7999 long int val; 8000 u8 tos; 8001 u8 buf[2 + HWSIM_PACKETLEN]; 8002 struct ether_header *eth; 8003 struct iphdr *ip; 8004 u8 *dpos; 8005 unsigned int i; 8006 8007 if (wpa_s->l2_test == NULL) 8008 return -1; 8009 8010 /* format: <dst> <src> <tos> */ 8011 8012 pos = cmd; 8013 used = hwaddr_aton2(pos, dst); 8014 if (used < 0) 8015 return -1; 8016 pos += used; 8017 while (*pos == ' ') 8018 pos++; 8019 used = hwaddr_aton2(pos, src); 8020 if (used < 0) 8021 return -1; 8022 pos += used; 8023 8024 val = strtol(pos, NULL, 0); 8025 if (val < 0 || val > 0xff) 8026 return -1; 8027 tos = val; 8028 8029 eth = (struct ether_header *) &buf[2]; 8030 os_memcpy(eth->ether_dhost, dst, ETH_ALEN); 8031 os_memcpy(eth->ether_shost, src, ETH_ALEN); 8032 eth->ether_type = htons(ETHERTYPE_IP); 8033 ip = (struct iphdr *) (eth + 1); 8034 os_memset(ip, 0, sizeof(*ip)); 8035 ip->ihl = 5; 8036 ip->version = 4; 8037 ip->ttl = 64; 8038 ip->tos = tos; 8039 ip->tot_len = htons(HWSIM_IP_LEN); 8040 ip->protocol = 1; 8041 ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); 8042 ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); 8043 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); 8044 dpos = (u8 *) (ip + 1); 8045 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) 8046 *dpos++ = i; 8047 8048 if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2], 8049 HWSIM_PACKETLEN) < 0) 8050 return -1; 8051 8052 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR 8053 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos); 8054 8055 return 0; 8056} 8057 8058 8059static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s, 8060 char *cmd) 8061{ 8062 u8 *buf; 8063 struct ether_header *eth; 8064 struct l2_packet_data *l2 = NULL; 8065 size_t len; 8066 u16 ethertype; 8067 int res = -1; 8068 8069 len = os_strlen(cmd); 8070 if (len & 1 || len < ETH_HLEN * 2) 8071 return -1; 8072 len /= 2; 8073 8074 buf = os_malloc(len); 8075 if (buf == NULL) 8076 return -1; 8077 8078 if (hexstr2bin(cmd, buf, len) < 0) 8079 goto done; 8080 8081 eth = (struct ether_header *) buf; 8082 ethertype = ntohs(eth->ether_type); 8083 8084 l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype, 8085 wpas_data_test_rx, wpa_s, 1); 8086 if (l2 == NULL) 8087 goto done; 8088 8089 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len); 8090 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res); 8091done: 8092 if (l2) 8093 l2_packet_deinit(l2); 8094 os_free(buf); 8095 8096 return res < 0 ? -1 : 0; 8097} 8098 8099 8100static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd) 8101{ 8102#ifdef WPA_TRACE_BFD 8103 char *pos; 8104 8105 wpa_trace_fail_after = atoi(cmd); 8106 pos = os_strchr(cmd, ':'); 8107 if (pos) { 8108 pos++; 8109 os_strlcpy(wpa_trace_fail_func, pos, 8110 sizeof(wpa_trace_fail_func)); 8111 } else { 8112 wpa_trace_fail_after = 0; 8113 } 8114 return 0; 8115#else /* WPA_TRACE_BFD */ 8116 return -1; 8117#endif /* WPA_TRACE_BFD */ 8118} 8119 8120 8121static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, 8122 char *buf, size_t buflen) 8123{ 8124#ifdef WPA_TRACE_BFD 8125 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, 8126 wpa_trace_fail_func); 8127#else /* WPA_TRACE_BFD */ 8128 return -1; 8129#endif /* WPA_TRACE_BFD */ 8130} 8131 8132 8133static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) 8134{ 8135#ifdef WPA_TRACE_BFD 8136 char *pos; 8137 8138 wpa_trace_test_fail_after = atoi(cmd); 8139 pos = os_strchr(cmd, ':'); 8140 if (pos) { 8141 pos++; 8142 os_strlcpy(wpa_trace_test_fail_func, pos, 8143 sizeof(wpa_trace_test_fail_func)); 8144 } else { 8145 wpa_trace_test_fail_after = 0; 8146 } 8147 return 0; 8148#else /* WPA_TRACE_BFD */ 8149 return -1; 8150#endif /* WPA_TRACE_BFD */ 8151} 8152 8153 8154static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, 8155 char *buf, size_t buflen) 8156{ 8157#ifdef WPA_TRACE_BFD 8158 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, 8159 wpa_trace_test_fail_func); 8160#else /* WPA_TRACE_BFD */ 8161 return -1; 8162#endif /* WPA_TRACE_BFD */ 8163} 8164 8165 8166static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx) 8167{ 8168 struct wpa_supplicant *wpa_s = eloop_ctx; 8169 int i, count = (intptr_t) timeout_ctx; 8170 8171 wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages", 8172 count); 8173 for (i = 0; i < count; i++) { 8174 wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d", 8175 i + 1, count); 8176 } 8177} 8178 8179 8180static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) 8181{ 8182 int count; 8183 8184 count = atoi(cmd); 8185 if (count <= 0) 8186 return -1; 8187 8188 return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s, 8189 (void *) (intptr_t) count); 8190} 8191 8192 8193static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, 8194 const char *cmd) 8195{ 8196 struct wpabuf *buf; 8197 size_t len; 8198 8199 len = os_strlen(cmd); 8200 if (len & 1) 8201 return -1; 8202 len /= 2; 8203 8204 if (len == 0) { 8205 buf = NULL; 8206 } else { 8207 buf = wpabuf_alloc(len); 8208 if (buf == NULL) 8209 return -1; 8210 8211 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { 8212 wpabuf_free(buf); 8213 return -1; 8214 } 8215 } 8216 8217 wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); 8218 return 0; 8219} 8220 8221#endif /* CONFIG_TESTING_OPTIONS */ 8222 8223 8224static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) 8225{ 8226 char *pos = cmd; 8227 int frame; 8228 size_t len; 8229 struct wpabuf *buf; 8230 struct ieee802_11_elems elems; 8231 8232 frame = atoi(pos); 8233 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 8234 return -1; 8235 wpa_s = wpas_vendor_elem(wpa_s, frame); 8236 8237 pos = os_strchr(pos, ' '); 8238 if (pos == NULL) 8239 return -1; 8240 pos++; 8241 8242 len = os_strlen(pos); 8243 if (len == 0) 8244 return 0; 8245 if (len & 1) 8246 return -1; 8247 len /= 2; 8248 8249 buf = wpabuf_alloc(len); 8250 if (buf == NULL) 8251 return -1; 8252 8253 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 8254 wpabuf_free(buf); 8255 return -1; 8256 } 8257 8258 if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) == 8259 ParseFailed) { 8260 wpabuf_free(buf); 8261 return -1; 8262 } 8263 8264 if (wpa_s->vendor_elem[frame] == NULL) { 8265 wpa_s->vendor_elem[frame] = buf; 8266 wpas_vendor_elem_update(wpa_s); 8267 return 0; 8268 } 8269 8270 if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) { 8271 wpabuf_free(buf); 8272 return -1; 8273 } 8274 8275 wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); 8276 wpabuf_free(buf); 8277 wpas_vendor_elem_update(wpa_s); 8278 8279 return 0; 8280} 8281 8282 8283static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, 8284 char *buf, size_t buflen) 8285{ 8286 int frame = atoi(cmd); 8287 8288 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 8289 return -1; 8290 wpa_s = wpas_vendor_elem(wpa_s, frame); 8291 8292 if (wpa_s->vendor_elem[frame] == NULL) 8293 return 0; 8294 8295 return wpa_snprintf_hex(buf, buflen, 8296 wpabuf_head_u8(wpa_s->vendor_elem[frame]), 8297 wpabuf_len(wpa_s->vendor_elem[frame])); 8298} 8299 8300 8301static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) 8302{ 8303 char *pos = cmd; 8304 int frame; 8305 size_t len; 8306 u8 *buf; 8307 struct ieee802_11_elems elems; 8308 int res; 8309 8310 frame = atoi(pos); 8311 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) 8312 return -1; 8313 wpa_s = wpas_vendor_elem(wpa_s, frame); 8314 8315 pos = os_strchr(pos, ' '); 8316 if (pos == NULL) 8317 return -1; 8318 pos++; 8319 8320 if (*pos == '*') { 8321 wpabuf_free(wpa_s->vendor_elem[frame]); 8322 wpa_s->vendor_elem[frame] = NULL; 8323 wpas_vendor_elem_update(wpa_s); 8324 return 0; 8325 } 8326 8327 if (wpa_s->vendor_elem[frame] == NULL) 8328 return -1; 8329 8330 len = os_strlen(pos); 8331 if (len == 0) 8332 return 0; 8333 if (len & 1) 8334 return -1; 8335 len /= 2; 8336 8337 buf = os_malloc(len); 8338 if (buf == NULL) 8339 return -1; 8340 8341 if (hexstr2bin(pos, buf, len) < 0) { 8342 os_free(buf); 8343 return -1; 8344 } 8345 8346 if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) { 8347 os_free(buf); 8348 return -1; 8349 } 8350 8351 res = wpas_vendor_elem_remove(wpa_s, frame, buf, len); 8352 os_free(buf); 8353 return res; 8354} 8355 8356 8357static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) 8358{ 8359 struct wpa_supplicant *wpa_s = ctx; 8360 size_t len; 8361 const u8 *data; 8362 8363 /* 8364 * Neighbor Report element (IEEE P802.11-REVmc/D5.0) 8365 * BSSID[6] 8366 * BSSID Information[4] 8367 * Operating Class[1] 8368 * Channel Number[1] 8369 * PHY Type[1] 8370 * Optional Subelements[variable] 8371 */ 8372#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1) 8373 8374 if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) { 8375 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED); 8376 goto out; 8377 } 8378 8379 data = wpabuf_head_u8(neighbor_rep); 8380 len = wpabuf_len(neighbor_rep); 8381 8382 while (len >= 2 + NR_IE_MIN_LEN) { 8383 const u8 *nr; 8384 char lci[256 * 2 + 1]; 8385 char civic[256 * 2 + 1]; 8386 u8 nr_len = data[1]; 8387 const u8 *pos = data, *end; 8388 8389 if (pos[0] != WLAN_EID_NEIGHBOR_REPORT || 8390 nr_len < NR_IE_MIN_LEN) { 8391 wpa_printf(MSG_DEBUG, 8392 "CTRL: Invalid Neighbor Report element: id=%u len=%u", 8393 data[0], nr_len); 8394 goto out; 8395 } 8396 8397 if (2U + nr_len > len) { 8398 wpa_printf(MSG_DEBUG, 8399 "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u", 8400 data[0], len, nr_len); 8401 goto out; 8402 } 8403 pos += 2; 8404 end = pos + nr_len; 8405 8406 nr = pos; 8407 pos += NR_IE_MIN_LEN; 8408 8409 lci[0] = '\0'; 8410 civic[0] = '\0'; 8411 while (end - pos > 2) { 8412 u8 s_id, s_len; 8413 8414 s_id = *pos++; 8415 s_len = *pos++; 8416 if (s_len > end - pos) 8417 goto out; 8418 if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) { 8419 /* Measurement Token[1] */ 8420 /* Measurement Report Mode[1] */ 8421 /* Measurement Type[1] */ 8422 /* Measurement Report[variable] */ 8423 switch (pos[2]) { 8424 case MEASURE_TYPE_LCI: 8425 if (lci[0]) 8426 break; 8427 wpa_snprintf_hex(lci, sizeof(lci), 8428 pos, s_len); 8429 break; 8430 case MEASURE_TYPE_LOCATION_CIVIC: 8431 if (civic[0]) 8432 break; 8433 wpa_snprintf_hex(civic, sizeof(civic), 8434 pos, s_len); 8435 break; 8436 } 8437 } 8438 8439 pos += s_len; 8440 } 8441 8442 wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED 8443 "bssid=" MACSTR 8444 " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s", 8445 MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN), 8446 nr[ETH_ALEN + 4], nr[ETH_ALEN + 5], 8447 nr[ETH_ALEN + 6], 8448 lci[0] ? " lci=" : "", lci, 8449 civic[0] ? " civic=" : "", civic); 8450 8451 data = end; 8452 len -= 2 + nr_len; 8453 } 8454 8455out: 8456 wpabuf_free(neighbor_rep); 8457} 8458 8459 8460static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s, 8461 char *cmd) 8462{ 8463 struct wpa_ssid_value ssid, *ssid_p = NULL; 8464 int ret, lci = 0, civic = 0; 8465 char *ssid_s; 8466 8467 ssid_s = os_strstr(cmd, "ssid="); 8468 if (ssid_s) { 8469 if (ssid_parse(ssid_s + 5, &ssid)) { 8470 wpa_printf(MSG_ERROR, 8471 "CTRL: Send Neighbor Report: bad SSID"); 8472 return -1; 8473 } 8474 8475 ssid_p = &ssid; 8476 8477 /* 8478 * Move cmd after the SSID text that may include "lci" or 8479 * "civic". 8480 */ 8481 cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' '); 8482 if (cmd) 8483 cmd++; 8484 8485 } 8486 8487 if (cmd && os_strstr(cmd, "lci")) 8488 lci = 1; 8489 8490 if (cmd && os_strstr(cmd, "civic")) 8491 civic = 1; 8492 8493 ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic, 8494 wpas_ctrl_neighbor_rep_cb, 8495 wpa_s); 8496 8497 return ret; 8498} 8499 8500 8501static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s) 8502{ 8503 eapol_sm_erp_flush(wpa_s->eapol); 8504 return 0; 8505} 8506 8507 8508static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, 8509 char *cmd) 8510{ 8511 char *token, *context = NULL; 8512 unsigned int enable = ~0, type = 0; 8513 u8 _addr[ETH_ALEN], _mask[ETH_ALEN]; 8514 u8 *addr = NULL, *mask = NULL; 8515 8516 while ((token = str_token(cmd, " ", &context))) { 8517 if (os_strcasecmp(token, "scan") == 0) { 8518 type |= MAC_ADDR_RAND_SCAN; 8519 } else if (os_strcasecmp(token, "sched") == 0) { 8520 type |= MAC_ADDR_RAND_SCHED_SCAN; 8521 } else if (os_strcasecmp(token, "pno") == 0) { 8522 type |= MAC_ADDR_RAND_PNO; 8523 } else if (os_strcasecmp(token, "all") == 0) { 8524 type = wpa_s->mac_addr_rand_supported; 8525 } else if (os_strncasecmp(token, "enable=", 7) == 0) { 8526 enable = atoi(token + 7); 8527 } else if (os_strncasecmp(token, "addr=", 5) == 0) { 8528 addr = _addr; 8529 if (hwaddr_aton(token + 5, addr)) { 8530 wpa_printf(MSG_INFO, 8531 "CTRL: Invalid MAC address: %s", 8532 token); 8533 return -1; 8534 } 8535 } else if (os_strncasecmp(token, "mask=", 5) == 0) { 8536 mask = _mask; 8537 if (hwaddr_aton(token + 5, mask)) { 8538 wpa_printf(MSG_INFO, 8539 "CTRL: Invalid MAC address mask: %s", 8540 token); 8541 return -1; 8542 } 8543 } else { 8544 wpa_printf(MSG_INFO, 8545 "CTRL: Invalid MAC_RAND_SCAN parameter: %s", 8546 token); 8547 return -1; 8548 } 8549 } 8550 8551 if (!type) { 8552 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified"); 8553 return -1; 8554 } 8555 8556 if ((wpa_s->mac_addr_rand_supported & type) != type) { 8557 wpa_printf(MSG_INFO, 8558 "CTRL: MAC_RAND_SCAN types=%u != supported=%u", 8559 type, wpa_s->mac_addr_rand_supported); 8560 return -1; 8561 } 8562 8563 if (enable > 1) { 8564 wpa_printf(MSG_INFO, 8565 "CTRL: MAC_RAND_SCAN enable=<0/1> not specified"); 8566 return -1; 8567 } 8568 8569 if (!enable) { 8570 wpas_mac_addr_rand_scan_clear(wpa_s, type); 8571 if (wpa_s->pno) { 8572 if (type & MAC_ADDR_RAND_PNO) { 8573 wpas_stop_pno(wpa_s); 8574 wpas_start_pno(wpa_s); 8575 } 8576 } else if (wpa_s->sched_scanning && 8577 (type & MAC_ADDR_RAND_SCHED_SCAN)) { 8578 wpas_scan_restart_sched_scan(wpa_s); 8579 } 8580 return 0; 8581 } 8582 8583 if ((addr && !mask) || (!addr && mask)) { 8584 wpa_printf(MSG_INFO, 8585 "CTRL: MAC_RAND_SCAN invalid addr/mask combination"); 8586 return -1; 8587 } 8588 8589 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) { 8590 wpa_printf(MSG_INFO, 8591 "CTRL: MAC_RAND_SCAN cannot allow multicast address"); 8592 return -1; 8593 } 8594 8595 if (type & MAC_ADDR_RAND_SCAN) { 8596 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN, 8597 addr, mask); 8598 } 8599 8600 if (type & MAC_ADDR_RAND_SCHED_SCAN) { 8601 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, 8602 addr, mask); 8603 8604 if (wpa_s->sched_scanning && !wpa_s->pno) 8605 wpas_scan_restart_sched_scan(wpa_s); 8606 } 8607 8608 if (type & MAC_ADDR_RAND_PNO) { 8609 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO, 8610 addr, mask); 8611 if (wpa_s->pno) { 8612 wpas_stop_pno(wpa_s); 8613 wpas_start_pno(wpa_s); 8614 } 8615 } 8616 8617 return 0; 8618} 8619 8620 8621static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s, 8622 char *buf, size_t buflen) 8623{ 8624 size_t reply_len; 8625 8626 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen); 8627#ifdef CONFIG_AP 8628 reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len], 8629 buflen - reply_len); 8630#endif /* CONFIG_AP */ 8631 return reply_len; 8632} 8633 8634 8635static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) 8636{ 8637 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); 8638#ifdef CONFIG_AP 8639 wpas_ap_pmksa_cache_flush(wpa_s); 8640#endif /* CONFIG_AP */ 8641} 8642 8643 8644static int wpas_ctrl_cmd_debug_level(const char *cmd) 8645{ 8646 if (os_strcmp(cmd, "PING") == 0 || 8647 os_strncmp(cmd, "BSS ", 4) == 0 || 8648 os_strncmp(cmd, "GET_NETWORK ", 12) == 0 || 8649 os_strncmp(cmd, "STATUS", 6) == 0 || 8650 os_strncmp(cmd, "STA ", 4) == 0 || 8651 os_strncmp(cmd, "STA-", 4) == 0) 8652 return MSG_EXCESSIVE; 8653 return MSG_DEBUG; 8654} 8655 8656 8657char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, 8658 char *buf, size_t *resp_len) 8659{ 8660 char *reply; 8661 const int reply_size = 4096; 8662 int reply_len; 8663 8664 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || 8665 os_strncmp(buf, "SET_NETWORK ", 12) == 0) { 8666 if (wpa_debug_show_keys) 8667 wpa_dbg(wpa_s, MSG_DEBUG, 8668 "Control interface command '%s'", buf); 8669 else 8670 wpa_dbg(wpa_s, MSG_DEBUG, 8671 "Control interface command '%s [REMOVED]'", 8672 os_strncmp(buf, WPA_CTRL_RSP, 8673 os_strlen(WPA_CTRL_RSP)) == 0 ? 8674 WPA_CTRL_RSP : "SET_NETWORK"); 8675 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || 8676 os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) { 8677 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", 8678 (const u8 *) buf, os_strlen(buf)); 8679 } else { 8680 int level = wpas_ctrl_cmd_debug_level(buf); 8681 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf); 8682 } 8683 8684 reply = os_malloc(reply_size); 8685 if (reply == NULL) { 8686 *resp_len = 1; 8687 return NULL; 8688 } 8689 8690 os_memcpy(reply, "OK\n", 3); 8691 reply_len = 3; 8692 8693 if (os_strcmp(buf, "PING") == 0) { 8694 os_memcpy(reply, "PONG\n", 5); 8695 reply_len = 5; 8696 } else if (os_strcmp(buf, "IFNAME") == 0) { 8697 reply_len = os_strlen(wpa_s->ifname); 8698 os_memcpy(reply, wpa_s->ifname, reply_len); 8699 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 8700 if (wpa_debug_reopen_file() < 0) 8701 reply_len = -1; 8702 } else if (os_strncmp(buf, "NOTE ", 5) == 0) { 8703 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); 8704 } else if (os_strcmp(buf, "MIB") == 0) { 8705 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); 8706 if (reply_len >= 0) { 8707 reply_len += eapol_sm_get_mib(wpa_s->eapol, 8708 reply + reply_len, 8709 reply_size - reply_len); 8710 } 8711 } else if (os_strncmp(buf, "STATUS", 6) == 0) { 8712 reply_len = wpa_supplicant_ctrl_iface_status( 8713 wpa_s, buf + 6, reply, reply_size); 8714 } else if (os_strcmp(buf, "PMKSA") == 0) { 8715 reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); 8716 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { 8717 wpas_ctrl_iface_pmksa_flush(wpa_s); 8718 } else if (os_strncmp(buf, "SET ", 4) == 0) { 8719 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) 8720 reply_len = -1; 8721 } else if (os_strncmp(buf, "DUMP", 4) == 0) { 8722 reply_len = wpa_config_dump_values(wpa_s->conf, 8723 reply, reply_size); 8724 } else if (os_strncmp(buf, "GET ", 4) == 0) { 8725 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4, 8726 reply, reply_size); 8727 } else if (os_strcmp(buf, "LOGON") == 0) { 8728 eapol_sm_notify_logoff(wpa_s->eapol, FALSE); 8729 } else if (os_strcmp(buf, "LOGOFF") == 0) { 8730 eapol_sm_notify_logoff(wpa_s->eapol, TRUE); 8731 } else if (os_strcmp(buf, "REASSOCIATE") == 0) { 8732 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) 8733 reply_len = -1; 8734 else 8735 wpas_request_connection(wpa_s); 8736 } else if (os_strcmp(buf, "REATTACH") == 0) { 8737 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED || 8738 !wpa_s->current_ssid) 8739 reply_len = -1; 8740 else { 8741 wpa_s->reattach = 1; 8742 wpas_request_connection(wpa_s); 8743 } 8744 } else if (os_strcmp(buf, "RECONNECT") == 0) { 8745 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) 8746 reply_len = -1; 8747 else if (wpa_s->disconnected) 8748 wpas_request_connection(wpa_s); 8749#ifdef IEEE8021X_EAPOL 8750 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { 8751 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) 8752 reply_len = -1; 8753#endif /* IEEE8021X_EAPOL */ 8754#ifdef CONFIG_PEERKEY 8755 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { 8756 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) 8757 reply_len = -1; 8758#endif /* CONFIG_PEERKEY */ 8759#ifdef CONFIG_IEEE80211R 8760 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { 8761 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) 8762 reply_len = -1; 8763#endif /* CONFIG_IEEE80211R */ 8764#ifdef CONFIG_WPS 8765 } else if (os_strcmp(buf, "WPS_PBC") == 0) { 8766 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL); 8767 if (res == -2) { 8768 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 8769 reply_len = 17; 8770 } else if (res) 8771 reply_len = -1; 8772 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) { 8773 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8); 8774 if (res == -2) { 8775 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 8776 reply_len = 17; 8777 } else if (res) 8778 reply_len = -1; 8779 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 8780 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, 8781 reply, 8782 reply_size); 8783 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { 8784 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin( 8785 wpa_s, buf + 14, reply, reply_size); 8786 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { 8787 if (wpas_wps_cancel(wpa_s)) 8788 reply_len = -1; 8789#ifdef CONFIG_WPS_NFC 8790 } else if (os_strcmp(buf, "WPS_NFC") == 0) { 8791 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL)) 8792 reply_len = -1; 8793 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) { 8794 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8)) 8795 reply_len = -1; 8796 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { 8797 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token( 8798 wpa_s, buf + 21, reply, reply_size); 8799 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { 8800 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token( 8801 wpa_s, buf + 14, reply, reply_size); 8802 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { 8803 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s, 8804 buf + 17)) 8805 reply_len = -1; 8806 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) { 8807 reply_len = wpas_ctrl_nfc_get_handover_req( 8808 wpa_s, buf + 21, reply, reply_size); 8809 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { 8810 reply_len = wpas_ctrl_nfc_get_handover_sel( 8811 wpa_s, buf + 21, reply, reply_size); 8812 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { 8813 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20)) 8814 reply_len = -1; 8815#endif /* CONFIG_WPS_NFC */ 8816 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) { 8817 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) 8818 reply_len = -1; 8819#ifdef CONFIG_AP 8820 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 8821 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin( 8822 wpa_s, buf + 11, reply, reply_size); 8823#endif /* CONFIG_AP */ 8824#ifdef CONFIG_WPS_ER 8825 } else if (os_strcmp(buf, "WPS_ER_START") == 0) { 8826 if (wpas_wps_er_start(wpa_s, NULL)) 8827 reply_len = -1; 8828 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) { 8829 if (wpas_wps_er_start(wpa_s, buf + 13)) 8830 reply_len = -1; 8831 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) { 8832 wpas_wps_er_stop(wpa_s); 8833 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) { 8834 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11)) 8835 reply_len = -1; 8836 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) { 8837 int ret = wpas_wps_er_pbc(wpa_s, buf + 11); 8838 if (ret == -2) { 8839 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); 8840 reply_len = 17; 8841 } else if (ret == -3) { 8842 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18); 8843 reply_len = 18; 8844 } else if (ret == -4) { 8845 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20); 8846 reply_len = 20; 8847 } else if (ret) 8848 reply_len = -1; 8849 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) { 8850 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13)) 8851 reply_len = -1; 8852 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) { 8853 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s, 8854 buf + 18)) 8855 reply_len = -1; 8856 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) { 8857 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14)) 8858 reply_len = -1; 8859#ifdef CONFIG_WPS_NFC 8860 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) { 8861 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( 8862 wpa_s, buf + 24, reply, reply_size); 8863#endif /* CONFIG_WPS_NFC */ 8864#endif /* CONFIG_WPS_ER */ 8865#endif /* CONFIG_WPS */ 8866#ifdef CONFIG_IBSS_RSN 8867 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) { 8868 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) 8869 reply_len = -1; 8870#endif /* CONFIG_IBSS_RSN */ 8871#ifdef CONFIG_MESH 8872 } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) { 8873 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add( 8874 wpa_s, buf + 19, reply, reply_size); 8875 } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) { 8876 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add( 8877 wpa_s, "", reply, reply_size); 8878 } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) { 8879 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15)) 8880 reply_len = -1; 8881 } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) { 8882 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, 8883 buf + 18)) 8884 reply_len = -1; 8885 } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) { 8886 if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17)) 8887 reply_len = -1; 8888 } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) { 8889 if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14)) 8890 reply_len = -1; 8891#endif /* CONFIG_MESH */ 8892#ifdef CONFIG_P2P 8893 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { 8894 if (p2p_ctrl_find(wpa_s, buf + 8)) 8895 reply_len = -1; 8896 } else if (os_strcmp(buf, "P2P_FIND") == 0) { 8897 if (p2p_ctrl_find(wpa_s, "")) 8898 reply_len = -1; 8899 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { 8900 wpas_p2p_stop_find(wpa_s); 8901 } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) { 8902 if (p2p_ctrl_asp_provision(wpa_s, buf + 18)) 8903 reply_len = -1; 8904 } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) { 8905 if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23)) 8906 reply_len = -1; 8907 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { 8908 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, 8909 reply_size); 8910 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) { 8911 if (p2p_ctrl_listen(wpa_s, buf + 11)) 8912 reply_len = -1; 8913 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) { 8914 if (p2p_ctrl_listen(wpa_s, "")) 8915 reply_len = -1; 8916 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) { 8917 if (wpas_p2p_group_remove(wpa_s, buf + 17)) 8918 reply_len = -1; 8919 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { 8920 if (p2p_ctrl_group_add(wpa_s, "")) 8921 reply_len = -1; 8922 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { 8923 if (p2p_ctrl_group_add(wpa_s, buf + 14)) 8924 reply_len = -1; 8925 } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) { 8926 reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply, 8927 reply_size); 8928 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { 8929 if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) 8930 reply_len = -1; 8931 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { 8932 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); 8933 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { 8934 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, 8935 reply_size); 8936 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) { 8937 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0) 8938 reply_len = -1; 8939 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) { 8940 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0) 8941 reply_len = -1; 8942 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) { 8943 wpas_p2p_sd_service_update(wpa_s); 8944 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) { 8945 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0) 8946 reply_len = -1; 8947 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) { 8948 wpas_p2p_service_flush(wpa_s); 8949 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) { 8950 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0) 8951 reply_len = -1; 8952 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) { 8953 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0) 8954 reply_len = -1; 8955 } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) { 8956 if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0) 8957 reply_len = -1; 8958 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) { 8959 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0) 8960 reply_len = -1; 8961 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) { 8962 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0) 8963 reply_len = -1; 8964 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) { 8965 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply, 8966 reply_size); 8967 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) { 8968 if (p2p_ctrl_set(wpa_s, buf + 8) < 0) 8969 reply_len = -1; 8970 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) { 8971 p2p_ctrl_flush(wpa_s); 8972 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) { 8973 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0) 8974 reply_len = -1; 8975 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) { 8976 if (wpas_p2p_cancel(wpa_s)) 8977 reply_len = -1; 8978 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) { 8979 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0) 8980 reply_len = -1; 8981 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) { 8982 if (p2p_ctrl_presence_req(wpa_s, "") < 0) 8983 reply_len = -1; 8984 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) { 8985 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0) 8986 reply_len = -1; 8987 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) { 8988 if (p2p_ctrl_ext_listen(wpa_s, "") < 0) 8989 reply_len = -1; 8990 } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) { 8991 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0) 8992 reply_len = -1; 8993 } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) { 8994 if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13)) 8995 reply_len = -1; 8996 } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) { 8997 if (wpas_p2p_lo_stop(wpa_s)) 8998 reply_len = -1; 8999#endif /* CONFIG_P2P */ 9000#ifdef CONFIG_WIFI_DISPLAY 9001 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { 9002 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0) 9003 reply_len = -1; 9004 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) { 9005 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16, 9006 reply, reply_size); 9007#endif /* CONFIG_WIFI_DISPLAY */ 9008#ifdef CONFIG_INTERWORKING 9009 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) { 9010 if (interworking_fetch_anqp(wpa_s) < 0) 9011 reply_len = -1; 9012 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) { 9013 interworking_stop_fetch_anqp(wpa_s); 9014 } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) { 9015 if (ctrl_interworking_select(wpa_s, NULL) < 0) 9016 reply_len = -1; 9017 } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) { 9018 if (ctrl_interworking_select(wpa_s, buf + 20) < 0) 9019 reply_len = -1; 9020 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { 9021 if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0) 9022 reply_len = -1; 9023 } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) { 9024 int id; 9025 9026 id = ctrl_interworking_connect(wpa_s, buf + 25, 1); 9027 if (id < 0) 9028 reply_len = -1; 9029 else { 9030 reply_len = os_snprintf(reply, reply_size, "%d\n", id); 9031 if (os_snprintf_error(reply_size, reply_len)) 9032 reply_len = -1; 9033 } 9034 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) { 9035 if (get_anqp(wpa_s, buf + 9) < 0) 9036 reply_len = -1; 9037 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) { 9038 if (gas_request(wpa_s, buf + 12) < 0) 9039 reply_len = -1; 9040 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) { 9041 reply_len = gas_response_get(wpa_s, buf + 17, reply, 9042 reply_size); 9043#endif /* CONFIG_INTERWORKING */ 9044#ifdef CONFIG_HS20 9045 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) { 9046 if (get_hs20_anqp(wpa_s, buf + 14) < 0) 9047 reply_len = -1; 9048 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) { 9049 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) 9050 reply_len = -1; 9051 } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { 9052 if (hs20_icon_request(wpa_s, buf + 18, 0) < 0) 9053 reply_len = -1; 9054 } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) { 9055 if (hs20_icon_request(wpa_s, buf + 14, 1) < 0) 9056 reply_len = -1; 9057 } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) { 9058 reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size); 9059 } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) { 9060 if (del_hs20_icon(wpa_s, buf + 14) < 0) 9061 reply_len = -1; 9062 } else if (os_strcmp(buf, "FETCH_OSU") == 0) { 9063 if (hs20_fetch_osu(wpa_s, 0) < 0) 9064 reply_len = -1; 9065 } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) { 9066 if (hs20_fetch_osu(wpa_s, 1) < 0) 9067 reply_len = -1; 9068 } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) { 9069 hs20_cancel_fetch_osu(wpa_s); 9070#endif /* CONFIG_HS20 */ 9071 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) 9072 { 9073 if (wpa_supplicant_ctrl_iface_ctrl_rsp( 9074 wpa_s, buf + os_strlen(WPA_CTRL_RSP))) 9075 reply_len = -1; 9076 else { 9077 /* 9078 * Notify response from timeout to allow the control 9079 * interface response to be sent first. 9080 */ 9081 eloop_register_timeout(0, 0, wpas_ctrl_eapol_response, 9082 wpa_s, NULL); 9083 } 9084 } else if (os_strcmp(buf, "RECONFIGURE") == 0) { 9085 if (wpa_supplicant_reload_configuration(wpa_s)) 9086 reply_len = -1; 9087 } else if (os_strcmp(buf, "TERMINATE") == 0) { 9088 wpa_supplicant_terminate_proc(wpa_s->global); 9089 } else if (os_strncmp(buf, "BSSID ", 6) == 0) { 9090 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) 9091 reply_len = -1; 9092 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) { 9093 reply_len = wpa_supplicant_ctrl_iface_blacklist( 9094 wpa_s, buf + 9, reply, reply_size); 9095 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) { 9096 reply_len = wpa_supplicant_ctrl_iface_log_level( 9097 wpa_s, buf + 9, reply, reply_size); 9098 } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) { 9099 reply_len = wpa_supplicant_ctrl_iface_list_networks( 9100 wpa_s, buf + 14, reply, reply_size); 9101 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { 9102 reply_len = wpa_supplicant_ctrl_iface_list_networks( 9103 wpa_s, NULL, reply, reply_size); 9104 } else if (os_strcmp(buf, "DISCONNECT") == 0) { 9105 wpas_request_disconnection(wpa_s); 9106 } else if (os_strcmp(buf, "SCAN") == 0) { 9107 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); 9108 } else if (os_strncmp(buf, "SCAN ", 5) == 0) { 9109 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); 9110 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { 9111 reply_len = wpa_supplicant_ctrl_iface_scan_results( 9112 wpa_s, reply, reply_size); 9113 } else if (os_strcmp(buf, "ABORT_SCAN") == 0) { 9114 if (wpas_abort_ongoing_scan(wpa_s) < 0) 9115 reply_len = -1; 9116 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { 9117 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) 9118 reply_len = -1; 9119 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { 9120 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) 9121 reply_len = -1; 9122 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { 9123 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) 9124 reply_len = -1; 9125 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { 9126 reply_len = wpa_supplicant_ctrl_iface_add_network( 9127 wpa_s, reply, reply_size); 9128 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { 9129 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) 9130 reply_len = -1; 9131 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { 9132 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) 9133 reply_len = -1; 9134 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { 9135 reply_len = wpa_supplicant_ctrl_iface_get_network( 9136 wpa_s, buf + 12, reply, reply_size); 9137 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { 9138 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12, 9139 wpa_s)) 9140 reply_len = -1; 9141 } else if (os_strcmp(buf, "LIST_CREDS") == 0) { 9142 reply_len = wpa_supplicant_ctrl_iface_list_creds( 9143 wpa_s, reply, reply_size); 9144 } else if (os_strcmp(buf, "ADD_CRED") == 0) { 9145 reply_len = wpa_supplicant_ctrl_iface_add_cred( 9146 wpa_s, reply, reply_size); 9147 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) { 9148 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12)) 9149 reply_len = -1; 9150 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) { 9151 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9)) 9152 reply_len = -1; 9153 } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) { 9154 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9, 9155 reply, 9156 reply_size); 9157#ifndef CONFIG_NO_CONFIG_WRITE 9158 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { 9159 if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) 9160 reply_len = -1; 9161#endif /* CONFIG_NO_CONFIG_WRITE */ 9162 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { 9163 reply_len = wpa_supplicant_ctrl_iface_get_capability( 9164 wpa_s, buf + 15, reply, reply_size); 9165 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { 9166 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) 9167 reply_len = -1; 9168 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) { 9169 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14)) 9170 reply_len = -1; 9171 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { 9172 reply_len = wpa_supplicant_global_iface_list( 9173 wpa_s->global, reply, reply_size); 9174 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { 9175 reply_len = wpa_supplicant_global_iface_interfaces( 9176 wpa_s->global, buf + 10, reply, reply_size); 9177 } else if (os_strncmp(buf, "BSS ", 4) == 0) { 9178 reply_len = wpa_supplicant_ctrl_iface_bss( 9179 wpa_s, buf + 4, reply, reply_size); 9180#ifdef CONFIG_AP 9181 } else if (os_strcmp(buf, "STA-FIRST") == 0) { 9182 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); 9183 } else if (os_strncmp(buf, "STA ", 4) == 0) { 9184 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply, 9185 reply_size); 9186 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 9187 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, 9188 reply_size); 9189 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 9190 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15)) 9191 reply_len = -1; 9192 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 9193 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13)) 9194 reply_len = -1; 9195 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { 9196 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12)) 9197 reply_len = -1; 9198 } else if (os_strcmp(buf, "STOP_AP") == 0) { 9199 if (wpas_ap_stop_ap(wpa_s)) 9200 reply_len = -1; 9201#endif /* CONFIG_AP */ 9202 } else if (os_strcmp(buf, "SUSPEND") == 0) { 9203 wpas_notify_suspend(wpa_s->global); 9204 } else if (os_strcmp(buf, "RESUME") == 0) { 9205 wpas_notify_resume(wpa_s->global); 9206#ifdef CONFIG_TESTING_OPTIONS 9207 } else if (os_strcmp(buf, "DROP_SA") == 0) { 9208 wpa_supplicant_ctrl_iface_drop_sa(wpa_s); 9209#endif /* CONFIG_TESTING_OPTIONS */ 9210 } else if (os_strncmp(buf, "ROAM ", 5) == 0) { 9211 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5)) 9212 reply_len = -1; 9213 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { 9214 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0; 9215 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) { 9216 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15)) 9217 reply_len = -1; 9218 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) { 9219 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s, 9220 buf + 17)) 9221 reply_len = -1; 9222 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) { 9223 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10); 9224#ifdef CONFIG_TDLS 9225 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) { 9226 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14)) 9227 reply_len = -1; 9228 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) { 9229 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11)) 9230 reply_len = -1; 9231 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) { 9232 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14)) 9233 reply_len = -1; 9234 } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) { 9235 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s, 9236 buf + 17)) 9237 reply_len = -1; 9238 } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) { 9239 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s, 9240 buf + 24)) 9241 reply_len = -1; 9242 } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) { 9243 reply_len = wpa_supplicant_ctrl_iface_tdls_link_status( 9244 wpa_s, buf + 17, reply, reply_size); 9245#endif /* CONFIG_TDLS */ 9246 } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) { 9247 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size); 9248 } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) { 9249 if (wmm_ac_ctrl_addts(wpa_s, buf + 13)) 9250 reply_len = -1; 9251 } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) { 9252 if (wmm_ac_ctrl_delts(wpa_s, buf + 13)) 9253 reply_len = -1; 9254 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { 9255 reply_len = wpa_supplicant_signal_poll(wpa_s, reply, 9256 reply_size); 9257 } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) { 9258 if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14)) 9259 reply_len = -1; 9260 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { 9261 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, 9262 reply_size); 9263#ifdef CONFIG_AUTOSCAN 9264 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) { 9265 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9)) 9266 reply_len = -1; 9267#endif /* CONFIG_AUTOSCAN */ 9268 } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { 9269 reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply, 9270 reply_size); 9271#ifdef ANDROID 9272 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { 9273 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, 9274 reply_size); 9275#endif /* ANDROID */ 9276 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { 9277 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply, 9278 reply_size); 9279 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) { 9280 pmksa_cache_clear_current(wpa_s->wpa); 9281 eapol_sm_request_reauth(wpa_s->eapol); 9282#ifdef CONFIG_WNM 9283 } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) { 9284 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10)) 9285 reply_len = -1; 9286 } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) { 9287 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14)) 9288 reply_len = -1; 9289#endif /* CONFIG_WNM */ 9290 } else if (os_strcmp(buf, "FLUSH") == 0) { 9291 wpa_supplicant_ctrl_iface_flush(wpa_s); 9292 } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { 9293 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, 9294 reply_size); 9295#ifdef CONFIG_TESTING_OPTIONS 9296 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { 9297 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0) 9298 reply_len = -1; 9299 } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { 9300 wpas_ctrl_iface_mgmt_tx_done(wpa_s); 9301 } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) { 9302 if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0) 9303 reply_len = -1; 9304 } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { 9305 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) 9306 reply_len = -1; 9307 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { 9308 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0) 9309 reply_len = -1; 9310 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { 9311 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0) 9312 reply_len = -1; 9313 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) { 9314 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0) 9315 reply_len = -1; 9316 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) { 9317 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0) 9318 reply_len = -1; 9319 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { 9320 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0) 9321 reply_len = -1; 9322 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { 9323 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size); 9324 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) { 9325 if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0) 9326 reply_len = -1; 9327 } else if (os_strcmp(buf, "GET_FAIL") == 0) { 9328 reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size); 9329 } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) { 9330 if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0) 9331 reply_len = -1; 9332 } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { 9333 if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) 9334 reply_len = -1; 9335#endif /* CONFIG_TESTING_OPTIONS */ 9336 } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { 9337 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) 9338 reply_len = -1; 9339 } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) { 9340 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply, 9341 reply_size); 9342 } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) { 9343 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) 9344 reply_len = -1; 9345 } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) { 9346 if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20)) 9347 reply_len = -1; 9348 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { 9349 wpas_ctrl_iface_erp_flush(wpa_s); 9350 } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) { 9351 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14)) 9352 reply_len = -1; 9353 } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { 9354 reply_len = wpas_ctrl_iface_get_pref_freq_list( 9355 wpa_s, buf + 19, reply, reply_size); 9356 } else { 9357 os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 9358 reply_len = 16; 9359 } 9360 9361 if (reply_len < 0) { 9362 os_memcpy(reply, "FAIL\n", 5); 9363 reply_len = 5; 9364 } 9365 9366 *resp_len = reply_len; 9367 return reply; 9368} 9369 9370 9371static int wpa_supplicant_global_iface_add(struct wpa_global *global, 9372 char *cmd) 9373{ 9374 struct wpa_interface iface; 9375 char *pos, *extra; 9376 struct wpa_supplicant *wpa_s; 9377 unsigned int create_iface = 0; 9378 u8 mac_addr[ETH_ALEN]; 9379 enum wpa_driver_if_type type = WPA_IF_STATION; 9380 9381 /* 9382 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> 9383 * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]] 9384 */ 9385 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); 9386 9387 os_memset(&iface, 0, sizeof(iface)); 9388 9389 do { 9390 iface.ifname = pos = cmd; 9391 pos = os_strchr(pos, '\t'); 9392 if (pos) 9393 *pos++ = '\0'; 9394 if (iface.ifname[0] == '\0') 9395 return -1; 9396 if (pos == NULL) 9397 break; 9398 9399 iface.confname = pos; 9400 pos = os_strchr(pos, '\t'); 9401 if (pos) 9402 *pos++ = '\0'; 9403 if (iface.confname[0] == '\0') 9404 iface.confname = NULL; 9405 if (pos == NULL) 9406 break; 9407 9408 iface.driver = pos; 9409 pos = os_strchr(pos, '\t'); 9410 if (pos) 9411 *pos++ = '\0'; 9412 if (iface.driver[0] == '\0') 9413 iface.driver = NULL; 9414 if (pos == NULL) 9415 break; 9416 9417 iface.ctrl_interface = pos; 9418 pos = os_strchr(pos, '\t'); 9419 if (pos) 9420 *pos++ = '\0'; 9421 if (iface.ctrl_interface[0] == '\0') 9422 iface.ctrl_interface = NULL; 9423 if (pos == NULL) 9424 break; 9425 9426 iface.driver_param = pos; 9427 pos = os_strchr(pos, '\t'); 9428 if (pos) 9429 *pos++ = '\0'; 9430 if (iface.driver_param[0] == '\0') 9431 iface.driver_param = NULL; 9432 if (pos == NULL) 9433 break; 9434 9435 iface.bridge_ifname = pos; 9436 pos = os_strchr(pos, '\t'); 9437 if (pos) 9438 *pos++ = '\0'; 9439 if (iface.bridge_ifname[0] == '\0') 9440 iface.bridge_ifname = NULL; 9441 if (pos == NULL) 9442 break; 9443 9444 extra = pos; 9445 pos = os_strchr(pos, '\t'); 9446 if (pos) 9447 *pos++ = '\0'; 9448 if (!extra[0]) 9449 break; 9450 9451 if (os_strcmp(extra, "create") == 0) { 9452 create_iface = 1; 9453 if (!pos) 9454 break; 9455 9456 if (os_strcmp(pos, "sta") == 0) { 9457 type = WPA_IF_STATION; 9458 } else if (os_strcmp(pos, "ap") == 0) { 9459 type = WPA_IF_AP_BSS; 9460 } else { 9461 wpa_printf(MSG_DEBUG, 9462 "INTERFACE_ADD unsupported interface type: '%s'", 9463 pos); 9464 return -1; 9465 } 9466 } else { 9467 wpa_printf(MSG_DEBUG, 9468 "INTERFACE_ADD unsupported extra parameter: '%s'", 9469 extra); 9470 return -1; 9471 } 9472 } while (0); 9473 9474 if (create_iface) { 9475 wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'", 9476 iface.ifname); 9477 if (!global->ifaces) 9478 return -1; 9479 if (wpa_drv_if_add(global->ifaces, type, iface.ifname, 9480 NULL, NULL, NULL, mac_addr, NULL) < 0) { 9481 wpa_printf(MSG_ERROR, 9482 "CTRL_IFACE interface creation failed"); 9483 return -1; 9484 } 9485 9486 wpa_printf(MSG_DEBUG, 9487 "CTRL_IFACE interface '%s' created with MAC addr: " 9488 MACSTR, iface.ifname, MAC2STR(mac_addr)); 9489 } 9490 9491 if (wpa_supplicant_get_iface(global, iface.ifname)) 9492 goto fail; 9493 9494 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); 9495 if (!wpa_s) 9496 goto fail; 9497 wpa_s->added_vif = create_iface; 9498 return 0; 9499 9500fail: 9501 if (create_iface) 9502 wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname); 9503 return -1; 9504} 9505 9506 9507static int wpa_supplicant_global_iface_remove(struct wpa_global *global, 9508 char *cmd) 9509{ 9510 struct wpa_supplicant *wpa_s; 9511 int ret; 9512 unsigned int delete_iface; 9513 9514 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd); 9515 9516 wpa_s = wpa_supplicant_get_iface(global, cmd); 9517 if (wpa_s == NULL) 9518 return -1; 9519 delete_iface = wpa_s->added_vif; 9520 ret = wpa_supplicant_remove_iface(global, wpa_s, 0); 9521 if (!ret && delete_iface) { 9522 wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'", 9523 cmd); 9524 ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd); 9525 } 9526 return ret; 9527} 9528 9529 9530static void wpa_free_iface_info(struct wpa_interface_info *iface) 9531{ 9532 struct wpa_interface_info *prev; 9533 9534 while (iface) { 9535 prev = iface; 9536 iface = iface->next; 9537 9538 os_free(prev->ifname); 9539 os_free(prev->desc); 9540 os_free(prev); 9541 } 9542} 9543 9544 9545static int wpa_supplicant_global_iface_list(struct wpa_global *global, 9546 char *buf, int len) 9547{ 9548 int i, res; 9549 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp; 9550 char *pos, *end; 9551 9552 for (i = 0; wpa_drivers[i]; i++) { 9553 const struct wpa_driver_ops *drv = wpa_drivers[i]; 9554 if (drv->get_interfaces == NULL) 9555 continue; 9556 tmp = drv->get_interfaces(global->drv_priv[i]); 9557 if (tmp == NULL) 9558 continue; 9559 9560 if (last == NULL) 9561 iface = last = tmp; 9562 else 9563 last->next = tmp; 9564 while (last->next) 9565 last = last->next; 9566 } 9567 9568 pos = buf; 9569 end = buf + len; 9570 for (tmp = iface; tmp; tmp = tmp->next) { 9571 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n", 9572 tmp->drv_name, tmp->ifname, 9573 tmp->desc ? tmp->desc : ""); 9574 if (os_snprintf_error(end - pos, res)) { 9575 *pos = '\0'; 9576 break; 9577 } 9578 pos += res; 9579 } 9580 9581 wpa_free_iface_info(iface); 9582 9583 return pos - buf; 9584} 9585 9586 9587static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, 9588 const char *input, 9589 char *buf, int len) 9590{ 9591 int res; 9592 char *pos, *end; 9593 struct wpa_supplicant *wpa_s; 9594 int show_ctrl = 0; 9595 9596 if (input) 9597 show_ctrl = !!os_strstr(input, "ctrl"); 9598 9599 wpa_s = global->ifaces; 9600 pos = buf; 9601 end = buf + len; 9602 9603 while (wpa_s) { 9604 if (show_ctrl) 9605 res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n", 9606 wpa_s->ifname, 9607 wpa_s->conf->ctrl_interface ? 9608 wpa_s->conf->ctrl_interface : "N/A"); 9609 else 9610 res = os_snprintf(pos, end - pos, "%s\n", 9611 wpa_s->ifname); 9612 9613 if (os_snprintf_error(end - pos, res)) { 9614 *pos = '\0'; 9615 break; 9616 } 9617 pos += res; 9618 wpa_s = wpa_s->next; 9619 } 9620 return pos - buf; 9621} 9622 9623 9624static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global, 9625 const char *ifname, 9626 char *cmd, size_t *resp_len) 9627{ 9628 struct wpa_supplicant *wpa_s; 9629 9630 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 9631 if (os_strcmp(ifname, wpa_s->ifname) == 0) 9632 break; 9633 } 9634 9635 if (wpa_s == NULL) { 9636 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n"); 9637 if (resp) 9638 *resp_len = os_strlen(resp); 9639 else 9640 *resp_len = 1; 9641 return resp; 9642 } 9643 9644 return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len); 9645} 9646 9647 9648static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, 9649 char *buf, size_t *resp_len) 9650{ 9651#ifdef CONFIG_P2P 9652 static const char * cmd[] = { 9653 "LIST_NETWORKS", 9654 "P2P_FIND", 9655 "P2P_STOP_FIND", 9656 "P2P_LISTEN", 9657 "P2P_GROUP_ADD", 9658 "P2P_GET_PASSPHRASE", 9659 "P2P_SERVICE_UPDATE", 9660 "P2P_SERVICE_FLUSH", 9661 "P2P_FLUSH", 9662 "P2P_CANCEL", 9663 "P2P_PRESENCE_REQ", 9664 "P2P_EXT_LISTEN", 9665 NULL 9666 }; 9667 static const char * prefix[] = { 9668#ifdef ANDROID 9669 "DRIVER ", 9670#endif /* ANDROID */ 9671 "GET_NETWORK ", 9672 "REMOVE_NETWORK ", 9673 "P2P_FIND ", 9674 "P2P_CONNECT ", 9675 "P2P_LISTEN ", 9676 "P2P_GROUP_REMOVE ", 9677 "P2P_GROUP_ADD ", 9678 "P2P_GROUP_MEMBER ", 9679 "P2P_PROV_DISC ", 9680 "P2P_SERV_DISC_REQ ", 9681 "P2P_SERV_DISC_CANCEL_REQ ", 9682 "P2P_SERV_DISC_RESP ", 9683 "P2P_SERV_DISC_EXTERNAL ", 9684 "P2P_SERVICE_ADD ", 9685 "P2P_SERVICE_DEL ", 9686 "P2P_SERVICE_REP ", 9687 "P2P_REJECT ", 9688 "P2P_INVITE ", 9689 "P2P_PEER ", 9690 "P2P_SET ", 9691 "P2P_UNAUTHORIZE ", 9692 "P2P_PRESENCE_REQ ", 9693 "P2P_EXT_LISTEN ", 9694 "P2P_REMOVE_CLIENT ", 9695 "WPS_NFC_TOKEN ", 9696 "WPS_NFC_TAG_READ ", 9697 "NFC_GET_HANDOVER_SEL ", 9698 "NFC_GET_HANDOVER_REQ ", 9699 "NFC_REPORT_HANDOVER ", 9700 "P2P_ASP_PROVISION ", 9701 "P2P_ASP_PROVISION_RESP ", 9702 NULL 9703 }; 9704 int found = 0; 9705 int i; 9706 9707 if (global->p2p_init_wpa_s == NULL) 9708 return NULL; 9709 9710 for (i = 0; !found && cmd[i]; i++) { 9711 if (os_strcmp(buf, cmd[i]) == 0) 9712 found = 1; 9713 } 9714 9715 for (i = 0; !found && prefix[i]; i++) { 9716 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0) 9717 found = 1; 9718 } 9719 9720 if (found) 9721 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, 9722 buf, resp_len); 9723#endif /* CONFIG_P2P */ 9724 return NULL; 9725} 9726 9727 9728static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global, 9729 char *buf, size_t *resp_len) 9730{ 9731#ifdef CONFIG_WIFI_DISPLAY 9732 if (global->p2p_init_wpa_s == NULL) 9733 return NULL; 9734 if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 || 9735 os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) 9736 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, 9737 buf, resp_len); 9738#endif /* CONFIG_WIFI_DISPLAY */ 9739 return NULL; 9740} 9741 9742 9743static char * wpas_global_ctrl_iface_redir(struct wpa_global *global, 9744 char *buf, size_t *resp_len) 9745{ 9746 char *ret; 9747 9748 ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len); 9749 if (ret) 9750 return ret; 9751 9752 ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len); 9753 if (ret) 9754 return ret; 9755 9756 return NULL; 9757} 9758 9759 9760static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd) 9761{ 9762 char *value; 9763 9764 value = os_strchr(cmd, ' '); 9765 if (value == NULL) 9766 return -1; 9767 *value++ = '\0'; 9768 9769 wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value); 9770 9771#ifdef CONFIG_WIFI_DISPLAY 9772 if (os_strcasecmp(cmd, "wifi_display") == 0) { 9773 wifi_display_enable(global, !!atoi(value)); 9774 return 0; 9775 } 9776#endif /* CONFIG_WIFI_DISPLAY */ 9777 9778 /* Restore cmd to its original value to allow redirection */ 9779 value[-1] = ' '; 9780 9781 return -1; 9782} 9783 9784 9785static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global, 9786 char *cmd) 9787{ 9788 struct wpa_supplicant *wpa_s[2]; /* src, dst */ 9789 char *p; 9790 unsigned int i; 9791 9792 /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id> 9793 * <variable name> */ 9794 9795 for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) { 9796 p = os_strchr(cmd, ' '); 9797 if (p == NULL) 9798 return -1; 9799 *p = '\0'; 9800 9801 wpa_s[i] = global->ifaces; 9802 for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) { 9803 if (os_strcmp(cmd, wpa_s[i]->ifname) == 0) 9804 break; 9805 } 9806 9807 if (!wpa_s[i]) { 9808 wpa_printf(MSG_DEBUG, 9809 "CTRL_IFACE: Could not find iface=%s", cmd); 9810 return -1; 9811 } 9812 9813 cmd = p + 1; 9814 } 9815 9816 return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]); 9817} 9818 9819 9820#ifndef CONFIG_NO_CONFIG_WRITE 9821static int wpas_global_ctrl_iface_save_config(struct wpa_global *global) 9822{ 9823 int ret = 0, saved = 0; 9824 struct wpa_supplicant *wpa_s; 9825 9826 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 9827 if (!wpa_s->conf->update_config) { 9828 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)"); 9829 continue; 9830 } 9831 9832 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) { 9833 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration"); 9834 ret = 1; 9835 } else { 9836 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated"); 9837 saved++; 9838 } 9839 } 9840 9841 if (!saved && !ret) { 9842 wpa_dbg(wpa_s, MSG_DEBUG, 9843 "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated"); 9844 ret = 1; 9845 } 9846 9847 return ret; 9848} 9849#endif /* CONFIG_NO_CONFIG_WRITE */ 9850 9851 9852static int wpas_global_ctrl_iface_status(struct wpa_global *global, 9853 char *buf, size_t buflen) 9854{ 9855 char *pos, *end; 9856 int ret; 9857 struct wpa_supplicant *wpa_s; 9858 9859 pos = buf; 9860 end = buf + buflen; 9861 9862#ifdef CONFIG_P2P 9863 if (global->p2p && !global->p2p_disabled) { 9864 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR 9865 "\n" 9866 "p2p_state=%s\n", 9867 MAC2STR(global->p2p_dev_addr), 9868 p2p_get_state_txt(global->p2p)); 9869 if (os_snprintf_error(end - pos, ret)) 9870 return pos - buf; 9871 pos += ret; 9872 } else if (global->p2p) { 9873 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n"); 9874 if (os_snprintf_error(end - pos, ret)) 9875 return pos - buf; 9876 pos += ret; 9877 } 9878#endif /* CONFIG_P2P */ 9879 9880#ifdef CONFIG_WIFI_DISPLAY 9881 ret = os_snprintf(pos, end - pos, "wifi_display=%d\n", 9882 !!global->wifi_display); 9883 if (os_snprintf_error(end - pos, ret)) 9884 return pos - buf; 9885 pos += ret; 9886#endif /* CONFIG_WIFI_DISPLAY */ 9887 9888 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 9889 ret = os_snprintf(pos, end - pos, "ifname=%s\n" 9890 "address=" MACSTR "\n", 9891 wpa_s->ifname, MAC2STR(wpa_s->own_addr)); 9892 if (os_snprintf_error(end - pos, ret)) 9893 return pos - buf; 9894 pos += ret; 9895 } 9896 9897 return pos - buf; 9898} 9899 9900 9901#ifdef CONFIG_FST 9902 9903static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global, 9904 char *cmd, char *buf, 9905 size_t reply_size) 9906{ 9907 char ifname[IFNAMSIZ + 1]; 9908 struct fst_iface_cfg cfg; 9909 struct wpa_supplicant *wpa_s; 9910 struct fst_wpa_obj iface_obj; 9911 9912 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) { 9913 wpa_s = wpa_supplicant_get_iface(global, ifname); 9914 if (wpa_s) { 9915 if (wpa_s->fst) { 9916 wpa_printf(MSG_INFO, "FST: Already attached"); 9917 return -1; 9918 } 9919 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj); 9920 wpa_s->fst = fst_attach(ifname, wpa_s->own_addr, 9921 &iface_obj, &cfg); 9922 if (wpa_s->fst) 9923 return os_snprintf(buf, reply_size, "OK\n"); 9924 } 9925 } 9926 9927 return -1; 9928} 9929 9930 9931static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global, 9932 char *cmd, char *buf, 9933 size_t reply_size) 9934{ 9935 char ifname[IFNAMSIZ + 1]; 9936 struct wpa_supplicant *wpa_s; 9937 9938 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) { 9939 wpa_s = wpa_supplicant_get_iface(global, ifname); 9940 if (wpa_s) { 9941 if (!fst_iface_detach(ifname)) { 9942 wpa_s->fst = NULL; 9943 return os_snprintf(buf, reply_size, "OK\n"); 9944 } 9945 } 9946 } 9947 9948 return -1; 9949} 9950 9951#endif /* CONFIG_FST */ 9952 9953 9954char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, 9955 char *buf, size_t *resp_len) 9956{ 9957 char *reply; 9958 const int reply_size = 2048; 9959 int reply_len; 9960 int level = MSG_DEBUG; 9961 9962 if (os_strncmp(buf, "IFNAME=", 7) == 0) { 9963 char *pos = os_strchr(buf + 7, ' '); 9964 if (pos) { 9965 *pos++ = '\0'; 9966 return wpas_global_ctrl_iface_ifname(global, 9967 buf + 7, pos, 9968 resp_len); 9969 } 9970 } 9971 9972 reply = wpas_global_ctrl_iface_redir(global, buf, resp_len); 9973 if (reply) 9974 return reply; 9975 9976 if (os_strcmp(buf, "PING") == 0) 9977 level = MSG_EXCESSIVE; 9978 wpa_hexdump_ascii(level, "RX global ctrl_iface", 9979 (const u8 *) buf, os_strlen(buf)); 9980 9981 reply = os_malloc(reply_size); 9982 if (reply == NULL) { 9983 *resp_len = 1; 9984 return NULL; 9985 } 9986 9987 os_memcpy(reply, "OK\n", 3); 9988 reply_len = 3; 9989 9990 if (os_strcmp(buf, "PING") == 0) { 9991 os_memcpy(reply, "PONG\n", 5); 9992 reply_len = 5; 9993 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { 9994 if (wpa_supplicant_global_iface_add(global, buf + 14)) 9995 reply_len = -1; 9996 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { 9997 if (wpa_supplicant_global_iface_remove(global, buf + 17)) 9998 reply_len = -1; 9999 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { 10000 reply_len = wpa_supplicant_global_iface_list( 10001 global, reply, reply_size); 10002 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { 10003 reply_len = wpa_supplicant_global_iface_interfaces( 10004 global, buf + 10, reply, reply_size); 10005#ifdef CONFIG_FST 10006 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { 10007 reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, 10008 reply, 10009 reply_size); 10010 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) { 10011 reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11, 10012 reply, 10013 reply_size); 10014 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) { 10015 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size); 10016#endif /* CONFIG_FST */ 10017 } else if (os_strcmp(buf, "TERMINATE") == 0) { 10018 wpa_supplicant_terminate_proc(global); 10019 } else if (os_strcmp(buf, "SUSPEND") == 0) { 10020 wpas_notify_suspend(global); 10021 } else if (os_strcmp(buf, "RESUME") == 0) { 10022 wpas_notify_resume(global); 10023 } else if (os_strncmp(buf, "SET ", 4) == 0) { 10024 if (wpas_global_ctrl_iface_set(global, buf + 4)) { 10025#ifdef CONFIG_P2P 10026 if (global->p2p_init_wpa_s) { 10027 os_free(reply); 10028 /* Check if P2P redirection would work for this 10029 * command. */ 10030 return wpa_supplicant_ctrl_iface_process( 10031 global->p2p_init_wpa_s, 10032 buf, resp_len); 10033 } 10034#endif /* CONFIG_P2P */ 10035 reply_len = -1; 10036 } 10037 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { 10038 if (wpas_global_ctrl_iface_dup_network(global, buf + 12)) 10039 reply_len = -1; 10040#ifndef CONFIG_NO_CONFIG_WRITE 10041 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { 10042 if (wpas_global_ctrl_iface_save_config(global)) 10043 reply_len = -1; 10044#endif /* CONFIG_NO_CONFIG_WRITE */ 10045 } else if (os_strcmp(buf, "STATUS") == 0) { 10046 reply_len = wpas_global_ctrl_iface_status(global, reply, 10047 reply_size); 10048#ifdef CONFIG_MODULE_TESTS 10049 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { 10050 if (wpas_module_tests() < 0) 10051 reply_len = -1; 10052#endif /* CONFIG_MODULE_TESTS */ 10053 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 10054 if (wpa_debug_reopen_file() < 0) 10055 reply_len = -1; 10056 } else { 10057 os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 10058 reply_len = 16; 10059 } 10060 10061 if (reply_len < 0) { 10062 os_memcpy(reply, "FAIL\n", 5); 10063 reply_len = 5; 10064 } 10065 10066 *resp_len = reply_len; 10067 return reply; 10068} 10069