blob: c4d8dfe34319b0bb7c9b99e6046c3d731d5505af [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / Control interface (shared code for all backends)
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003 * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010#ifdef CONFIG_TESTING_OPTIONS
11#include <net/ethernet.h>
12#include <netinet/ip.h>
13#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014
15#include "utils/common.h"
16#include "utils/eloop.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080017#include "utils/uuid.h"
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -070018#include "utils/module_tests.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include "common/version.h"
20#include "common/ieee802_11_defs.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070021#include "common/ieee802_11_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include "common/wpa_ctrl.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080023#include "crypto/tls.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080024#include "ap/hostapd.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070025#include "eap_peer/eap.h"
26#include "eapol_supp/eapol_supp_sm.h"
27#include "rsn_supp/wpa.h"
28#include "rsn_supp/preauth.h"
29#include "rsn_supp/pmksa_cache.h"
30#include "l2_packet/l2_packet.h"
31#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080032#include "fst/fst.h"
33#include "fst/fst_ctrl_iface.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "config.h"
35#include "wpa_supplicant_i.h"
36#include "driver_i.h"
37#include "wps_supplicant.h"
38#include "ibss_rsn.h"
39#include "ap.h"
40#include "p2p_supplicant.h"
41#include "p2p/p2p.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070042#include "hs20_supplicant.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070043#include "wifi_display.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070044#include "notify.h"
45#include "bss.h"
46#include "scan.h"
47#include "ctrl_iface.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080048#include "interworking.h"
Dmitry Shmidte19501d2011-03-16 14:32:18 -070049#include "blacklist.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070050#include "autoscan.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080051#include "wnm_sta.h"
Dmitry Shmidt818ea482014-03-10 13:15:21 -070052#include "offchannel.h"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070053#include "drivers/driver.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080054#include "mesh.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070055#include "dpp_supplicant.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070057static int wpa_supplicant_global_iface_list(struct wpa_global *global,
58 char *buf, int len);
59static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080060 const char *input,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070061 char *buf, int len);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -070062static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
63 char *val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070064
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070065
66#ifdef CONFIG_FILS
67
68static int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
69{
70 return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
71 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
72 (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
73 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
74}
75
76
77#ifdef CONFIG_FILS_SK_PFS
78static int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
79{
80 return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
81 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
82}
83#endif /* CONFIG_FILS_SK_PFS */
84
85#endif /* CONFIG_FILS */
86
87
Dmitry Shmidt04949592012-07-19 12:16:46 -070088static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
89{
90 char *pos;
91 u8 addr[ETH_ALEN], *filter = NULL, *n;
92 size_t count = 0;
93
94 pos = val;
95 while (pos) {
96 if (*pos == '\0')
97 break;
98 if (hwaddr_aton(pos, addr)) {
99 os_free(filter);
100 return -1;
101 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700102 n = os_realloc_array(filter, count + 1, ETH_ALEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700103 if (n == NULL) {
104 os_free(filter);
105 return -1;
106 }
107 filter = n;
108 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
109 count++;
110
111 pos = os_strchr(pos, ' ');
112 if (pos)
113 pos++;
114 }
115
116 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
117 os_free(wpa_s->bssid_filter);
118 wpa_s->bssid_filter = filter;
119 wpa_s->bssid_filter_count = count;
120
121 return 0;
122}
123
124
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800125static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
126{
127 char *pos;
128 u8 addr[ETH_ALEN], *bssid = NULL, *n;
129 struct wpa_ssid_value *ssid = NULL, *ns;
130 size_t count = 0, ssid_count = 0;
131 struct wpa_ssid *c;
132
133 /*
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800134 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800135 * SSID_SPEC ::= ssid <SSID_HEX>
136 * BSSID_SPEC ::= bssid <BSSID_HEX>
137 */
138
139 pos = val;
140 while (pos) {
141 if (*pos == '\0')
142 break;
143 if (os_strncmp(pos, "bssid ", 6) == 0) {
144 int res;
145 pos += 6;
146 res = hwaddr_aton2(pos, addr);
147 if (res < 0) {
148 os_free(ssid);
149 os_free(bssid);
150 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
151 "BSSID value '%s'", pos);
152 return -1;
153 }
154 pos += res;
155 n = os_realloc_array(bssid, count + 1, ETH_ALEN);
156 if (n == NULL) {
157 os_free(ssid);
158 os_free(bssid);
159 return -1;
160 }
161 bssid = n;
162 os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
163 count++;
164 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
165 char *end;
166 pos += 5;
167
168 end = pos;
169 while (*end) {
170 if (*end == '\0' || *end == ' ')
171 break;
172 end++;
173 }
174
175 ns = os_realloc_array(ssid, ssid_count + 1,
176 sizeof(struct wpa_ssid_value));
177 if (ns == NULL) {
178 os_free(ssid);
179 os_free(bssid);
180 return -1;
181 }
182 ssid = ns;
183
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700184 if ((end - pos) & 0x01 ||
185 end - pos > 2 * SSID_MAX_LEN ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800186 hexstr2bin(pos, ssid[ssid_count].ssid,
187 (end - pos) / 2) < 0) {
188 os_free(ssid);
189 os_free(bssid);
190 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
191 "SSID value '%s'", pos);
192 return -1;
193 }
194 ssid[ssid_count].ssid_len = (end - pos) / 2;
195 wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
196 ssid[ssid_count].ssid,
197 ssid[ssid_count].ssid_len);
198 ssid_count++;
199 pos = end;
200 } else {
201 wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
202 "'%s'", pos);
203 os_free(ssid);
204 os_free(bssid);
205 return -1;
206 }
207
208 pos = os_strchr(pos, ' ');
209 if (pos)
210 pos++;
211 }
212
213 wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
214 os_free(wpa_s->disallow_aps_bssid);
215 wpa_s->disallow_aps_bssid = bssid;
216 wpa_s->disallow_aps_bssid_count = count;
217
218 wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
219 os_free(wpa_s->disallow_aps_ssid);
220 wpa_s->disallow_aps_ssid = ssid;
221 wpa_s->disallow_aps_ssid_count = ssid_count;
222
223 if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
224 return 0;
225
226 c = wpa_s->current_ssid;
227 if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
228 return 0;
229
230 if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
231 !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
232 return 0;
233
234 wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
235 "because current AP was marked disallowed");
236
237#ifdef CONFIG_SME
238 wpa_s->sme.prev_bssid_set = 0;
239#endif /* CONFIG_SME */
240 wpa_s->reassociate = 1;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800241 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800242 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
243 wpa_supplicant_req_scan(wpa_s, 0, 0);
244
245 return 0;
246}
247
248
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700249#ifndef CONFIG_NO_CONFIG_BLOBS
250static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
251{
252 char *name = pos;
253 struct wpa_config_blob *blob;
254 size_t len;
255
256 pos = os_strchr(pos, ' ');
257 if (pos == NULL)
258 return -1;
259 *pos++ = '\0';
260 len = os_strlen(pos);
261 if (len & 1)
262 return -1;
263
264 wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
265 blob = os_zalloc(sizeof(*blob));
266 if (blob == NULL)
267 return -1;
268 blob->name = os_strdup(name);
269 blob->data = os_malloc(len / 2);
270 if (blob->name == NULL || blob->data == NULL) {
271 wpa_config_free_blob(blob);
272 return -1;
273 }
274
275 if (hexstr2bin(pos, blob->data, len / 2) < 0) {
276 wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
277 wpa_config_free_blob(blob);
278 return -1;
279 }
280 blob->len = len / 2;
281
282 wpa_config_set_blob(wpa_s->conf, blob);
283
284 return 0;
285}
286#endif /* CONFIG_NO_CONFIG_BLOBS */
287
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700288
289static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
290{
291 char *params;
292 char *pos;
293 int *freqs = NULL;
294 int ret;
295
296 if (atoi(cmd)) {
297 params = os_strchr(cmd, ' ');
298 os_free(wpa_s->manual_sched_scan_freqs);
299 if (params) {
300 params++;
301 pos = os_strstr(params, "freq=");
302 if (pos)
303 freqs = freq_range_to_channel_list(wpa_s,
304 pos + 5);
305 }
306 wpa_s->manual_sched_scan_freqs = freqs;
307 ret = wpas_start_pno(wpa_s);
308 } else {
309 ret = wpas_stop_pno(wpa_s);
310 }
311 return ret;
312}
313
314
Ravi Joshie6ccb162015-07-16 17:45:41 -0700315static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
316{
317 union wpa_event_data event;
318
319 if (os_strcmp(band, "AUTO") == 0)
320 wpa_s->setband = WPA_SETBAND_AUTO;
321 else if (os_strcmp(band, "5G") == 0)
322 wpa_s->setband = WPA_SETBAND_5G;
323 else if (os_strcmp(band, "2G") == 0)
324 wpa_s->setband = WPA_SETBAND_2G;
325 else
326 return -1;
327
328 if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
329 os_memset(&event, 0, sizeof(event));
330 event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
331 event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
332 wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event);
333 }
334
335 return 0;
336}
337
338
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700339static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
340 const char *cmd)
341{
342 struct wpabuf *lci;
343
344 if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
345 wpabuf_free(wpa_s->lci);
346 wpa_s->lci = NULL;
347 return 0;
348 }
349
350 lci = wpabuf_parse_bin(cmd);
351 if (!lci)
352 return -1;
353
354 if (os_get_reltime(&wpa_s->lci_time)) {
355 wpabuf_free(lci);
356 return -1;
357 }
358
359 wpabuf_free(wpa_s->lci);
360 wpa_s->lci = lci;
361
362 return 0;
363}
364
365
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800366static int
367wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd)
368{
369 int relative_rssi;
370
371 if (os_strcmp(cmd, "disable") == 0) {
372 wpa_s->srp.relative_rssi_set = 0;
373 return 0;
374 }
375
376 relative_rssi = atoi(cmd);
377 if (relative_rssi < 0 || relative_rssi > 100)
378 return -1;
379 wpa_s->srp.relative_rssi = relative_rssi;
380 wpa_s->srp.relative_rssi_set = 1;
381 return 0;
382}
383
384
385static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s,
386 const char *cmd)
387{
388 char *pos;
389 int adjust_rssi;
390
391 /* <band>:adjust_value */
392 pos = os_strchr(cmd, ':');
393 if (!pos)
394 return -1;
395 pos++;
396 adjust_rssi = atoi(pos);
397 if (adjust_rssi < -100 || adjust_rssi > 100)
398 return -1;
399
400 if (os_strncmp(cmd, "2G", 2) == 0)
401 wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G;
402 else if (os_strncmp(cmd, "5G", 2) == 0)
403 wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G;
404 else
405 return -1;
406
407 wpa_s->srp.relative_adjust_rssi = adjust_rssi;
408
409 return 0;
410}
411
412
413static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
414 const char *cmd)
415{
416 struct wpabuf *ric_ies;
417
418 if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
419 wpabuf_free(wpa_s->ric_ies);
420 wpa_s->ric_ies = NULL;
421 return 0;
422 }
423
424 ric_ies = wpabuf_parse_bin(cmd);
425 if (!ric_ies)
426 return -1;
427
428 wpabuf_free(wpa_s->ric_ies);
429 wpa_s->ric_ies = ric_ies;
430
431 return 0;
432}
433
434
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700435static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
436 char *cmd)
437{
438 char *value;
439 int ret = 0;
440
441 value = os_strchr(cmd, ' ');
442 if (value == NULL)
443 return -1;
444 *value++ = '\0';
445
446 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
447 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
448 eapol_sm_configure(wpa_s->eapol,
449 atoi(value), -1, -1, -1);
450 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
451 eapol_sm_configure(wpa_s->eapol,
452 -1, atoi(value), -1, -1);
453 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
454 eapol_sm_configure(wpa_s->eapol,
455 -1, -1, atoi(value), -1);
456 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
457 eapol_sm_configure(wpa_s->eapol,
458 -1, -1, -1, atoi(value));
459 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
460 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
Paul Stewart092955c2017-02-06 09:13:09 -0800461 atoi(value))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800463 } else {
464 value[-1] = '=';
465 wpa_config_process_global(wpa_s->conf, cmd, -1);
466 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700467 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
468 0) {
469 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
Paul Stewart092955c2017-02-06 09:13:09 -0800470 atoi(value))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800472 } else {
473 value[-1] = '=';
474 wpa_config_process_global(wpa_s->conf, cmd, -1);
475 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
Paul Stewart092955c2017-02-06 09:13:09 -0800477 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
478 atoi(value))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700479 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800480 } else {
481 value[-1] = '=';
482 wpa_config_process_global(wpa_s->conf, cmd, -1);
483 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700484 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
485 wpa_s->wps_fragment_size = atoi(value);
486#ifdef CONFIG_WPS_TESTING
487 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
488 long int val;
489 val = strtol(value, NULL, 0);
490 if (val < 0 || val > 0xff) {
491 ret = -1;
492 wpa_printf(MSG_DEBUG, "WPS: Invalid "
493 "wps_version_number %ld", val);
494 } else {
495 wps_version_number = val;
496 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
497 "version %u.%u",
498 (wps_version_number & 0xf0) >> 4,
499 wps_version_number & 0x0f);
500 }
501 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
502 wps_testing_dummy_cred = atoi(value);
503 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
504 wps_testing_dummy_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800505 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
506 wps_corrupt_pkhash = atoi(value);
507 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
508 wps_corrupt_pkhash);
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800509 } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
510 if (value[0] == '\0') {
511 wps_force_auth_types_in_use = 0;
512 } else {
513 wps_force_auth_types = strtol(value, NULL, 0);
514 wps_force_auth_types_in_use = 1;
515 }
516 } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
517 if (value[0] == '\0') {
518 wps_force_encr_types_in_use = 0;
519 } else {
520 wps_force_encr_types = strtol(value, NULL, 0);
521 wps_force_encr_types_in_use = 1;
522 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700523#endif /* CONFIG_WPS_TESTING */
524 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
525 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
526 ret = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800527#ifdef CONFIG_TDLS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700528#ifdef CONFIG_TDLS_TESTING
529 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 tdls_testing = strtol(value, NULL, 0);
531 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
532#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700533 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
534 int disabled = atoi(value);
535 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
536 if (disabled) {
537 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
538 ret = -1;
539 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
540 ret = -1;
541 wpa_tdls_enable(wpa_s->wpa, !disabled);
542#endif /* CONFIG_TDLS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800543 } else if (os_strcasecmp(cmd, "pno") == 0) {
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700544 ret = wpas_ctrl_pno(wpa_s, value);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700545 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
546 int disabled = atoi(value);
547 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
548 ret = -1;
549 else if (disabled)
550 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
551 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
552 if (os_strcmp(value, "disable") == 0)
553 wpa_s->set_sta_uapsd = 0;
554 else {
555 int be, bk, vi, vo;
556 char *pos;
557 /* format: BE,BK,VI,VO;max SP Length */
558 be = atoi(value);
559 pos = os_strchr(value, ',');
560 if (pos == NULL)
561 return -1;
562 pos++;
563 bk = atoi(pos);
564 pos = os_strchr(pos, ',');
565 if (pos == NULL)
566 return -1;
567 pos++;
568 vi = atoi(pos);
569 pos = os_strchr(pos, ',');
570 if (pos == NULL)
571 return -1;
572 pos++;
573 vo = atoi(pos);
574 /* ignore max SP Length for now */
575
576 wpa_s->set_sta_uapsd = 1;
577 wpa_s->sta_uapsd = 0;
578 if (be)
579 wpa_s->sta_uapsd |= BIT(0);
580 if (bk)
581 wpa_s->sta_uapsd |= BIT(1);
582 if (vi)
583 wpa_s->sta_uapsd |= BIT(2);
584 if (vo)
585 wpa_s->sta_uapsd |= BIT(3);
586 }
Jouni Malinen21d6bc82012-04-10 16:17:59 -0700587 } else if (os_strcasecmp(cmd, "ps") == 0) {
588 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700589#ifdef CONFIG_WIFI_DISPLAY
590 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800591 int enabled = !!atoi(value);
592 if (enabled && !wpa_s->global->p2p)
593 ret = -1;
594 else
595 wifi_display_enable(wpa_s->global, enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700596#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700597 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
598 ret = set_bssid_filter(wpa_s, value);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800599 } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
600 ret = set_disallow_aps(wpa_s, value);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800601 } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
602 wpa_s->no_keep_alive = !!atoi(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700603#ifdef CONFIG_DPP
604 } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
605 os_free(wpa_s->dpp_configurator_params);
606 wpa_s->dpp_configurator_params = os_strdup(value);
607#endif /* CONFIG_DPP */
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700608#ifdef CONFIG_TESTING_OPTIONS
609 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
610 wpa_s->ext_mgmt_frame_handling = !!atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800611 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
612 wpa_s->ext_eapol_frame_io = !!atoi(value);
613#ifdef CONFIG_AP
614 if (wpa_s->ap_iface) {
615 wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
616 wpa_s->ext_eapol_frame_io;
617 }
618#endif /* CONFIG_AP */
619 } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
620 wpa_s->extra_roc_dur = atoi(value);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800621 } else if (os_strcasecmp(cmd, "test_failure") == 0) {
622 wpa_s->test_failure = atoi(value);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800623 } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
624 wpa_s->p2p_go_csa_on_inv = !!atoi(value);
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700625 } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
626 wpa_s->ignore_auth_resp = !!atoi(value);
627 } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
628 wpa_s->ignore_assoc_disallow = !!atoi(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700629 wpa_drv_ignore_assoc_disallow(wpa_s,
630 wpa_s->ignore_assoc_disallow);
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700631 } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
632 wpa_s->reject_btm_req_reason = atoi(value);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800633 } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
634 os_free(wpa_s->get_pref_freq_list_override);
635 if (!value[0])
636 wpa_s->get_pref_freq_list_override = NULL;
637 else
638 wpa_s->get_pref_freq_list_override = os_strdup(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700639 } else if (os_strcasecmp(cmd, "sae_commit_override") == 0) {
640 wpabuf_free(wpa_s->sae_commit_override);
641 if (value[0] == '\0')
642 wpa_s->sae_commit_override = NULL;
643 else
644 wpa_s->sae_commit_override = wpabuf_parse_bin(value);
645#ifdef CONFIG_DPP
646 } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
647 os_free(wpa_s->dpp_config_obj_override);
648 wpa_s->dpp_config_obj_override = os_strdup(value);
649 } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
650 os_free(wpa_s->dpp_discovery_override);
651 wpa_s->dpp_discovery_override = os_strdup(value);
652 } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
653 os_free(wpa_s->dpp_groups_override);
654 wpa_s->dpp_groups_override = os_strdup(value);
655 } else if (os_strcasecmp(cmd,
656 "dpp_ignore_netaccesskey_mismatch") == 0) {
657 wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
658#endif /* CONFIG_DPP */
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700659#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700660#ifndef CONFIG_NO_CONFIG_BLOBS
661 } else if (os_strcmp(cmd, "blob") == 0) {
662 ret = wpas_ctrl_set_blob(wpa_s, value);
663#endif /* CONFIG_NO_CONFIG_BLOBS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664 } else if (os_strcasecmp(cmd, "setband") == 0) {
Ravi Joshie6ccb162015-07-16 17:45:41 -0700665 ret = wpas_ctrl_set_band(wpa_s, value);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800666#ifdef CONFIG_MBO
667 } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
668 ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
Paul Stewart092955c2017-02-06 09:13:09 -0800669 if (ret == 0) {
670 value[-1] = '=';
671 wpa_config_process_global(wpa_s->conf, cmd, -1);
672 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800673 } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
674 wpas_mbo_update_cell_capa(wpa_s, atoi(value));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700675 } else if (os_strcasecmp(cmd, "oce") == 0) {
676 wpa_s->conf->oce = atoi(value);
677 if (wpa_s->conf->oce) {
678 if ((wpa_s->conf->oce & OCE_STA) &&
679 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
680 wpa_s->enable_oce = OCE_STA;
681
682 if ((wpa_s->conf->oce & OCE_STA_CFON) &&
683 (wpa_s->drv_flags &
684 WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
685 /* TODO: Need to add STA-CFON support */
686 wpa_printf(MSG_ERROR,
687 "OCE STA-CFON feature is not yet supported");
688 return -1;
689 }
690 } else {
691 wpa_s->enable_oce = 0;
692 }
693 wpa_supplicant_set_default_scan_ies(wpa_s);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800694#endif /* CONFIG_MBO */
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700695 } else if (os_strcasecmp(cmd, "lci") == 0) {
696 ret = wpas_ctrl_iface_set_lci(wpa_s, value);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800697 } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) {
698 ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800699 } else if (os_strcasecmp(cmd, "relative_rssi") == 0) {
700 ret = wpas_ctrl_set_relative_rssi(wpa_s, value);
701 } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) {
702 ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value);
703 } else if (os_strcasecmp(cmd, "ric_ies") == 0) {
704 ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700705 } else if (os_strcasecmp(cmd, "roaming") == 0) {
706 ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700707 } else {
708 value[-1] = '=';
709 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
710 if (ret == 0)
711 wpa_supplicant_update_config(wpa_s);
712 }
713
714 return ret;
715}
716
717
718static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
719 char *cmd, char *buf, size_t buflen)
720{
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700721 int res = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700722
723 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
724
725 if (os_strcmp(cmd, "version") == 0) {
726 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700727 } else if (os_strcasecmp(cmd, "country") == 0) {
728 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
729 res = os_snprintf(buf, buflen, "%c%c",
730 wpa_s->conf->country[0],
731 wpa_s->conf->country[1]);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700732#ifdef CONFIG_WIFI_DISPLAY
733 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800734 int enabled;
735 if (wpa_s->global->p2p == NULL ||
736 wpa_s->global->p2p_disabled)
737 enabled = 0;
738 else
739 enabled = wpa_s->global->wifi_display;
740 res = os_snprintf(buf, buflen, "%d", enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700741#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700742#ifdef CONFIG_TESTING_GET_GTK
743 } else if (os_strcmp(cmd, "gtk") == 0) {
744 if (wpa_s->last_gtk_len == 0)
745 return -1;
746 res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
747 wpa_s->last_gtk_len);
748 return res;
749#endif /* CONFIG_TESTING_GET_GTK */
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800750 } else if (os_strcmp(cmd, "tls_library") == 0) {
751 res = tls_get_library_version(buf, buflen);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700752#ifdef CONFIG_TESTING_OPTIONS
753 } else if (os_strcmp(cmd, "anonce") == 0) {
754 return wpa_snprintf_hex(buf, buflen,
755 wpa_sm_get_anonce(wpa_s->wpa),
756 WPA_NONCE_LEN);
757#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800758 } else {
759 res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700760 }
761
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800762 if (os_snprintf_error(buflen, res))
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700763 return -1;
764 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700765}
766
767
768#ifdef IEEE8021X_EAPOL
769static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
770 char *addr)
771{
772 u8 bssid[ETH_ALEN];
773 struct wpa_ssid *ssid = wpa_s->current_ssid;
774
775 if (hwaddr_aton(addr, bssid)) {
776 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
777 "'%s'", addr);
778 return -1;
779 }
780
781 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
782 rsn_preauth_deinit(wpa_s->wpa);
783 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
784 return -1;
785
786 return 0;
787}
788#endif /* IEEE8021X_EAPOL */
789
790
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700791#ifdef CONFIG_TDLS
792
793static int wpa_supplicant_ctrl_iface_tdls_discover(
794 struct wpa_supplicant *wpa_s, char *addr)
795{
796 u8 peer[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800797 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700798
799 if (hwaddr_aton(addr, peer)) {
800 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
801 "address '%s'", addr);
802 return -1;
803 }
804
805 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
806 MAC2STR(peer));
807
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800808 if (wpa_tdls_is_external_setup(wpa_s->wpa))
809 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
810 else
811 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
812
813 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700814}
815
816
817static int wpa_supplicant_ctrl_iface_tdls_setup(
818 struct wpa_supplicant *wpa_s, char *addr)
819{
820 u8 peer[ETH_ALEN];
821 int ret;
822
823 if (hwaddr_aton(addr, peer)) {
824 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
825 "address '%s'", addr);
826 return -1;
827 }
828
829 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
830 MAC2STR(peer));
831
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800832 if ((wpa_s->conf->tdls_external_control) &&
833 wpa_tdls_is_external_setup(wpa_s->wpa))
834 return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
835
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800836 wpa_tdls_remove(wpa_s->wpa, peer);
837
838 if (wpa_tdls_is_external_setup(wpa_s->wpa))
839 ret = wpa_tdls_start(wpa_s->wpa, peer);
840 else
841 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800842
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700843 return ret;
844}
845
846
847static int wpa_supplicant_ctrl_iface_tdls_teardown(
848 struct wpa_supplicant *wpa_s, char *addr)
849{
850 u8 peer[ETH_ALEN];
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700851 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700852
Dmitry Shmidt43cb5782014-06-16 16:23:22 -0700853 if (os_strcmp(addr, "*") == 0) {
854 /* remove everyone */
855 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
856 wpa_tdls_teardown_peers(wpa_s->wpa);
857 return 0;
858 }
859
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700860 if (hwaddr_aton(addr, peer)) {
861 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
862 "address '%s'", addr);
863 return -1;
864 }
865
866 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
867 MAC2STR(peer));
868
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800869 if ((wpa_s->conf->tdls_external_control) &&
870 wpa_tdls_is_external_setup(wpa_s->wpa))
871 return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
872
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700873 if (wpa_tdls_is_external_setup(wpa_s->wpa))
874 ret = wpa_tdls_teardown_link(
875 wpa_s->wpa, peer,
876 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
877 else
878 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
879
880 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700881}
882
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700883
884static int ctrl_iface_get_capability_tdls(
885 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
886{
887 int ret;
888
889 ret = os_snprintf(buf, buflen, "%s\n",
890 wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
891 (wpa_s->drv_flags &
892 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
893 "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800894 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700895 return -1;
896 return ret;
897}
898
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800899
900static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
901 struct wpa_supplicant *wpa_s, char *cmd)
902{
903 u8 peer[ETH_ALEN];
904 struct hostapd_freq_params freq_params;
905 u8 oper_class;
906 char *pos, *end;
907
908 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
909 wpa_printf(MSG_INFO,
910 "tdls_chanswitch: Only supported with external setup");
911 return -1;
912 }
913
914 os_memset(&freq_params, 0, sizeof(freq_params));
915
916 pos = os_strchr(cmd, ' ');
917 if (pos == NULL)
918 return -1;
919 *pos++ = '\0';
920
921 oper_class = strtol(pos, &end, 10);
922 if (pos == end) {
923 wpa_printf(MSG_INFO,
924 "tdls_chanswitch: Invalid op class provided");
925 return -1;
926 }
927
928 pos = end;
929 freq_params.freq = atoi(pos);
930 if (freq_params.freq == 0) {
931 wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
932 return -1;
933 }
934
935#define SET_FREQ_SETTING(str) \
936 do { \
937 const char *pos2 = os_strstr(pos, " " #str "="); \
938 if (pos2) { \
939 pos2 += sizeof(" " #str "=") - 1; \
940 freq_params.str = atoi(pos2); \
941 } \
942 } while (0)
943
944 SET_FREQ_SETTING(center_freq1);
945 SET_FREQ_SETTING(center_freq2);
946 SET_FREQ_SETTING(bandwidth);
947 SET_FREQ_SETTING(sec_channel_offset);
948#undef SET_FREQ_SETTING
949
950 freq_params.ht_enabled = !!os_strstr(pos, " ht");
951 freq_params.vht_enabled = !!os_strstr(pos, " vht");
952
953 if (hwaddr_aton(cmd, peer)) {
954 wpa_printf(MSG_DEBUG,
955 "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
956 cmd);
957 return -1;
958 }
959
960 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
961 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
962 MAC2STR(peer), oper_class, freq_params.freq,
963 freq_params.center_freq1, freq_params.center_freq2,
964 freq_params.bandwidth, freq_params.sec_channel_offset,
965 freq_params.ht_enabled ? " HT" : "",
966 freq_params.vht_enabled ? " VHT" : "");
967
968 return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
969 &freq_params);
970}
971
972
973static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
974 struct wpa_supplicant *wpa_s, char *cmd)
975{
976 u8 peer[ETH_ALEN];
977
978 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
979 wpa_printf(MSG_INFO,
980 "tdls_chanswitch: Only supported with external setup");
981 return -1;
982 }
983
984 if (hwaddr_aton(cmd, peer)) {
985 wpa_printf(MSG_DEBUG,
986 "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
987 cmd);
988 return -1;
989 }
990
991 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
992 MAC2STR(peer));
993
994 return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
995}
996
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -0700997
998static int wpa_supplicant_ctrl_iface_tdls_link_status(
999 struct wpa_supplicant *wpa_s, const char *addr,
1000 char *buf, size_t buflen)
1001{
1002 u8 peer[ETH_ALEN];
1003 const char *tdls_status;
1004 int ret;
1005
1006 if (hwaddr_aton(addr, peer)) {
1007 wpa_printf(MSG_DEBUG,
1008 "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'",
1009 addr);
1010 return -1;
1011 }
1012 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR,
1013 MAC2STR(peer));
1014
1015 tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
1016 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status);
1017 ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status);
1018 if (os_snprintf_error(buflen, ret))
1019 return -1;
1020
1021 return ret;
1022}
1023
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024#endif /* CONFIG_TDLS */
1025
1026
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001027static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
1028{
1029 char *token, *context = NULL;
1030 struct wmm_ac_ts_setup_params params = {
1031 .tsid = 0xff,
1032 .direction = 0xff,
1033 };
1034
1035 while ((token = str_token(cmd, " ", &context))) {
1036 if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
1037 sscanf(token, "up=%i", &params.user_priority) == 1 ||
1038 sscanf(token, "nominal_msdu_size=%i",
1039 &params.nominal_msdu_size) == 1 ||
1040 sscanf(token, "mean_data_rate=%i",
1041 &params.mean_data_rate) == 1 ||
1042 sscanf(token, "min_phy_rate=%i",
1043 &params.minimum_phy_rate) == 1 ||
1044 sscanf(token, "sba=%i",
1045 &params.surplus_bandwidth_allowance) == 1)
1046 continue;
1047
1048 if (os_strcasecmp(token, "downlink") == 0) {
1049 params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
1050 } else if (os_strcasecmp(token, "uplink") == 0) {
1051 params.direction = WMM_TSPEC_DIRECTION_UPLINK;
1052 } else if (os_strcasecmp(token, "bidi") == 0) {
1053 params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
1054 } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
1055 params.fixed_nominal_msdu = 1;
1056 } else {
1057 wpa_printf(MSG_DEBUG,
1058 "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
1059 token);
1060 return -1;
1061 }
1062
1063 }
1064
1065 return wpas_wmm_ac_addts(wpa_s, &params);
1066}
1067
1068
1069static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
1070{
1071 u8 tsid = atoi(cmd);
1072
1073 return wpas_wmm_ac_delts(wpa_s, tsid);
1074}
1075
1076
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001077#ifdef CONFIG_IEEE80211R
1078static int wpa_supplicant_ctrl_iface_ft_ds(
1079 struct wpa_supplicant *wpa_s, char *addr)
1080{
1081 u8 target_ap[ETH_ALEN];
1082 struct wpa_bss *bss;
1083 const u8 *mdie;
1084
1085 if (hwaddr_aton(addr, target_ap)) {
1086 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
1087 "address '%s'", addr);
1088 return -1;
1089 }
1090
1091 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
1092
1093 bss = wpa_bss_get_bssid(wpa_s, target_ap);
1094 if (bss)
1095 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
1096 else
1097 mdie = NULL;
1098
1099 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
1100}
1101#endif /* CONFIG_IEEE80211R */
1102
1103
1104#ifdef CONFIG_WPS
1105static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
1106 char *cmd)
1107{
1108 u8 bssid[ETH_ALEN], *_bssid = bssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -07001109#ifdef CONFIG_P2P
1110 u8 p2p_dev_addr[ETH_ALEN];
1111#endif /* CONFIG_P2P */
1112#ifdef CONFIG_AP
1113 u8 *_p2p_dev_addr = NULL;
1114#endif /* CONFIG_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001115
Dmitry Shmidtc0a8db02013-11-08 11:18:33 -08001116 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001117 _bssid = NULL;
1118#ifdef CONFIG_P2P
1119 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
1120 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
1121 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
1122 "P2P Device Address '%s'",
1123 cmd + 13);
1124 return -1;
1125 }
1126 _p2p_dev_addr = p2p_dev_addr;
1127#endif /* CONFIG_P2P */
1128 } else if (hwaddr_aton(cmd, bssid)) {
1129 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
1130 cmd);
1131 return -1;
1132 }
1133
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001134#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001135 if (wpa_s->ap_iface)
1136 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
1137#endif /* CONFIG_AP */
1138
1139 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
1140}
1141
1142
1143static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
1144 char *cmd, char *buf,
1145 size_t buflen)
1146{
1147 u8 bssid[ETH_ALEN], *_bssid = bssid;
1148 char *pin;
1149 int ret;
1150
1151 pin = os_strchr(cmd, ' ');
1152 if (pin)
1153 *pin++ = '\0';
1154
1155 if (os_strcmp(cmd, "any") == 0)
1156 _bssid = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001157 else if (os_strcmp(cmd, "get") == 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001158 if (wps_generate_pin((unsigned int *) &ret) < 0)
1159 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001160 goto done;
1161 } else if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001162 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
1163 cmd);
1164 return -1;
1165 }
1166
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001167#ifdef CONFIG_AP
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001168 if (wpa_s->ap_iface) {
1169 int timeout = 0;
1170 char *pos;
1171
1172 if (pin) {
1173 pos = os_strchr(pin, ' ');
1174 if (pos) {
1175 *pos++ = '\0';
1176 timeout = atoi(pos);
1177 }
1178 }
1179
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001180 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001181 buf, buflen, timeout);
1182 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001183#endif /* CONFIG_AP */
1184
1185 if (pin) {
1186 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
1187 DEV_PW_DEFAULT);
1188 if (ret < 0)
1189 return -1;
1190 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001191 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001192 return -1;
1193 return ret;
1194 }
1195
1196 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
1197 if (ret < 0)
1198 return -1;
1199
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001200done:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001201 /* Return the generated PIN */
1202 ret = os_snprintf(buf, buflen, "%08d", ret);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001203 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001204 return -1;
1205 return ret;
1206}
1207
1208
1209static int wpa_supplicant_ctrl_iface_wps_check_pin(
1210 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1211{
1212 char pin[9];
1213 size_t len;
1214 char *pos;
1215 int ret;
1216
1217 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
1218 (u8 *) cmd, os_strlen(cmd));
1219 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
1220 if (*pos < '0' || *pos > '9')
1221 continue;
1222 pin[len++] = *pos;
1223 if (len == 9) {
1224 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
1225 return -1;
1226 }
1227 }
1228 if (len != 4 && len != 8) {
1229 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
1230 return -1;
1231 }
1232 pin[len] = '\0';
1233
1234 if (len == 8) {
1235 unsigned int pin_val;
1236 pin_val = atoi(pin);
1237 if (!wps_pin_valid(pin_val)) {
1238 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
1239 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001240 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001241 return -1;
1242 return ret;
1243 }
1244 }
1245
1246 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001247 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001248 return -1;
1249
1250 return ret;
1251}
1252
1253
Dmitry Shmidt04949592012-07-19 12:16:46 -07001254#ifdef CONFIG_WPS_NFC
1255
1256static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
1257 char *cmd)
1258{
1259 u8 bssid[ETH_ALEN], *_bssid = bssid;
1260
1261 if (cmd == NULL || cmd[0] == '\0')
1262 _bssid = NULL;
1263 else if (hwaddr_aton(cmd, bssid))
1264 return -1;
1265
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001266 return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
1267 0, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001268}
1269
1270
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001271static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
1272 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1273{
1274 int ndef;
1275 struct wpabuf *buf;
1276 int res;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001277 char *pos;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001278
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001279 pos = os_strchr(cmd, ' ');
1280 if (pos)
1281 *pos++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001282 if (os_strcmp(cmd, "WPS") == 0)
1283 ndef = 0;
1284 else if (os_strcmp(cmd, "NDEF") == 0)
1285 ndef = 1;
1286 else
1287 return -1;
1288
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001289 buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001290 if (buf == NULL)
1291 return -1;
1292
1293 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1294 wpabuf_len(buf));
1295 reply[res++] = '\n';
1296 reply[res] = '\0';
1297
1298 wpabuf_free(buf);
1299
1300 return res;
1301}
1302
1303
Dmitry Shmidt04949592012-07-19 12:16:46 -07001304static int wpa_supplicant_ctrl_iface_wps_nfc_token(
1305 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1306{
1307 int ndef;
1308 struct wpabuf *buf;
1309 int res;
1310
1311 if (os_strcmp(cmd, "WPS") == 0)
1312 ndef = 0;
1313 else if (os_strcmp(cmd, "NDEF") == 0)
1314 ndef = 1;
1315 else
1316 return -1;
1317
1318 buf = wpas_wps_nfc_token(wpa_s, ndef);
1319 if (buf == NULL)
1320 return -1;
1321
1322 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1323 wpabuf_len(buf));
1324 reply[res++] = '\n';
1325 reply[res] = '\0';
1326
1327 wpabuf_free(buf);
1328
1329 return res;
1330}
1331
1332
1333static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
1334 struct wpa_supplicant *wpa_s, char *pos)
1335{
1336 size_t len;
1337 struct wpabuf *buf;
1338 int ret;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001339 char *freq;
1340 int forced_freq = 0;
1341
1342 freq = strstr(pos, " freq=");
1343 if (freq) {
1344 *freq = '\0';
1345 freq += 6;
1346 forced_freq = atoi(freq);
1347 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001348
1349 len = os_strlen(pos);
1350 if (len & 0x01)
1351 return -1;
1352 len /= 2;
1353
1354 buf = wpabuf_alloc(len);
1355 if (buf == NULL)
1356 return -1;
1357 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
1358 wpabuf_free(buf);
1359 return -1;
1360 }
1361
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001362 ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001363 wpabuf_free(buf);
1364
1365 return ret;
1366}
1367
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001368
1369static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001370 char *reply, size_t max_len,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001371 int ndef)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001372{
1373 struct wpabuf *buf;
1374 int res;
1375
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001376 buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001377 if (buf == NULL)
1378 return -1;
1379
1380 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1381 wpabuf_len(buf));
1382 reply[res++] = '\n';
1383 reply[res] = '\0';
1384
1385 wpabuf_free(buf);
1386
1387 return res;
1388}
1389
1390
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001391#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001392static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
1393 char *reply, size_t max_len,
1394 int ndef)
1395{
1396 struct wpabuf *buf;
1397 int res;
1398
1399 buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
1400 if (buf == NULL) {
1401 wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
1402 return -1;
1403 }
1404
1405 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1406 wpabuf_len(buf));
1407 reply[res++] = '\n';
1408 reply[res] = '\0';
1409
1410 wpabuf_free(buf);
1411
1412 return res;
1413}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001414#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001415
1416
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001417static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
1418 char *cmd, char *reply,
1419 size_t max_len)
1420{
1421 char *pos;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001422 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001423
1424 pos = os_strchr(cmd, ' ');
1425 if (pos == NULL)
1426 return -1;
1427 *pos++ = '\0';
1428
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001429 if (os_strcmp(cmd, "WPS") == 0)
1430 ndef = 0;
1431 else if (os_strcmp(cmd, "NDEF") == 0)
1432 ndef = 1;
1433 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001434 return -1;
1435
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001436 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001437 if (!ndef)
1438 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001439 return wpas_ctrl_nfc_get_handover_req_wps(
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001440 wpa_s, reply, max_len, ndef);
1441 }
1442
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001443#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001444 if (os_strcmp(pos, "P2P-CR") == 0) {
1445 return wpas_ctrl_nfc_get_handover_req_p2p(
1446 wpa_s, reply, max_len, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001447 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001448#endif /* CONFIG_P2P */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001449
1450 return -1;
1451}
1452
1453
1454static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001455 char *reply, size_t max_len,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001456 int ndef, int cr, char *uuid)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001457{
1458 struct wpabuf *buf;
1459 int res;
1460
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001461 buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001462 if (buf == NULL)
1463 return -1;
1464
1465 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1466 wpabuf_len(buf));
1467 reply[res++] = '\n';
1468 reply[res] = '\0';
1469
1470 wpabuf_free(buf);
1471
1472 return res;
1473}
1474
1475
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001476#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001477static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
1478 char *reply, size_t max_len,
1479 int ndef, int tag)
1480{
1481 struct wpabuf *buf;
1482 int res;
1483
1484 buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
1485 if (buf == NULL)
1486 return -1;
1487
1488 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1489 wpabuf_len(buf));
1490 reply[res++] = '\n';
1491 reply[res] = '\0';
1492
1493 wpabuf_free(buf);
1494
1495 return res;
1496}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001497#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001498
1499
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001500static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
1501 char *cmd, char *reply,
1502 size_t max_len)
1503{
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001504 char *pos, *pos2;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001505 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001506
1507 pos = os_strchr(cmd, ' ');
1508 if (pos == NULL)
1509 return -1;
1510 *pos++ = '\0';
1511
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001512 if (os_strcmp(cmd, "WPS") == 0)
1513 ndef = 0;
1514 else if (os_strcmp(cmd, "NDEF") == 0)
1515 ndef = 1;
1516 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001517 return -1;
1518
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001519 pos2 = os_strchr(pos, ' ');
1520 if (pos2)
1521 *pos2++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001522 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001523 if (!ndef)
1524 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001525 return wpas_ctrl_nfc_get_handover_sel_wps(
1526 wpa_s, reply, max_len, ndef,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001527 os_strcmp(pos, "WPS-CR") == 0, pos2);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001528 }
1529
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001530#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001531 if (os_strcmp(pos, "P2P-CR") == 0) {
1532 return wpas_ctrl_nfc_get_handover_sel_p2p(
1533 wpa_s, reply, max_len, ndef, 0);
1534 }
1535
1536 if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
1537 return wpas_ctrl_nfc_get_handover_sel_p2p(
1538 wpa_s, reply, max_len, ndef, 1);
1539 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001540#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001541
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001542 return -1;
1543}
1544
1545
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001546static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
1547 char *cmd)
1548{
1549 size_t len;
1550 struct wpabuf *req, *sel;
1551 int ret;
1552 char *pos, *role, *type, *pos2;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001553#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001554 char *freq;
1555 int forced_freq = 0;
1556
1557 freq = strstr(cmd, " freq=");
1558 if (freq) {
1559 *freq = '\0';
1560 freq += 6;
1561 forced_freq = atoi(freq);
1562 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001563#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001564
1565 role = cmd;
1566 pos = os_strchr(role, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001567 if (pos == NULL) {
1568 wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001569 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001570 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001571 *pos++ = '\0';
1572
1573 type = pos;
1574 pos = os_strchr(type, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001575 if (pos == NULL) {
1576 wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001577 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001578 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001579 *pos++ = '\0';
1580
1581 pos2 = os_strchr(pos, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001582 if (pos2 == NULL) {
1583 wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001584 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001585 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001586 *pos2++ = '\0';
1587
1588 len = os_strlen(pos);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001589 if (len & 0x01) {
1590 wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001591 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001592 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001593 len /= 2;
1594
1595 req = wpabuf_alloc(len);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001596 if (req == NULL) {
1597 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001598 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001599 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001600 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001601 wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001602 wpabuf_free(req);
1603 return -1;
1604 }
1605
1606 len = os_strlen(pos2);
1607 if (len & 0x01) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001608 wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001609 wpabuf_free(req);
1610 return -1;
1611 }
1612 len /= 2;
1613
1614 sel = wpabuf_alloc(len);
1615 if (sel == NULL) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001616 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001617 wpabuf_free(req);
1618 return -1;
1619 }
1620 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001621 wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001622 wpabuf_free(req);
1623 wpabuf_free(sel);
1624 return -1;
1625 }
1626
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001627 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
1628 role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
1629
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001630 if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
1631 ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001632#ifdef CONFIG_AP
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001633 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
1634 {
1635 ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
1636 if (ret < 0)
1637 ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001638#endif /* CONFIG_AP */
1639#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001640 } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
1641 {
1642 ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
1643 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
1644 {
1645 ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
1646 forced_freq);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001647#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001648 } else {
1649 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
1650 "reported: role=%s type=%s", role, type);
1651 ret = -1;
1652 }
1653 wpabuf_free(req);
1654 wpabuf_free(sel);
1655
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001656 if (ret)
1657 wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
1658
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001659 return ret;
1660}
1661
Dmitry Shmidt04949592012-07-19 12:16:46 -07001662#endif /* CONFIG_WPS_NFC */
1663
1664
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001665static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
1666 char *cmd)
1667{
1668 u8 bssid[ETH_ALEN];
1669 char *pin;
1670 char *new_ssid;
1671 char *new_auth;
1672 char *new_encr;
1673 char *new_key;
1674 struct wps_new_ap_settings ap;
1675
1676 pin = os_strchr(cmd, ' ');
1677 if (pin == NULL)
1678 return -1;
1679 *pin++ = '\0';
1680
1681 if (hwaddr_aton(cmd, bssid)) {
1682 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1683 cmd);
1684 return -1;
1685 }
1686
1687 new_ssid = os_strchr(pin, ' ');
1688 if (new_ssid == NULL)
1689 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
1690 *new_ssid++ = '\0';
1691
1692 new_auth = os_strchr(new_ssid, ' ');
1693 if (new_auth == NULL)
1694 return -1;
1695 *new_auth++ = '\0';
1696
1697 new_encr = os_strchr(new_auth, ' ');
1698 if (new_encr == NULL)
1699 return -1;
1700 *new_encr++ = '\0';
1701
1702 new_key = os_strchr(new_encr, ' ');
1703 if (new_key == NULL)
1704 return -1;
1705 *new_key++ = '\0';
1706
1707 os_memset(&ap, 0, sizeof(ap));
1708 ap.ssid_hex = new_ssid;
1709 ap.auth = new_auth;
1710 ap.encr = new_encr;
1711 ap.key_hex = new_key;
1712 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1713}
1714
1715
1716#ifdef CONFIG_AP
1717static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1718 char *cmd, char *buf,
1719 size_t buflen)
1720{
1721 int timeout = 300;
1722 char *pos;
1723 const char *pin_txt;
1724
1725 if (!wpa_s->ap_iface)
1726 return -1;
1727
1728 pos = os_strchr(cmd, ' ');
1729 if (pos)
1730 *pos++ = '\0';
1731
1732 if (os_strcmp(cmd, "disable") == 0) {
1733 wpas_wps_ap_pin_disable(wpa_s);
1734 return os_snprintf(buf, buflen, "OK\n");
1735 }
1736
1737 if (os_strcmp(cmd, "random") == 0) {
1738 if (pos)
1739 timeout = atoi(pos);
1740 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1741 if (pin_txt == NULL)
1742 return -1;
1743 return os_snprintf(buf, buflen, "%s", pin_txt);
1744 }
1745
1746 if (os_strcmp(cmd, "get") == 0) {
1747 pin_txt = wpas_wps_ap_pin_get(wpa_s);
1748 if (pin_txt == NULL)
1749 return -1;
1750 return os_snprintf(buf, buflen, "%s", pin_txt);
1751 }
1752
1753 if (os_strcmp(cmd, "set") == 0) {
1754 char *pin;
1755 if (pos == NULL)
1756 return -1;
1757 pin = pos;
1758 pos = os_strchr(pos, ' ');
1759 if (pos) {
1760 *pos++ = '\0';
1761 timeout = atoi(pos);
1762 }
1763 if (os_strlen(pin) > buflen)
1764 return -1;
1765 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1766 return -1;
1767 return os_snprintf(buf, buflen, "%s", pin);
1768 }
1769
1770 return -1;
1771}
1772#endif /* CONFIG_AP */
1773
1774
1775#ifdef CONFIG_WPS_ER
1776static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1777 char *cmd)
1778{
1779 char *uuid = cmd, *pin, *pos;
1780 u8 addr_buf[ETH_ALEN], *addr = NULL;
1781 pin = os_strchr(uuid, ' ');
1782 if (pin == NULL)
1783 return -1;
1784 *pin++ = '\0';
1785 pos = os_strchr(pin, ' ');
1786 if (pos) {
1787 *pos++ = '\0';
1788 if (hwaddr_aton(pos, addr_buf) == 0)
1789 addr = addr_buf;
1790 }
1791 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1792}
1793
1794
1795static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1796 char *cmd)
1797{
1798 char *uuid = cmd, *pin;
1799 pin = os_strchr(uuid, ' ');
1800 if (pin == NULL)
1801 return -1;
1802 *pin++ = '\0';
1803 return wpas_wps_er_learn(wpa_s, uuid, pin);
1804}
1805
1806
1807static int wpa_supplicant_ctrl_iface_wps_er_set_config(
1808 struct wpa_supplicant *wpa_s, char *cmd)
1809{
1810 char *uuid = cmd, *id;
1811 id = os_strchr(uuid, ' ');
1812 if (id == NULL)
1813 return -1;
1814 *id++ = '\0';
1815 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1816}
1817
1818
1819static int wpa_supplicant_ctrl_iface_wps_er_config(
1820 struct wpa_supplicant *wpa_s, char *cmd)
1821{
1822 char *pin;
1823 char *new_ssid;
1824 char *new_auth;
1825 char *new_encr;
1826 char *new_key;
1827 struct wps_new_ap_settings ap;
1828
1829 pin = os_strchr(cmd, ' ');
1830 if (pin == NULL)
1831 return -1;
1832 *pin++ = '\0';
1833
1834 new_ssid = os_strchr(pin, ' ');
1835 if (new_ssid == NULL)
1836 return -1;
1837 *new_ssid++ = '\0';
1838
1839 new_auth = os_strchr(new_ssid, ' ');
1840 if (new_auth == NULL)
1841 return -1;
1842 *new_auth++ = '\0';
1843
1844 new_encr = os_strchr(new_auth, ' ');
1845 if (new_encr == NULL)
1846 return -1;
1847 *new_encr++ = '\0';
1848
1849 new_key = os_strchr(new_encr, ' ');
1850 if (new_key == NULL)
1851 return -1;
1852 *new_key++ = '\0';
1853
1854 os_memset(&ap, 0, sizeof(ap));
1855 ap.ssid_hex = new_ssid;
1856 ap.auth = new_auth;
1857 ap.encr = new_encr;
1858 ap.key_hex = new_key;
1859 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1860}
Dmitry Shmidt04949592012-07-19 12:16:46 -07001861
1862
1863#ifdef CONFIG_WPS_NFC
1864static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1865 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1866{
1867 int ndef;
1868 struct wpabuf *buf;
1869 int res;
1870 char *uuid;
1871
1872 uuid = os_strchr(cmd, ' ');
1873 if (uuid == NULL)
1874 return -1;
1875 *uuid++ = '\0';
1876
1877 if (os_strcmp(cmd, "WPS") == 0)
1878 ndef = 0;
1879 else if (os_strcmp(cmd, "NDEF") == 0)
1880 ndef = 1;
1881 else
1882 return -1;
1883
1884 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1885 if (buf == NULL)
1886 return -1;
1887
1888 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1889 wpabuf_len(buf));
1890 reply[res++] = '\n';
1891 reply[res] = '\0';
1892
1893 wpabuf_free(buf);
1894
1895 return res;
1896}
1897#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001898#endif /* CONFIG_WPS_ER */
1899
1900#endif /* CONFIG_WPS */
1901
1902
1903#ifdef CONFIG_IBSS_RSN
1904static int wpa_supplicant_ctrl_iface_ibss_rsn(
1905 struct wpa_supplicant *wpa_s, char *addr)
1906{
1907 u8 peer[ETH_ALEN];
1908
1909 if (hwaddr_aton(addr, peer)) {
1910 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1911 "address '%s'", addr);
1912 return -1;
1913 }
1914
1915 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1916 MAC2STR(peer));
1917
1918 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1919}
1920#endif /* CONFIG_IBSS_RSN */
1921
1922
1923static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1924 char *rsp)
1925{
1926#ifdef IEEE8021X_EAPOL
1927 char *pos, *id_pos;
1928 int id;
1929 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001930
1931 pos = os_strchr(rsp, '-');
1932 if (pos == NULL)
1933 return -1;
1934 *pos++ = '\0';
1935 id_pos = pos;
1936 pos = os_strchr(pos, ':');
1937 if (pos == NULL)
1938 return -1;
1939 *pos++ = '\0';
1940 id = atoi(id_pos);
1941 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1942 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1943 (u8 *) pos, os_strlen(pos));
1944
1945 ssid = wpa_config_get_network(wpa_s->conf, id);
1946 if (ssid == NULL) {
1947 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1948 "to update", id);
1949 return -1;
1950 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001951
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001952 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1953 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001954#else /* IEEE8021X_EAPOL */
1955 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1956 return -1;
1957#endif /* IEEE8021X_EAPOL */
1958}
1959
1960
1961static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1962 const char *params,
1963 char *buf, size_t buflen)
1964{
1965 char *pos, *end, tmp[30];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001966 int res, verbose, wps, ret;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001967#ifdef CONFIG_HS20
1968 const u8 *hs20;
1969#endif /* CONFIG_HS20 */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001970 const u8 *sess_id;
1971 size_t sess_id_len;
Dmitry Shmidt44da0252011-08-23 12:30:30 -07001972
Dmitry Shmidt56052862013-10-04 10:23:25 -07001973 if (os_strcmp(params, "-DRIVER") == 0)
1974 return wpa_drv_status(wpa_s, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001975 verbose = os_strcmp(params, "-VERBOSE") == 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001976 wps = os_strcmp(params, "-WPS") == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001977 pos = buf;
1978 end = buf + buflen;
1979 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1980 struct wpa_ssid *ssid = wpa_s->current_ssid;
1981 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1982 MAC2STR(wpa_s->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001983 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001984 return pos - buf;
1985 pos += ret;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001986 ret = os_snprintf(pos, end - pos, "freq=%u\n",
1987 wpa_s->assoc_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001988 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001989 return pos - buf;
1990 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001991 if (ssid) {
1992 u8 *_ssid = ssid->ssid;
1993 size_t ssid_len = ssid->ssid_len;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001994 u8 ssid_buf[SSID_MAX_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995 if (ssid_len == 0) {
1996 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1997 if (_res < 0)
1998 ssid_len = 0;
1999 else
2000 ssid_len = _res;
2001 _ssid = ssid_buf;
2002 }
2003 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
2004 wpa_ssid_txt(_ssid, ssid_len),
2005 ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002006 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002007 return pos - buf;
2008 pos += ret;
2009
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002010 if (wps && ssid->passphrase &&
2011 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
2012 (ssid->mode == WPAS_MODE_AP ||
2013 ssid->mode == WPAS_MODE_P2P_GO)) {
2014 ret = os_snprintf(pos, end - pos,
2015 "passphrase=%s\n",
2016 ssid->passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002017 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002018 return pos - buf;
2019 pos += ret;
2020 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002021 if (ssid->id_str) {
2022 ret = os_snprintf(pos, end - pos,
2023 "id_str=%s\n",
2024 ssid->id_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002025 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002026 return pos - buf;
2027 pos += ret;
2028 }
2029
2030 switch (ssid->mode) {
2031 case WPAS_MODE_INFRA:
2032 ret = os_snprintf(pos, end - pos,
2033 "mode=station\n");
2034 break;
2035 case WPAS_MODE_IBSS:
2036 ret = os_snprintf(pos, end - pos,
2037 "mode=IBSS\n");
2038 break;
2039 case WPAS_MODE_AP:
2040 ret = os_snprintf(pos, end - pos,
2041 "mode=AP\n");
2042 break;
2043 case WPAS_MODE_P2P_GO:
2044 ret = os_snprintf(pos, end - pos,
2045 "mode=P2P GO\n");
2046 break;
2047 case WPAS_MODE_P2P_GROUP_FORMATION:
2048 ret = os_snprintf(pos, end - pos,
2049 "mode=P2P GO - group "
2050 "formation\n");
2051 break;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07002052 case WPAS_MODE_MESH:
2053 ret = os_snprintf(pos, end - pos,
2054 "mode=mesh\n");
2055 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002056 default:
2057 ret = 0;
2058 break;
2059 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002060 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002061 return pos - buf;
2062 pos += ret;
2063 }
2064
2065#ifdef CONFIG_AP
2066 if (wpa_s->ap_iface) {
2067 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
2068 end - pos,
2069 verbose);
2070 } else
2071#endif /* CONFIG_AP */
2072 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
2073 }
Paul Stewart092955c2017-02-06 09:13:09 -08002074#ifdef CONFIG_SME
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002075#ifdef CONFIG_SAE
2076 if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07002077#ifdef CONFIG_AP
2078 !wpa_s->ap_iface &&
2079#endif /* CONFIG_AP */
2080 wpa_s->sme.sae.state == SAE_ACCEPTED) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002081 ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
2082 wpa_s->sme.sae.group);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002083 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002084 return pos - buf;
2085 pos += ret;
2086 }
2087#endif /* CONFIG_SAE */
Paul Stewart092955c2017-02-06 09:13:09 -08002088#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002089 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
2090 wpa_supplicant_state_txt(wpa_s->wpa_state));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002091 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002092 return pos - buf;
2093 pos += ret;
2094
2095 if (wpa_s->l2 &&
2096 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
2097 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002098 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002099 return pos - buf;
2100 pos += ret;
2101 }
2102
2103#ifdef CONFIG_P2P
2104 if (wpa_s->global->p2p) {
2105 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
2106 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002107 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002108 return pos - buf;
2109 pos += ret;
2110 }
2111#endif /* CONFIG_P2P */
2112
2113 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
2114 MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002115 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002116 return pos - buf;
2117 pos += ret;
2118
Dmitry Shmidt04949592012-07-19 12:16:46 -07002119#ifdef CONFIG_HS20
2120 if (wpa_s->current_bss &&
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002121 (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
2122 HS20_IE_VENDOR_TYPE)) &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002123 wpa_s->wpa_proto == WPA_PROTO_RSN &&
2124 wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002125 int release = 1;
2126 if (hs20[1] >= 5) {
2127 u8 rel_num = (hs20[6] & 0xf0) >> 4;
2128 release = rel_num + 1;
2129 }
2130 ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002131 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07002132 return pos - buf;
2133 pos += ret;
2134 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002135
2136 if (wpa_s->current_ssid) {
2137 struct wpa_cred *cred;
2138 char *type;
2139
2140 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07002141 size_t i;
2142
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002143 if (wpa_s->current_ssid->parent_cred != cred)
2144 continue;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002145
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002146 if (cred->provisioning_sp) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07002147 ret = os_snprintf(pos, end - pos,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002148 "provisioning_sp=%s\n",
2149 cred->provisioning_sp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002150 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt051af732013-10-22 13:52:46 -07002151 return pos - buf;
2152 pos += ret;
2153 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002154
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002155 if (!cred->domain)
2156 goto no_domain;
2157
2158 i = 0;
2159 if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
2160 struct wpabuf *names =
2161 wpa_s->current_bss->anqp->domain_name;
2162 for (i = 0; names && i < cred->num_domain; i++)
2163 {
2164 if (domain_name_list_contains(
2165 names, cred->domain[i], 1))
2166 break;
2167 }
2168 if (i == cred->num_domain)
2169 i = 0; /* show first entry by default */
2170 }
2171 ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
2172 cred->domain[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002173 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002174 return pos - buf;
2175 pos += ret;
2176
2177 no_domain:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002178 if (wpa_s->current_bss == NULL ||
2179 wpa_s->current_bss->anqp == NULL)
2180 res = -1;
2181 else
2182 res = interworking_home_sp_cred(
2183 wpa_s, cred,
2184 wpa_s->current_bss->anqp->domain_name);
2185 if (res > 0)
2186 type = "home";
2187 else if (res == 0)
2188 type = "roaming";
2189 else
2190 type = "unknown";
2191
2192 ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002193 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002194 return pos - buf;
2195 pos += ret;
2196
2197 break;
2198 }
2199 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002200#endif /* CONFIG_HS20 */
2201
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002202 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
2203 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
2204 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
2205 verbose);
2206 if (res >= 0)
2207 pos += res;
2208 }
2209
Dmitry Shmidt29333592017-01-09 12:27:11 -08002210#ifdef CONFIG_MACSEC
2211 res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos);
2212 if (res > 0)
2213 pos += res;
2214#endif /* CONFIG_MACSEC */
2215
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002216 sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
2217 if (sess_id) {
2218 char *start = pos;
2219
2220 ret = os_snprintf(pos, end - pos, "eap_session_id=");
2221 if (os_snprintf_error(end - pos, ret))
2222 return start - buf;
2223 pos += ret;
2224 ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
2225 if (ret <= 0)
2226 return start - buf;
2227 pos += ret;
2228 ret = os_snprintf(pos, end - pos, "\n");
2229 if (os_snprintf_error(end - pos, ret))
2230 return start - buf;
2231 pos += ret;
2232 }
2233
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002234 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
2235 if (res >= 0)
2236 pos += res;
2237
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002238#ifdef CONFIG_WPS
2239 {
2240 char uuid_str[100];
2241 uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
2242 ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002243 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002244 return pos - buf;
2245 pos += ret;
2246 }
2247#endif /* CONFIG_WPS */
2248
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08002249#ifdef ANDROID
vandwalleffc70182014-09-11 11:40:14 -07002250 /*
2251 * Allow using the STATUS command with default behavior, say for debug,
2252 * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
2253 * events with STATUS-NO_EVENTS.
2254 */
2255 if (os_strcmp(params, "-NO_EVENTS")) {
2256 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
2257 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
2258 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
2259 wpa_s->wpa_state,
2260 MAC2STR(wpa_s->bssid),
2261 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
2262 wpa_ssid_txt(wpa_s->current_ssid->ssid,
2263 wpa_s->current_ssid->ssid_len) : "");
2264 if (wpa_s->wpa_state == WPA_COMPLETED) {
2265 struct wpa_ssid *ssid = wpa_s->current_ssid;
2266 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
2267 "- connection to " MACSTR
2268 " completed %s [id=%d id_str=%s]",
2269 MAC2STR(wpa_s->bssid), "(auth)",
2270 ssid ? ssid->id : -1,
2271 ssid && ssid->id_str ? ssid->id_str : "");
2272 }
Irfan Sheriffbf5edf42012-01-11 16:54:57 -08002273 }
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08002274#endif /* ANDROID */
2275
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002276 return pos - buf;
2277}
2278
2279
2280static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
2281 char *cmd)
2282{
2283 char *pos;
2284 int id;
2285 struct wpa_ssid *ssid;
2286 u8 bssid[ETH_ALEN];
2287
2288 /* cmd: "<network id> <BSSID>" */
2289 pos = os_strchr(cmd, ' ');
2290 if (pos == NULL)
2291 return -1;
2292 *pos++ = '\0';
2293 id = atoi(cmd);
2294 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
2295 if (hwaddr_aton(pos, bssid)) {
2296 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
2297 return -1;
2298 }
2299
2300 ssid = wpa_config_get_network(wpa_s->conf, id);
2301 if (ssid == NULL) {
2302 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2303 "to update", id);
2304 return -1;
2305 }
2306
2307 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
2308 ssid->bssid_set = !is_zero_ether_addr(bssid);
2309
2310 return 0;
2311}
2312
2313
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002314static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002315 char *cmd, char *buf,
2316 size_t buflen)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002317{
2318 u8 bssid[ETH_ALEN];
2319 struct wpa_blacklist *e;
2320 char *pos, *end;
2321 int ret;
2322
2323 /* cmd: "BLACKLIST [<BSSID>]" */
2324 if (*cmd == '\0') {
2325 pos = buf;
2326 end = buf + buflen;
2327 e = wpa_s->blacklist;
2328 while (e) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002329 ret = os_snprintf(pos, end - pos, MACSTR "\n",
2330 MAC2STR(e->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002331 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002332 return pos - buf;
2333 pos += ret;
2334 e = e->next;
2335 }
2336 return pos - buf;
2337 }
2338
2339 cmd++;
2340 if (os_strncmp(cmd, "clear", 5) == 0) {
2341 wpa_blacklist_clear(wpa_s);
2342 os_memcpy(buf, "OK\n", 3);
2343 return 3;
2344 }
2345
2346 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
2347 if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002348 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002349 return -1;
2350 }
2351
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002352 /*
2353 * Add the BSSID twice, so its count will be 2, causing it to be
2354 * skipped when processing scan results.
2355 */
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002356 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002357 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002358 return -1;
2359 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002360 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002361 return -1;
2362 os_memcpy(buf, "OK\n", 3);
2363 return 3;
2364}
2365
2366
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002367static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
2368 char *cmd, char *buf,
2369 size_t buflen)
2370{
2371 char *pos, *end, *stamp;
2372 int ret;
2373
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002374 /* cmd: "LOG_LEVEL [<level>]" */
2375 if (*cmd == '\0') {
2376 pos = buf;
2377 end = buf + buflen;
2378 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2379 "Timestamp: %d\n",
2380 debug_level_str(wpa_debug_level),
2381 wpa_debug_timestamp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002382 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002383 ret = 0;
2384
2385 return ret;
2386 }
2387
2388 while (*cmd == ' ')
2389 cmd++;
2390
2391 stamp = os_strchr(cmd, ' ');
2392 if (stamp) {
2393 *stamp++ = '\0';
2394 while (*stamp == ' ') {
2395 stamp++;
2396 }
2397 }
2398
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002399 if (os_strlen(cmd)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002400 int level = str_to_debug_level(cmd);
2401 if (level < 0)
2402 return -1;
2403 wpa_debug_level = level;
2404 }
2405
2406 if (stamp && os_strlen(stamp))
2407 wpa_debug_timestamp = atoi(stamp);
2408
2409 os_memcpy(buf, "OK\n", 3);
2410 return 3;
2411}
2412
2413
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002414static int wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002415 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002416{
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002417 char *pos, *end, *prev;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002418 struct wpa_ssid *ssid;
2419 int ret;
2420
2421 pos = buf;
2422 end = buf + buflen;
2423 ret = os_snprintf(pos, end - pos,
2424 "network id / ssid / bssid / flags\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002425 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426 return pos - buf;
2427 pos += ret;
2428
2429 ssid = wpa_s->conf->ssid;
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002430
2431 /* skip over ssids until we find next one */
2432 if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
2433 int last_id = atoi(cmd + 8);
2434 if (last_id != -1) {
2435 while (ssid != NULL && ssid->id <= last_id) {
2436 ssid = ssid->next;
2437 }
2438 }
2439 }
2440
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002441 while (ssid) {
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002442 prev = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002443 ret = os_snprintf(pos, end - pos, "%d\t%s",
2444 ssid->id,
2445 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002446 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002447 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002448 pos += ret;
2449 if (ssid->bssid_set) {
2450 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
2451 MAC2STR(ssid->bssid));
2452 } else {
2453 ret = os_snprintf(pos, end - pos, "\tany");
2454 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002455 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002456 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002457 pos += ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002458 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002459 ssid == wpa_s->current_ssid ?
2460 "[CURRENT]" : "",
2461 ssid->disabled ? "[DISABLED]" : "",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002462 ssid->disabled_until.sec ?
2463 "[TEMP-DISABLED]" : "",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002464 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
2465 "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002466 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002467 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002468 pos += ret;
2469 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002470 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002471 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472 pos += ret;
2473
2474 ssid = ssid->next;
2475 }
2476
2477 return pos - buf;
2478}
2479
2480
2481static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
2482{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002483 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002484 ret = os_snprintf(pos, end - pos, "-");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002485 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002486 return pos;
2487 pos += ret;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002488 ret = wpa_write_ciphers(pos, end, cipher, "+");
2489 if (ret < 0)
2490 return pos;
2491 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002492 return pos;
2493}
2494
2495
2496static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
2497 const u8 *ie, size_t ie_len)
2498{
2499 struct wpa_ie_data data;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002500 char *start;
2501 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002502
2503 ret = os_snprintf(pos, end - pos, "[%s-", proto);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002504 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002505 return pos;
2506 pos += ret;
2507
2508 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
2509 ret = os_snprintf(pos, end - pos, "?]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002510 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002511 return pos;
2512 pos += ret;
2513 return pos;
2514 }
2515
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002516 start = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002517 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002518 ret = os_snprintf(pos, end - pos, "%sEAP",
2519 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002520 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002521 return pos;
2522 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002523 }
2524 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002525 ret = os_snprintf(pos, end - pos, "%sPSK",
2526 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002527 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002528 return pos;
2529 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002530 }
2531 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002532 ret = os_snprintf(pos, end - pos, "%sNone",
2533 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002534 if (os_snprintf_error(end - pos, ret))
2535 return pos;
2536 pos += ret;
2537 }
2538 if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
2539 ret = os_snprintf(pos, end - pos, "%sSAE",
2540 pos == start ? "" : "+");
2541 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002542 return pos;
2543 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002544 }
2545#ifdef CONFIG_IEEE80211R
2546 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
2547 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002548 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002549 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002550 return pos;
2551 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002552 }
2553 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
2554 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002555 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002556 if (os_snprintf_error(end - pos, ret))
2557 return pos;
2558 pos += ret;
2559 }
2560 if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
2561 ret = os_snprintf(pos, end - pos, "%sFT/SAE",
2562 pos == start ? "" : "+");
2563 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002564 return pos;
2565 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002566 }
2567#endif /* CONFIG_IEEE80211R */
2568#ifdef CONFIG_IEEE80211W
2569 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2570 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002571 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002572 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002573 return pos;
2574 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002575 }
2576 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
2577 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002578 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002579 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002580 return pos;
2581 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002582 }
2583#endif /* CONFIG_IEEE80211W */
2584
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002585#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002586 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2587 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
2588 pos == start ? "" : "+");
2589 if (os_snprintf_error(end - pos, ret))
2590 return pos;
2591 pos += ret;
2592 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002593#endif /* CONFIG_SUITEB */
2594
2595#ifdef CONFIG_SUITEB192
2596 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2597 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
2598 pos == start ? "" : "+");
2599 if (os_snprintf_error(end - pos, ret))
2600 return pos;
2601 pos += ret;
2602 }
2603#endif /* CONFIG_SUITEB192 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002604
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002605#ifdef CONFIG_FILS
2606 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
2607 ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
2608 pos == start ? "" : "+");
2609 if (os_snprintf_error(end - pos, ret))
2610 return pos;
2611 pos += ret;
2612 }
2613 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
2614 ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
2615 pos == start ? "" : "+");
2616 if (os_snprintf_error(end - pos, ret))
2617 return pos;
2618 pos += ret;
2619 }
2620#ifdef CONFIG_IEEE80211R
2621 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
2622 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
2623 pos == start ? "" : "+");
2624 if (os_snprintf_error(end - pos, ret))
2625 return pos;
2626 pos += ret;
2627 }
2628 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
2629 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
2630 pos == start ? "" : "+");
2631 if (os_snprintf_error(end - pos, ret))
2632 return pos;
2633 pos += ret;
2634 }
2635#endif /* CONFIG_IEEE80211R */
2636#endif /* CONFIG_FILS */
2637
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002638#ifdef CONFIG_OWE
2639 if (data.key_mgmt & WPA_KEY_MGMT_OWE) {
2640 ret = os_snprintf(pos, end - pos, "%sOWE",
2641 pos == start ? "" : "+");
2642 if (os_snprintf_error(end - pos, ret))
2643 return pos;
2644 pos += ret;
2645 }
2646#endif /* CONFIG_OWE */
2647
2648#ifdef CONFIG_DPP
2649 if (data.key_mgmt & WPA_KEY_MGMT_DPP) {
2650 ret = os_snprintf(pos, end - pos, "%sDPP",
2651 pos == start ? "" : "+");
2652 if (os_snprintf_error(end - pos, ret))
2653 return pos;
2654 pos += ret;
2655 }
2656#endif /* CONFIG_DPP */
2657
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002658 if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
2659 ret = os_snprintf(pos, end - pos, "%sOSEN",
2660 pos == start ? "" : "+");
2661 if (os_snprintf_error(end - pos, ret))
2662 return pos;
2663 pos += ret;
2664 }
2665
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002666 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
2667
2668 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
2669 ret = os_snprintf(pos, end - pos, "-preauth");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002670 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002671 return pos;
2672 pos += ret;
2673 }
2674
2675 ret = os_snprintf(pos, end - pos, "]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002676 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002677 return pos;
2678 pos += ret;
2679
2680 return pos;
2681}
2682
2683
2684#ifdef CONFIG_WPS
2685static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
2686 char *pos, char *end,
2687 struct wpabuf *wps_ie)
2688{
2689 int ret;
2690 const char *txt;
2691
2692 if (wps_ie == NULL)
2693 return pos;
2694 if (wps_is_selected_pbc_registrar(wps_ie))
2695 txt = "[WPS-PBC]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002696 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
2697 txt = "[WPS-AUTH]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002698 else if (wps_is_selected_pin_registrar(wps_ie))
2699 txt = "[WPS-PIN]";
2700 else
2701 txt = "[WPS]";
2702
2703 ret = os_snprintf(pos, end - pos, "%s", txt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002704 if (!os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002705 pos += ret;
2706 wpabuf_free(wps_ie);
2707 return pos;
2708}
2709#endif /* CONFIG_WPS */
2710
2711
2712static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
2713 char *pos, char *end,
2714 const struct wpa_bss *bss)
2715{
2716#ifdef CONFIG_WPS
2717 struct wpabuf *wps_ie;
2718 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
2719 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
2720#else /* CONFIG_WPS */
2721 return pos;
2722#endif /* CONFIG_WPS */
2723}
2724
2725
2726/* Format one result on one text line into a buffer. */
2727static int wpa_supplicant_ctrl_iface_scan_result(
2728 struct wpa_supplicant *wpa_s,
2729 const struct wpa_bss *bss, char *buf, size_t buflen)
2730{
2731 char *pos, *end;
2732 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002733 const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002734
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002735 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002736 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt96571392013-10-14 12:54:46 -07002737 if (!p2p)
2738 p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
2740 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
2741 0)
2742 return 0; /* Do not show P2P listen discovery results here */
2743
2744 pos = buf;
2745 end = buf + buflen;
2746
2747 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
2748 MAC2STR(bss->bssid), bss->freq, bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002749 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002750 return -1;
2751 pos += ret;
2752 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2753 if (ie)
2754 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
2755 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002756 if (ie2) {
2757 pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
2758 ie2, 2 + ie2[1]);
2759 }
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002760 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
2761 if (osen_ie)
2762 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
2763 osen_ie, 2 + osen_ie[1]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002764 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
2765 if (owe) {
2766 ret = os_snprintf(pos, end - pos,
2767 ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
2768 if (os_snprintf_error(end - pos, ret))
2769 return -1;
2770 pos += ret;
2771 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002772 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002773 if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002774 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002775 if (os_snprintf_error(end - pos, ret))
2776 return -1;
2777 pos += ret;
2778 }
2779 if (mesh) {
2780 ret = os_snprintf(pos, end - pos, "[MESH]");
2781 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002782 return -1;
2783 pos += ret;
2784 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002785 if (bss_is_dmg(bss)) {
2786 const char *s;
2787 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002788 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002789 return -1;
2790 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002791 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
2792 case IEEE80211_CAP_DMG_IBSS:
2793 s = "[IBSS]";
2794 break;
2795 case IEEE80211_CAP_DMG_AP:
2796 s = "[ESS]";
2797 break;
2798 case IEEE80211_CAP_DMG_PBSS:
2799 s = "[PBSS]";
2800 break;
2801 default:
2802 s = "";
2803 break;
2804 }
2805 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002806 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002807 return -1;
2808 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002809 } else {
2810 if (bss->caps & IEEE80211_CAP_IBSS) {
2811 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002812 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002813 return -1;
2814 pos += ret;
2815 }
2816 if (bss->caps & IEEE80211_CAP_ESS) {
2817 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002818 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002819 return -1;
2820 pos += ret;
2821 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002822 }
2823 if (p2p) {
2824 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002825 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002826 return -1;
2827 pos += ret;
2828 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002829#ifdef CONFIG_HS20
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002830 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002831 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002832 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07002833 return -1;
2834 pos += ret;
2835 }
2836#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002837#ifdef CONFIG_FILS
2838 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
2839 ret = os_snprintf(pos, end - pos, "[FILS]");
2840 if (os_snprintf_error(end - pos, ret))
2841 return -1;
2842 pos += ret;
2843 }
2844#endif /* CONFIG_FILS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002845#ifdef CONFIG_FST
2846 if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
2847 ret = os_snprintf(pos, end - pos, "[FST]");
2848 if (os_snprintf_error(end - pos, ret))
2849 return -1;
2850 pos += ret;
2851 }
2852#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002853
2854 ret = os_snprintf(pos, end - pos, "\t%s",
2855 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002856 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002857 return -1;
2858 pos += ret;
2859
2860 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002861 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002862 return -1;
2863 pos += ret;
2864
2865 return pos - buf;
2866}
2867
2868
2869static int wpa_supplicant_ctrl_iface_scan_results(
2870 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2871{
2872 char *pos, *end;
2873 struct wpa_bss *bss;
2874 int ret;
2875
2876 pos = buf;
2877 end = buf + buflen;
2878 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
2879 "flags / ssid\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002880 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002881 return pos - buf;
2882 pos += ret;
2883
2884 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2885 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
2886 end - pos);
2887 if (ret < 0 || ret >= end - pos)
2888 return pos - buf;
2889 pos += ret;
2890 }
2891
2892 return pos - buf;
2893}
2894
2895
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002896#ifdef CONFIG_MESH
2897
2898static int wpa_supplicant_ctrl_iface_mesh_interface_add(
2899 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
2900{
2901 char *pos, ifname[IFNAMSIZ + 1];
2902
2903 ifname[0] = '\0';
2904
2905 pos = os_strstr(cmd, "ifname=");
2906 if (pos) {
2907 pos += 7;
2908 os_strlcpy(ifname, pos, sizeof(ifname));
2909 }
2910
2911 if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
2912 return -1;
2913
2914 os_strlcpy(reply, ifname, max_len);
2915 return os_strlen(ifname);
2916}
2917
2918
2919static int wpa_supplicant_ctrl_iface_mesh_group_add(
2920 struct wpa_supplicant *wpa_s, char *cmd)
2921{
2922 int id;
2923 struct wpa_ssid *ssid;
2924
2925 id = atoi(cmd);
2926 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
2927
2928 ssid = wpa_config_get_network(wpa_s->conf, id);
2929 if (ssid == NULL) {
2930 wpa_printf(MSG_DEBUG,
2931 "CTRL_IFACE: Could not find network id=%d", id);
2932 return -1;
2933 }
2934 if (ssid->mode != WPAS_MODE_MESH) {
2935 wpa_printf(MSG_DEBUG,
2936 "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
2937 return -1;
2938 }
2939 if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
2940 ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
2941 wpa_printf(MSG_ERROR,
2942 "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
2943 return -1;
2944 }
2945
2946 /*
2947 * TODO: If necessary write our own group_add function,
2948 * for now we can reuse select_network
2949 */
2950 wpa_supplicant_select_network(wpa_s, ssid);
2951
2952 return 0;
2953}
2954
2955
2956static int wpa_supplicant_ctrl_iface_mesh_group_remove(
2957 struct wpa_supplicant *wpa_s, char *cmd)
2958{
2959 struct wpa_supplicant *orig;
2960 struct wpa_global *global;
2961 int found = 0;
2962
2963 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
2964
2965 global = wpa_s->global;
2966 orig = wpa_s;
2967
2968 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2969 if (os_strcmp(wpa_s->ifname, cmd) == 0) {
2970 found = 1;
2971 break;
2972 }
2973 }
2974 if (!found) {
2975 wpa_printf(MSG_ERROR,
2976 "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
2977 cmd);
2978 return -1;
2979 }
2980 if (wpa_s->mesh_if_created && wpa_s == orig) {
2981 wpa_printf(MSG_ERROR,
2982 "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
2983 return -1;
2984 }
2985
2986 wpa_s->reassociate = 0;
2987 wpa_s->disconnected = 1;
2988 wpa_supplicant_cancel_sched_scan(wpa_s);
2989 wpa_supplicant_cancel_scan(wpa_s);
2990
2991 /*
2992 * TODO: If necessary write our own group_remove function,
2993 * for now we can reuse deauthenticate
2994 */
2995 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2996
2997 if (wpa_s->mesh_if_created)
2998 wpa_supplicant_remove_iface(global, wpa_s, 0);
2999
3000 return 0;
3001}
3002
Dmitry Shmidte4663042016-04-04 10:07:49 -07003003
3004static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
3005 struct wpa_supplicant *wpa_s, char *cmd)
3006{
3007 u8 addr[ETH_ALEN];
3008
3009 if (hwaddr_aton(cmd, addr) < 0)
3010 return -1;
3011
3012 return wpas_mesh_peer_remove(wpa_s, addr);
3013}
3014
3015
3016static int wpa_supplicant_ctrl_iface_mesh_peer_add(
3017 struct wpa_supplicant *wpa_s, char *cmd)
3018{
3019 u8 addr[ETH_ALEN];
3020 int duration;
3021 char *pos;
3022
3023 pos = os_strstr(cmd, " duration=");
3024 if (pos) {
3025 *pos = '\0';
3026 duration = atoi(pos + 10);
3027 } else {
3028 duration = -1;
3029 }
3030
3031 if (hwaddr_aton(cmd, addr))
3032 return -1;
3033
3034 return wpas_mesh_peer_add(wpa_s, addr, duration);
3035}
3036
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003037#endif /* CONFIG_MESH */
3038
3039
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003040static int wpa_supplicant_ctrl_iface_select_network(
3041 struct wpa_supplicant *wpa_s, char *cmd)
3042{
3043 int id;
3044 struct wpa_ssid *ssid;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003045 char *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003046
3047 /* cmd: "<network id>" or "any" */
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003048 if (os_strncmp(cmd, "any", 3) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003049 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
3050 ssid = NULL;
3051 } else {
3052 id = atoi(cmd);
3053 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
3054
3055 ssid = wpa_config_get_network(wpa_s->conf, id);
3056 if (ssid == NULL) {
3057 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3058 "network id=%d", id);
3059 return -1;
3060 }
3061 if (ssid->disabled == 2) {
3062 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
3063 "SELECT_NETWORK with persistent P2P group");
3064 return -1;
3065 }
3066 }
3067
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003068 pos = os_strstr(cmd, " freq=");
3069 if (pos) {
3070 int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
3071 if (freqs) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003072 os_free(wpa_s->select_network_scan_freqs);
3073 wpa_s->select_network_scan_freqs = freqs;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003074 }
3075 }
3076
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003077 wpa_s->scan_min_time.sec = 0;
3078 wpa_s->scan_min_time.usec = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003079 wpa_supplicant_select_network(wpa_s, ssid);
3080
3081 return 0;
3082}
3083
3084
3085static int wpa_supplicant_ctrl_iface_enable_network(
3086 struct wpa_supplicant *wpa_s, char *cmd)
3087{
3088 int id;
3089 struct wpa_ssid *ssid;
3090
3091 /* cmd: "<network id>" or "all" */
3092 if (os_strcmp(cmd, "all") == 0) {
3093 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
3094 ssid = NULL;
3095 } else {
3096 id = atoi(cmd);
3097 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
3098
3099 ssid = wpa_config_get_network(wpa_s->conf, id);
3100 if (ssid == NULL) {
3101 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3102 "network id=%d", id);
3103 return -1;
3104 }
3105 if (ssid->disabled == 2) {
3106 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
3107 "ENABLE_NETWORK with persistent P2P group");
3108 return -1;
3109 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003110
3111 if (os_strstr(cmd, " no-connect")) {
3112 ssid->disabled = 0;
3113 return 0;
3114 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003115 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003116 wpa_s->scan_min_time.sec = 0;
3117 wpa_s->scan_min_time.usec = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003118 wpa_supplicant_enable_network(wpa_s, ssid);
3119
3120 return 0;
3121}
3122
3123
3124static int wpa_supplicant_ctrl_iface_disable_network(
3125 struct wpa_supplicant *wpa_s, char *cmd)
3126{
3127 int id;
3128 struct wpa_ssid *ssid;
3129
3130 /* cmd: "<network id>" or "all" */
3131 if (os_strcmp(cmd, "all") == 0) {
3132 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
3133 ssid = NULL;
3134 } else {
3135 id = atoi(cmd);
3136 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
3137
3138 ssid = wpa_config_get_network(wpa_s->conf, id);
3139 if (ssid == NULL) {
3140 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3141 "network id=%d", id);
3142 return -1;
3143 }
3144 if (ssid->disabled == 2) {
3145 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
3146 "DISABLE_NETWORK with persistent P2P "
3147 "group");
3148 return -1;
3149 }
3150 }
3151 wpa_supplicant_disable_network(wpa_s, ssid);
3152
3153 return 0;
3154}
3155
3156
3157static int wpa_supplicant_ctrl_iface_add_network(
3158 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
3159{
3160 struct wpa_ssid *ssid;
3161 int ret;
3162
3163 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
3164
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003165 ssid = wpa_supplicant_add_network(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003166 if (ssid == NULL)
3167 return -1;
3168
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003169 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003170 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003171 return -1;
3172 return ret;
3173}
3174
3175
3176static int wpa_supplicant_ctrl_iface_remove_network(
3177 struct wpa_supplicant *wpa_s, char *cmd)
3178{
3179 int id;
3180 struct wpa_ssid *ssid;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003181 int result;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003182
3183 /* cmd: "<network id>" or "all" */
3184 if (os_strcmp(cmd, "all") == 0) {
3185 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
Dmitry Shmidt2f023192013-03-12 12:44:17 -07003186 if (wpa_s->sched_scanning)
3187 wpa_supplicant_cancel_sched_scan(wpa_s);
3188
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003189 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003190 if (wpa_s->current_ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07003191#ifdef CONFIG_SME
3192 wpa_s->sme.prev_bssid_set = 0;
3193#endif /* CONFIG_SME */
Jouni Malinen75ecf522011-06-27 15:19:46 -07003194 wpa_sm_set_config(wpa_s->wpa, NULL);
3195 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07003196 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3197 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003198 wpa_supplicant_deauthenticate(
3199 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003200 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003201 ssid = wpa_s->conf->ssid;
3202 while (ssid) {
3203 struct wpa_ssid *remove_ssid = ssid;
3204 id = ssid->id;
3205 ssid = ssid->next;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003206 if (wpa_s->last_ssid == remove_ssid)
3207 wpa_s->last_ssid = NULL;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003208 wpas_notify_network_removed(wpa_s, remove_ssid);
3209 wpa_config_remove_network(wpa_s->conf, id);
3210 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003211 return 0;
3212 }
3213
3214 id = atoi(cmd);
3215 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
3216
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003217 result = wpa_supplicant_remove_network(wpa_s, id);
3218 if (result == -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003219 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3220 "id=%d", id);
3221 return -1;
3222 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003223 if (result == -2) {
Deepthi Gowria831d782012-09-03 11:55:38 +03003224 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
3225 "network id=%d", id);
3226 return -1;
3227 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003228 return 0;
3229}
3230
3231
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003232static int wpa_supplicant_ctrl_iface_update_network(
3233 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
3234 char *name, char *value)
3235{
Dmitry Shmidte4663042016-04-04 10:07:49 -07003236 int ret;
3237
3238 ret = wpa_config_set(ssid, name, value, 0);
3239 if (ret < 0) {
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003240 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
3241 "variable '%s'", name);
3242 return -1;
3243 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07003244 if (ret == 1)
3245 return 0; /* No change to the previously configured value */
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003246
3247 if (os_strcmp(name, "bssid") != 0 &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003248 os_strcmp(name, "bssid_hint") != 0 &&
Dmitry Shmidte4663042016-04-04 10:07:49 -07003249 os_strcmp(name, "priority") != 0) {
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003250 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
3251
Dmitry Shmidte4663042016-04-04 10:07:49 -07003252 if (wpa_s->current_ssid == ssid ||
3253 wpa_s->current_ssid == NULL) {
3254 /*
3255 * Invalidate the EAP session cache if anything in the
3256 * current or previously used configuration changes.
3257 */
3258 eapol_sm_invalidate_cached_session(wpa_s->eapol);
3259 }
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003260 }
3261
3262 if ((os_strcmp(name, "psk") == 0 &&
3263 value[0] == '"' && ssid->ssid_len) ||
3264 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
3265 wpa_config_update_psk(ssid);
3266 else if (os_strcmp(name, "priority") == 0)
3267 wpa_config_update_prio_list(wpa_s->conf);
3268
3269 return 0;
3270}
3271
3272
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003273static int wpa_supplicant_ctrl_iface_set_network(
3274 struct wpa_supplicant *wpa_s, char *cmd)
3275{
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003276 int id, ret, prev_bssid_set, prev_disabled;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003277 struct wpa_ssid *ssid;
3278 char *name, *value;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003279 u8 prev_bssid[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003280
3281 /* cmd: "<network id> <variable name> <value>" */
3282 name = os_strchr(cmd, ' ');
3283 if (name == NULL)
3284 return -1;
3285 *name++ = '\0';
3286
3287 value = os_strchr(name, ' ');
3288 if (value == NULL)
3289 return -1;
3290 *value++ = '\0';
3291
3292 id = atoi(cmd);
3293 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
3294 id, name);
3295 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3296 (u8 *) value, os_strlen(value));
3297
3298 ssid = wpa_config_get_network(wpa_s->conf, id);
3299 if (ssid == NULL) {
3300 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3301 "id=%d", id);
3302 return -1;
3303 }
3304
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003305 prev_bssid_set = ssid->bssid_set;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003306 prev_disabled = ssid->disabled;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003307 os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
3308 ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
3309 value);
3310 if (ret == 0 &&
3311 (ssid->bssid_set != prev_bssid_set ||
3312 os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
3313 wpas_notify_network_bssid_set_changed(wpa_s, ssid);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003314
3315 if (prev_disabled != ssid->disabled &&
3316 (prev_disabled == 2 || ssid->disabled == 2))
3317 wpas_notify_network_type_changed(wpa_s, ssid);
3318
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003319 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003320}
3321
3322
3323static int wpa_supplicant_ctrl_iface_get_network(
3324 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
3325{
3326 int id;
3327 size_t res;
3328 struct wpa_ssid *ssid;
3329 char *name, *value;
3330
3331 /* cmd: "<network id> <variable name>" */
3332 name = os_strchr(cmd, ' ');
3333 if (name == NULL || buflen == 0)
3334 return -1;
3335 *name++ = '\0';
3336
3337 id = atoi(cmd);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003338 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003339 id, name);
3340
3341 ssid = wpa_config_get_network(wpa_s->conf, id);
3342 if (ssid == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003343 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003344 "id=%d", id);
3345 return -1;
3346 }
3347
3348 value = wpa_config_get_no_key(ssid, name);
3349 if (value == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003350 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003351 "variable '%s'", name);
3352 return -1;
3353 }
3354
3355 res = os_strlcpy(buf, value, buflen);
3356 if (res >= buflen) {
3357 os_free(value);
3358 return -1;
3359 }
3360
3361 os_free(value);
3362
3363 return res;
3364}
3365
3366
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003367static int wpa_supplicant_ctrl_iface_dup_network(
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003368 struct wpa_supplicant *wpa_s, char *cmd,
3369 struct wpa_supplicant *dst_wpa_s)
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003370{
3371 struct wpa_ssid *ssid_s, *ssid_d;
3372 char *name, *id, *value;
3373 int id_s, id_d, ret;
3374
3375 /* cmd: "<src network id> <dst network id> <variable name>" */
3376 id = os_strchr(cmd, ' ');
3377 if (id == NULL)
3378 return -1;
3379 *id++ = '\0';
3380
3381 name = os_strchr(id, ' ');
3382 if (name == NULL)
3383 return -1;
3384 *name++ = '\0';
3385
3386 id_s = atoi(cmd);
3387 id_d = atoi(id);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003388
3389 wpa_printf(MSG_DEBUG,
3390 "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'",
3391 wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003392
3393 ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
3394 if (ssid_s == NULL) {
3395 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3396 "network id=%d", id_s);
3397 return -1;
3398 }
3399
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003400 ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003401 if (ssid_d == NULL) {
3402 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003403 "network id=%d", id_d);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003404 return -1;
3405 }
3406
3407 value = wpa_config_get(ssid_s, name);
3408 if (value == NULL) {
3409 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
3410 "variable '%s'", name);
3411 return -1;
3412 }
3413
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003414 ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003415 value);
3416
3417 os_free(value);
3418
3419 return ret;
3420}
3421
3422
Dmitry Shmidt04949592012-07-19 12:16:46 -07003423static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
3424 char *buf, size_t buflen)
3425{
3426 char *pos, *end;
3427 struct wpa_cred *cred;
3428 int ret;
3429
3430 pos = buf;
3431 end = buf + buflen;
3432 ret = os_snprintf(pos, end - pos,
3433 "cred id / realm / username / domain / imsi\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003434 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003435 return pos - buf;
3436 pos += ret;
3437
3438 cred = wpa_s->conf->cred;
3439 while (cred) {
3440 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
3441 cred->id, cred->realm ? cred->realm : "",
3442 cred->username ? cred->username : "",
Dmitry Shmidt051af732013-10-22 13:52:46 -07003443 cred->domain ? cred->domain[0] : "",
Dmitry Shmidt04949592012-07-19 12:16:46 -07003444 cred->imsi ? cred->imsi : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003445 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003446 return pos - buf;
3447 pos += ret;
3448
3449 cred = cred->next;
3450 }
3451
3452 return pos - buf;
3453}
3454
3455
3456static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
3457 char *buf, size_t buflen)
3458{
3459 struct wpa_cred *cred;
3460 int ret;
3461
3462 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
3463
3464 cred = wpa_config_add_cred(wpa_s->conf);
3465 if (cred == NULL)
3466 return -1;
3467
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003468 wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
3469
Dmitry Shmidt04949592012-07-19 12:16:46 -07003470 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003471 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003472 return -1;
3473 return ret;
3474}
3475
3476
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003477static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
3478 struct wpa_cred *cred)
3479{
3480 struct wpa_ssid *ssid;
3481 char str[20];
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003482 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003483
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003484 if (cred == NULL) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003485 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3486 return -1;
3487 }
3488
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003489 id = cred->id;
3490 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
3491 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3492 return -1;
3493 }
3494
3495 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
3496
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003497 /* Remove any network entry created based on the removed credential */
3498 ssid = wpa_s->conf->ssid;
3499 while (ssid) {
3500 if (ssid->parent_cred == cred) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003501 int res;
3502
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003503 wpa_printf(MSG_DEBUG, "Remove network id %d since it "
3504 "used the removed credential", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003505 res = os_snprintf(str, sizeof(str), "%d", ssid->id);
3506 if (os_snprintf_error(sizeof(str), res))
3507 str[sizeof(str) - 1] = '\0';
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003508 ssid = ssid->next;
3509 wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
3510 } else
3511 ssid = ssid->next;
3512 }
3513
3514 return 0;
3515}
3516
3517
Dmitry Shmidt04949592012-07-19 12:16:46 -07003518static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
3519 char *cmd)
3520{
3521 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003522 struct wpa_cred *cred, *prev;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003523
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003524 /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
3525 * "provisioning_sp=<FQDN> */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003526 if (os_strcmp(cmd, "all") == 0) {
3527 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
3528 cred = wpa_s->conf->cred;
3529 while (cred) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003530 prev = cred;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003531 cred = cred->next;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003532 wpas_ctrl_remove_cred(wpa_s, prev);
3533 }
3534 return 0;
3535 }
3536
3537 if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
3538 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
3539 cmd + 8);
3540 cred = wpa_s->conf->cred;
3541 while (cred) {
3542 prev = cred;
3543 cred = cred->next;
Dmitry Shmidt051af732013-10-22 13:52:46 -07003544 if (prev->domain) {
3545 size_t i;
3546 for (i = 0; i < prev->num_domain; i++) {
3547 if (os_strcmp(prev->domain[i], cmd + 8)
3548 != 0)
3549 continue;
3550 wpas_ctrl_remove_cred(wpa_s, prev);
3551 break;
3552 }
3553 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003554 }
3555 return 0;
3556 }
3557
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003558 if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
3559 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
3560 cmd + 16);
3561 cred = wpa_s->conf->cred;
3562 while (cred) {
3563 prev = cred;
3564 cred = cred->next;
3565 if (prev->provisioning_sp &&
3566 os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
3567 wpas_ctrl_remove_cred(wpa_s, prev);
3568 }
3569 return 0;
3570 }
3571
Dmitry Shmidt04949592012-07-19 12:16:46 -07003572 id = atoi(cmd);
3573 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
3574
3575 cred = wpa_config_get_cred(wpa_s->conf, id);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003576 return wpas_ctrl_remove_cred(wpa_s, cred);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003577}
3578
3579
3580static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
3581 char *cmd)
3582{
3583 int id;
3584 struct wpa_cred *cred;
3585 char *name, *value;
3586
3587 /* cmd: "<cred id> <variable name> <value>" */
3588 name = os_strchr(cmd, ' ');
3589 if (name == NULL)
3590 return -1;
3591 *name++ = '\0';
3592
3593 value = os_strchr(name, ' ');
3594 if (value == NULL)
3595 return -1;
3596 *value++ = '\0';
3597
3598 id = atoi(cmd);
3599 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
3600 id, name);
3601 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3602 (u8 *) value, os_strlen(value));
3603
3604 cred = wpa_config_get_cred(wpa_s->conf, id);
3605 if (cred == NULL) {
3606 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3607 id);
3608 return -1;
3609 }
3610
3611 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
3612 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
3613 "variable '%s'", name);
3614 return -1;
3615 }
3616
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003617 wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
3618
Dmitry Shmidt04949592012-07-19 12:16:46 -07003619 return 0;
3620}
3621
3622
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003623static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
3624 char *cmd, char *buf,
3625 size_t buflen)
3626{
3627 int id;
3628 size_t res;
3629 struct wpa_cred *cred;
3630 char *name, *value;
3631
3632 /* cmd: "<cred id> <variable name>" */
3633 name = os_strchr(cmd, ' ');
3634 if (name == NULL)
3635 return -1;
3636 *name++ = '\0';
3637
3638 id = atoi(cmd);
3639 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
3640 id, name);
3641
3642 cred = wpa_config_get_cred(wpa_s->conf, id);
3643 if (cred == NULL) {
3644 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3645 id);
3646 return -1;
3647 }
3648
3649 value = wpa_config_get_cred_no_key(cred, name);
3650 if (value == NULL) {
3651 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
3652 name);
3653 return -1;
3654 }
3655
3656 res = os_strlcpy(buf, value, buflen);
3657 if (res >= buflen) {
3658 os_free(value);
3659 return -1;
3660 }
3661
3662 os_free(value);
3663
3664 return res;
3665}
3666
3667
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003668#ifndef CONFIG_NO_CONFIG_WRITE
3669static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
3670{
3671 int ret;
3672
3673 if (!wpa_s->conf->update_config) {
3674 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
3675 "to update configuration (update_config=0)");
3676 return -1;
3677 }
3678
3679 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3680 if (ret) {
3681 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
3682 "update configuration");
3683 } else {
3684 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
3685 " updated");
3686 }
3687
3688 return ret;
3689}
3690#endif /* CONFIG_NO_CONFIG_WRITE */
3691
3692
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003693struct cipher_info {
3694 unsigned int capa;
3695 const char *name;
3696 int group_only;
3697};
3698
3699static const struct cipher_info ciphers[] = {
3700 { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
3701 { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
3702 { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
3703 { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
3704 { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
3705 { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
3706 { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
3707 { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
3708};
3709
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003710static const struct cipher_info ciphers_group_mgmt[] = {
3711 { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
3712 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
3713 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
3714 { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
3715};
3716
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003717
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003718static int ctrl_iface_get_capability_pairwise(int res, char *strict,
3719 struct wpa_driver_capa *capa,
3720 char *buf, size_t buflen)
3721{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003722 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003723 char *pos, *end;
3724 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003725 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003726
3727 pos = buf;
3728 end = pos + buflen;
3729
3730 if (res < 0) {
3731 if (strict)
3732 return 0;
3733 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
3734 if (len >= buflen)
3735 return -1;
3736 return len;
3737 }
3738
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003739 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3740 if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
3741 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003742 pos == buf ? "" : " ",
3743 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003744 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003745 return pos - buf;
3746 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003747 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003748 }
3749
3750 return pos - buf;
3751}
3752
3753
3754static int ctrl_iface_get_capability_group(int res, char *strict,
3755 struct wpa_driver_capa *capa,
3756 char *buf, size_t buflen)
3757{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003758 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003759 char *pos, *end;
3760 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003761 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003762
3763 pos = buf;
3764 end = pos + buflen;
3765
3766 if (res < 0) {
3767 if (strict)
3768 return 0;
3769 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
3770 if (len >= buflen)
3771 return -1;
3772 return len;
3773 }
3774
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003775 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3776 if (capa->enc & ciphers[i].capa) {
3777 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003778 pos == buf ? "" : " ",
3779 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003780 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003781 return pos - buf;
3782 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003783 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003784 }
3785
3786 return pos - buf;
3787}
3788
3789
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003790static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
3791 struct wpa_driver_capa *capa,
3792 char *buf, size_t buflen)
3793{
3794 int ret;
3795 char *pos, *end;
3796 unsigned int i;
3797
3798 pos = buf;
3799 end = pos + buflen;
3800
3801 if (res < 0)
3802 return 0;
3803
3804 for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
3805 if (capa->enc & ciphers_group_mgmt[i].capa) {
3806 ret = os_snprintf(pos, end - pos, "%s%s",
3807 pos == buf ? "" : " ",
3808 ciphers_group_mgmt[i].name);
3809 if (os_snprintf_error(end - pos, ret))
3810 return pos - buf;
3811 pos += ret;
3812 }
3813 }
3814
3815 return pos - buf;
3816}
3817
3818
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003819static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
3820 struct wpa_driver_capa *capa,
3821 char *buf, size_t buflen)
3822{
3823 int ret;
3824 char *pos, *end;
3825 size_t len;
3826
3827 pos = buf;
3828 end = pos + buflen;
3829
3830 if (res < 0) {
3831 if (strict)
3832 return 0;
3833 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
3834 "NONE", buflen);
3835 if (len >= buflen)
3836 return -1;
3837 return len;
3838 }
3839
3840 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003841 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003842 return pos - buf;
3843 pos += ret;
3844
3845 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3846 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3847 ret = os_snprintf(pos, end - pos, " WPA-EAP");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003848 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003849 return pos - buf;
3850 pos += ret;
3851 }
3852
3853 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3854 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3855 ret = os_snprintf(pos, end - pos, " WPA-PSK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003856 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003857 return pos - buf;
3858 pos += ret;
3859 }
3860
3861 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
3862 ret = os_snprintf(pos, end - pos, " WPA-NONE");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003863 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003864 return pos - buf;
3865 pos += ret;
3866 }
3867
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003868#ifdef CONFIG_SUITEB
3869 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
3870 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
3871 if (os_snprintf_error(end - pos, ret))
3872 return pos - buf;
3873 pos += ret;
3874 }
3875#endif /* CONFIG_SUITEB */
3876#ifdef CONFIG_SUITEB192
3877 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
3878 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
3879 if (os_snprintf_error(end - pos, ret))
3880 return pos - buf;
3881 pos += ret;
3882 }
3883#endif /* CONFIG_SUITEB192 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003884#ifdef CONFIG_OWE
3885 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
3886 ret = os_snprintf(pos, end - pos, " OWE");
3887 if (os_snprintf_error(end - pos, ret))
3888 return pos - buf;
3889 pos += ret;
3890 }
3891#endif /* CONFIG_OWE */
3892#ifdef CONFIG_DPP
3893 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
3894 ret = os_snprintf(pos, end - pos, " DPP");
3895 if (os_snprintf_error(end - pos, ret))
3896 return pos - buf;
3897 pos += ret;
3898 }
3899#endif /* CONFIG_DPP */
3900#ifdef CONFIG_FILS
3901 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
3902 ret = os_snprintf(pos, end - pos, " FILS-SHA256");
3903 if (os_snprintf_error(end - pos, ret))
3904 return pos - buf;
3905 pos += ret;
3906 }
3907 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
3908 ret = os_snprintf(pos, end - pos, " FILS-SHA384");
3909 if (os_snprintf_error(end - pos, ret))
3910 return pos - buf;
3911 pos += ret;
3912 }
3913#ifdef CONFIG_IEEE80211R
3914 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256) {
3915 ret = os_snprintf(pos, end - pos, " FT-FILS-SHA256");
3916 if (os_snprintf_error(end - pos, ret))
3917 return pos - buf;
3918 pos += ret;
3919 }
3920 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384) {
3921 ret = os_snprintf(pos, end - pos, " FT-FILS-SHA384");
3922 if (os_snprintf_error(end - pos, ret))
3923 return pos - buf;
3924 pos += ret;
3925 }
3926#endif /* CONFIG_IEEE80211R */
3927#endif /* CONFIG_FILS */
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003928
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003929 return pos - buf;
3930}
3931
3932
3933static int ctrl_iface_get_capability_proto(int res, char *strict,
3934 struct wpa_driver_capa *capa,
3935 char *buf, size_t buflen)
3936{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003937 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003938 char *pos, *end;
3939 size_t len;
3940
3941 pos = buf;
3942 end = pos + buflen;
3943
3944 if (res < 0) {
3945 if (strict)
3946 return 0;
3947 len = os_strlcpy(buf, "RSN WPA", buflen);
3948 if (len >= buflen)
3949 return -1;
3950 return len;
3951 }
3952
3953 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3954 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003955 ret = os_snprintf(pos, end - pos, "%sRSN",
3956 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003957 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003958 return pos - buf;
3959 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003960 }
3961
3962 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3963 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003964 ret = os_snprintf(pos, end - pos, "%sWPA",
3965 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003966 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003967 return pos - buf;
3968 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003969 }
3970
3971 return pos - buf;
3972}
3973
3974
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003975static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
3976 int res, char *strict,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003977 struct wpa_driver_capa *capa,
3978 char *buf, size_t buflen)
3979{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003980 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003981 char *pos, *end;
3982 size_t len;
3983
3984 pos = buf;
3985 end = pos + buflen;
3986
3987 if (res < 0) {
3988 if (strict)
3989 return 0;
3990 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
3991 if (len >= buflen)
3992 return -1;
3993 return len;
3994 }
3995
3996 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003997 ret = os_snprintf(pos, end - pos, "%sOPEN",
3998 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003999 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004000 return pos - buf;
4001 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004002 }
4003
4004 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
4005 ret = os_snprintf(pos, end - pos, "%sSHARED",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08004006 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004007 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004008 return pos - buf;
4009 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004010 }
4011
4012 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08004013 ret = os_snprintf(pos, end - pos, "%sLEAP",
4014 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004015 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004016 return pos - buf;
4017 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004018 }
4019
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004020#ifdef CONFIG_SAE
4021 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
4022 ret = os_snprintf(pos, end - pos, "%sSAE",
4023 pos == buf ? "" : " ");
4024 if (os_snprintf_error(end - pos, ret))
4025 return pos - buf;
4026 pos += ret;
4027 }
4028#endif /* CONFIG_SAE */
4029
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004030#ifdef CONFIG_FILS
4031 if (wpa_is_fils_supported(wpa_s)) {
4032 ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITHOUT_PFS",
4033 pos == buf ? "" : " ");
4034 if (os_snprintf_error(end - pos, ret))
4035 return pos - buf;
4036 pos += ret;
4037 }
4038
4039#ifdef CONFIG_FILS_SK_PFS
4040 if (wpa_is_fils_sk_pfs_supported(wpa_s)) {
4041 ret = os_snprintf(pos, end - pos, "%sFILS_SK_WITH_PFS",
4042 pos == buf ? "" : " ");
4043 if (os_snprintf_error(end - pos, ret))
4044 return pos - buf;
4045 pos += ret;
4046 }
4047#endif /* CONFIG_FILS_SK_PFS */
4048#endif /* CONFIG_FILS */
4049
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004050 return pos - buf;
4051}
4052
4053
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004054static int ctrl_iface_get_capability_modes(int res, char *strict,
4055 struct wpa_driver_capa *capa,
4056 char *buf, size_t buflen)
4057{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08004058 int ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004059 char *pos, *end;
4060 size_t len;
4061
4062 pos = buf;
4063 end = pos + buflen;
4064
4065 if (res < 0) {
4066 if (strict)
4067 return 0;
4068 len = os_strlcpy(buf, "IBSS AP", buflen);
4069 if (len >= buflen)
4070 return -1;
4071 return len;
4072 }
4073
4074 if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08004075 ret = os_snprintf(pos, end - pos, "%sIBSS",
4076 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004077 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004078 return pos - buf;
4079 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004080 }
4081
4082 if (capa->flags & WPA_DRIVER_FLAGS_AP) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08004083 ret = os_snprintf(pos, end - pos, "%sAP",
4084 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004085 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004086 return pos - buf;
4087 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004088 }
4089
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004090#ifdef CONFIG_MESH
4091 if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
4092 ret = os_snprintf(pos, end - pos, "%sMESH",
4093 pos == buf ? "" : " ");
4094 if (os_snprintf_error(end - pos, ret))
4095 return pos - buf;
4096 pos += ret;
4097 }
4098#endif /* CONFIG_MESH */
4099
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004100 return pos - buf;
4101}
4102
4103
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004104static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
4105 char *buf, size_t buflen)
4106{
4107 struct hostapd_channel_data *chnl;
4108 int ret, i, j;
4109 char *pos, *end, *hmode;
4110
4111 pos = buf;
4112 end = pos + buflen;
4113
4114 for (j = 0; j < wpa_s->hw.num_modes; j++) {
4115 switch (wpa_s->hw.modes[j].mode) {
4116 case HOSTAPD_MODE_IEEE80211B:
4117 hmode = "B";
4118 break;
4119 case HOSTAPD_MODE_IEEE80211G:
4120 hmode = "G";
4121 break;
4122 case HOSTAPD_MODE_IEEE80211A:
4123 hmode = "A";
4124 break;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004125 case HOSTAPD_MODE_IEEE80211AD:
4126 hmode = "AD";
4127 break;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004128 default:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004129 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004130 }
4131 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004132 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004133 return pos - buf;
4134 pos += ret;
4135 chnl = wpa_s->hw.modes[j].channels;
4136 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004137 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
4138 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004139 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004140 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004141 return pos - buf;
4142 pos += ret;
4143 }
4144 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004145 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004146 return pos - buf;
4147 pos += ret;
4148 }
4149
4150 return pos - buf;
4151}
4152
4153
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004154static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
4155 char *buf, size_t buflen)
4156{
4157 struct hostapd_channel_data *chnl;
4158 int ret, i, j;
4159 char *pos, *end, *hmode;
4160
4161 pos = buf;
4162 end = pos + buflen;
4163
4164 for (j = 0; j < wpa_s->hw.num_modes; j++) {
4165 switch (wpa_s->hw.modes[j].mode) {
4166 case HOSTAPD_MODE_IEEE80211B:
4167 hmode = "B";
4168 break;
4169 case HOSTAPD_MODE_IEEE80211G:
4170 hmode = "G";
4171 break;
4172 case HOSTAPD_MODE_IEEE80211A:
4173 hmode = "A";
4174 break;
4175 case HOSTAPD_MODE_IEEE80211AD:
4176 hmode = "AD";
4177 break;
4178 default:
4179 continue;
4180 }
4181 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
4182 hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004183 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004184 return pos - buf;
4185 pos += ret;
4186 chnl = wpa_s->hw.modes[j].channels;
4187 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
4188 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
4189 continue;
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08004190 ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004191 chnl[i].chan, chnl[i].freq,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004192 chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
4193 " (NO_IR)" : "",
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08004194 chnl[i].flag & HOSTAPD_CHAN_RADAR ?
4195 " (DFS)" : "");
4196
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004197 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004198 return pos - buf;
4199 pos += ret;
4200 }
4201 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004202 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004203 return pos - buf;
4204 pos += ret;
4205 }
4206
4207 return pos - buf;
4208}
4209
4210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004211static int wpa_supplicant_ctrl_iface_get_capability(
4212 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
4213 size_t buflen)
4214{
4215 struct wpa_driver_capa capa;
4216 int res;
4217 char *strict;
4218 char field[30];
4219 size_t len;
4220
4221 /* Determine whether or not strict checking was requested */
4222 len = os_strlcpy(field, _field, sizeof(field));
4223 if (len >= sizeof(field))
4224 return -1;
4225 strict = os_strchr(field, ' ');
4226 if (strict != NULL) {
4227 *strict++ = '\0';
4228 if (os_strcmp(strict, "strict") != 0)
4229 return -1;
4230 }
4231
4232 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
4233 field, strict ? strict : "");
4234
4235 if (os_strcmp(field, "eap") == 0) {
4236 return eap_get_names(buf, buflen);
4237 }
4238
4239 res = wpa_drv_get_capa(wpa_s, &capa);
4240
4241 if (os_strcmp(field, "pairwise") == 0)
4242 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
4243 buf, buflen);
4244
4245 if (os_strcmp(field, "group") == 0)
4246 return ctrl_iface_get_capability_group(res, strict, &capa,
4247 buf, buflen);
4248
Dmitry Shmidt807291d2015-01-27 13:40:23 -08004249 if (os_strcmp(field, "group_mgmt") == 0)
4250 return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
4251 buf, buflen);
4252
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004253 if (os_strcmp(field, "key_mgmt") == 0)
4254 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
4255 buf, buflen);
4256
4257 if (os_strcmp(field, "proto") == 0)
4258 return ctrl_iface_get_capability_proto(res, strict, &capa,
4259 buf, buflen);
4260
4261 if (os_strcmp(field, "auth_alg") == 0)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004262 return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
4263 &capa, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004264
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004265 if (os_strcmp(field, "modes") == 0)
4266 return ctrl_iface_get_capability_modes(res, strict, &capa,
4267 buf, buflen);
4268
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004269 if (os_strcmp(field, "channels") == 0)
4270 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
4271
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004272 if (os_strcmp(field, "freq") == 0)
4273 return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
4274
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004275#ifdef CONFIG_TDLS
4276 if (os_strcmp(field, "tdls") == 0)
4277 return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
4278#endif /* CONFIG_TDLS */
4279
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004280#ifdef CONFIG_ERP
4281 if (os_strcmp(field, "erp") == 0) {
4282 res = os_snprintf(buf, buflen, "ERP");
4283 if (os_snprintf_error(buflen, res))
4284 return -1;
4285 return res;
4286 }
4287#endif /* CONFIG_EPR */
4288
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004289#ifdef CONFIG_FIPS
4290 if (os_strcmp(field, "fips") == 0) {
4291 res = os_snprintf(buf, buflen, "FIPS");
4292 if (os_snprintf_error(buflen, res))
4293 return -1;
4294 return res;
4295 }
4296#endif /* CONFIG_FIPS */
4297
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08004298#ifdef CONFIG_ACS
4299 if (os_strcmp(field, "acs") == 0) {
4300 res = os_snprintf(buf, buflen, "ACS");
4301 if (os_snprintf_error(buflen, res))
4302 return -1;
4303 return res;
4304 }
4305#endif /* CONFIG_ACS */
4306
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004307#ifdef CONFIG_FILS
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004308 if (os_strcmp(field, "fils") == 0) {
4309#ifdef CONFIG_FILS_SK_PFS
4310 if (wpa_is_fils_supported(wpa_s) &&
4311 wpa_is_fils_sk_pfs_supported(wpa_s)) {
4312 res = os_snprintf(buf, buflen, "FILS FILS-SK-PFS");
4313 if (os_snprintf_error(buflen, res))
4314 return -1;
4315 return res;
4316 }
4317#endif /* CONFIG_FILS_SK_PFS */
4318
4319 if (wpa_is_fils_supported(wpa_s)) {
4320 res = os_snprintf(buf, buflen, "FILS");
4321 if (os_snprintf_error(buflen, res))
4322 return -1;
4323 return res;
4324 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004325 }
4326#endif /* CONFIG_FILS */
4327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004328 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
4329 field);
4330
4331 return -1;
4332}
4333
4334
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004335#ifdef CONFIG_INTERWORKING
4336static char * anqp_add_hex(char *pos, char *end, const char *title,
4337 struct wpabuf *data)
4338{
4339 char *start = pos;
4340 size_t i;
4341 int ret;
4342 const u8 *d;
4343
4344 if (data == NULL)
4345 return start;
4346
4347 ret = os_snprintf(pos, end - pos, "%s=", title);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004348 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004349 return start;
4350 pos += ret;
4351
4352 d = wpabuf_head_u8(data);
4353 for (i = 0; i < wpabuf_len(data); i++) {
4354 ret = os_snprintf(pos, end - pos, "%02x", *d++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004355 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004356 return start;
4357 pos += ret;
4358 }
4359
4360 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004361 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004362 return start;
4363 pos += ret;
4364
4365 return pos;
4366}
4367#endif /* CONFIG_INTERWORKING */
4368
4369
Dmitry Shmidt29333592017-01-09 12:27:11 -08004370#ifdef CONFIG_FILS
4371static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end)
4372{
4373 char *start = pos;
4374 const u8 *ie, *ie_end;
4375 u16 info, realms;
4376 int ret;
4377
4378 ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
4379 if (!ie)
4380 return 0;
4381 ie_end = ie + 2 + ie[1];
4382 ie += 2;
4383 if (ie_end - ie < 2)
4384 return -1;
4385
4386 info = WPA_GET_LE16(ie);
4387 ie += 2;
4388 ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info);
4389 if (os_snprintf_error(end - pos, ret))
4390 return 0;
4391 pos += ret;
4392
4393 if (info & BIT(7)) {
4394 /* Cache Identifier Included */
4395 if (ie_end - ie < 2)
4396 return -1;
4397 ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n",
4398 ie[0], ie[1]);
4399 if (os_snprintf_error(end - pos, ret))
4400 return 0;
4401 pos += ret;
4402 ie += 2;
4403 }
4404
4405 if (info & BIT(8)) {
4406 /* HESSID Included */
4407 if (ie_end - ie < ETH_ALEN)
4408 return -1;
4409 ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n",
4410 MAC2STR(ie));
4411 if (os_snprintf_error(end - pos, ret))
4412 return 0;
4413 pos += ret;
4414 ie += ETH_ALEN;
4415 }
4416
4417 realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3;
4418 if (realms) {
4419 if (ie_end - ie < realms * 2)
4420 return -1;
4421 ret = os_snprintf(pos, end - pos, "fils_realms=");
4422 if (os_snprintf_error(end - pos, ret))
4423 return 0;
4424 pos += ret;
4425
4426 ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2);
4427 if (ret <= 0)
4428 return 0;
4429 pos += ret;
4430 ie += realms * 2;
4431 ret = os_snprintf(pos, end - pos, "\n");
4432 if (os_snprintf_error(end - pos, ret))
4433 return 0;
4434 pos += ret;
4435 }
4436
4437 return pos - start;
4438}
4439#endif /* CONFIG_FILS */
4440
4441
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004442static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
4443 unsigned long mask, char *buf, size_t buflen)
4444{
4445 size_t i;
4446 int ret;
4447 char *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004448 const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004449
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004450 pos = buf;
4451 end = buf + buflen;
4452
4453 if (mask & WPA_BSS_MASK_ID) {
4454 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004455 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004456 return 0;
4457 pos += ret;
4458 }
4459
4460 if (mask & WPA_BSS_MASK_BSSID) {
4461 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
4462 MAC2STR(bss->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004463 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004464 return 0;
4465 pos += ret;
4466 }
4467
4468 if (mask & WPA_BSS_MASK_FREQ) {
4469 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004470 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004471 return 0;
4472 pos += ret;
4473 }
4474
4475 if (mask & WPA_BSS_MASK_BEACON_INT) {
4476 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
4477 bss->beacon_int);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004478 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004479 return 0;
4480 pos += ret;
4481 }
4482
4483 if (mask & WPA_BSS_MASK_CAPABILITIES) {
4484 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
4485 bss->caps);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004486 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004487 return 0;
4488 pos += ret;
4489 }
4490
4491 if (mask & WPA_BSS_MASK_QUAL) {
4492 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004493 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004494 return 0;
4495 pos += ret;
4496 }
4497
4498 if (mask & WPA_BSS_MASK_NOISE) {
4499 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004500 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004501 return 0;
4502 pos += ret;
4503 }
4504
4505 if (mask & WPA_BSS_MASK_LEVEL) {
4506 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004507 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004508 return 0;
4509 pos += ret;
4510 }
4511
4512 if (mask & WPA_BSS_MASK_TSF) {
4513 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
4514 (unsigned long long) bss->tsf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004515 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004516 return 0;
4517 pos += ret;
4518 }
4519
4520 if (mask & WPA_BSS_MASK_AGE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004521 struct os_reltime now;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004522
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004523 os_get_reltime(&now);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004524 ret = os_snprintf(pos, end - pos, "age=%d\n",
4525 (int) (now.sec - bss->last_update.sec));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004526 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004527 return 0;
4528 pos += ret;
4529 }
4530
4531 if (mask & WPA_BSS_MASK_IE) {
4532 ret = os_snprintf(pos, end - pos, "ie=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004533 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004534 return 0;
4535 pos += ret;
4536
4537 ie = (const u8 *) (bss + 1);
4538 for (i = 0; i < bss->ie_len; i++) {
4539 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004540 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004541 return 0;
4542 pos += ret;
4543 }
4544
4545 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004546 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004547 return 0;
4548 pos += ret;
4549 }
4550
4551 if (mask & WPA_BSS_MASK_FLAGS) {
4552 ret = os_snprintf(pos, end - pos, "flags=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004553 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004554 return 0;
4555 pos += ret;
4556
Dmitry Shmidt29333592017-01-09 12:27:11 -08004557 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
4558
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004559 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
4560 if (ie)
4561 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
4562 2 + ie[1]);
4563 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
4564 if (ie2)
Dmitry Shmidt29333592017-01-09 12:27:11 -08004565 pos = wpa_supplicant_ie_txt(pos, end,
4566 mesh ? "RSN" : "WPA2", ie2,
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004567 2 + ie2[1]);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07004568 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
4569 if (osen_ie)
4570 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
4571 osen_ie, 2 + osen_ie[1]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004572 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
4573 if (owe) {
4574 ret = os_snprintf(
4575 pos, end - pos,
4576 ie2 ? "[OWE-TRANS]" : "[OWE-TRANS-OPEN]");
4577 if (os_snprintf_error(end - pos, ret))
4578 return 0;
4579 pos += ret;
4580 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004581 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07004582 if (!ie && !ie2 && !osen_ie &&
4583 (bss->caps & IEEE80211_CAP_PRIVACY)) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004584 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004585 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004586 return 0;
4587 pos += ret;
4588 }
Dmitry Shmidt29333592017-01-09 12:27:11 -08004589
4590 if (mesh) {
4591 ret = os_snprintf(pos, end - pos, "[MESH]");
4592 if (os_snprintf_error(end - pos, ret))
4593 return 0;
4594 pos += ret;
4595 }
4596
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004597 if (bss_is_dmg(bss)) {
4598 const char *s;
4599 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004600 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004601 return 0;
4602 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004603 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
4604 case IEEE80211_CAP_DMG_IBSS:
4605 s = "[IBSS]";
4606 break;
4607 case IEEE80211_CAP_DMG_AP:
4608 s = "[ESS]";
4609 break;
4610 case IEEE80211_CAP_DMG_PBSS:
4611 s = "[PBSS]";
4612 break;
4613 default:
4614 s = "";
4615 break;
4616 }
4617 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004618 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004619 return 0;
4620 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004621 } else {
4622 if (bss->caps & IEEE80211_CAP_IBSS) {
4623 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004624 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004625 return 0;
4626 pos += ret;
4627 }
4628 if (bss->caps & IEEE80211_CAP_ESS) {
4629 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004630 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004631 return 0;
4632 pos += ret;
4633 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004634 }
Dmitry Shmidt96571392013-10-14 12:54:46 -07004635 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
4636 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004637 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004638 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004639 return 0;
4640 pos += ret;
4641 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004642#ifdef CONFIG_HS20
4643 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
4644 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004645 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004646 return 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004647 pos += ret;
4648 }
4649#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004650#ifdef CONFIG_FILS
4651 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
4652 ret = os_snprintf(pos, end - pos, "[FILS]");
4653 if (os_snprintf_error(end - pos, ret))
4654 return 0;
4655 pos += ret;
4656 }
4657#endif /* CONFIG_FILS */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004658
4659 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004660 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004661 return 0;
4662 pos += ret;
4663 }
4664
4665 if (mask & WPA_BSS_MASK_SSID) {
4666 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
4667 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004668 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004669 return 0;
4670 pos += ret;
4671 }
4672
4673#ifdef CONFIG_WPS
4674 if (mask & WPA_BSS_MASK_WPS_SCAN) {
4675 ie = (const u8 *) (bss + 1);
4676 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004677 if (ret >= end - pos)
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004678 return 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004679 if (ret > 0)
4680 pos += ret;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004681 }
4682#endif /* CONFIG_WPS */
4683
4684#ifdef CONFIG_P2P
4685 if (mask & WPA_BSS_MASK_P2P_SCAN) {
4686 ie = (const u8 *) (bss + 1);
4687 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004688 if (ret >= end - pos)
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004689 return 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004690 if (ret > 0)
4691 pos += ret;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004692 }
4693#endif /* CONFIG_P2P */
4694
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004695#ifdef CONFIG_WIFI_DISPLAY
4696 if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
4697 struct wpabuf *wfd;
4698 ie = (const u8 *) (bss + 1);
4699 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
4700 WFD_IE_VENDOR_TYPE);
4701 if (wfd) {
4702 ret = os_snprintf(pos, end - pos, "wfd_subelems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004703 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004704 wpabuf_free(wfd);
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004705 return 0;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004706 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004707 pos += ret;
4708
4709 pos += wpa_snprintf_hex(pos, end - pos,
4710 wpabuf_head(wfd),
4711 wpabuf_len(wfd));
4712 wpabuf_free(wfd);
4713
4714 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004715 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004716 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004717 pos += ret;
4718 }
4719 }
4720#endif /* CONFIG_WIFI_DISPLAY */
4721
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004722#ifdef CONFIG_INTERWORKING
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004723 if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
4724 struct wpa_bss_anqp *anqp = bss->anqp;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004725 struct wpa_bss_anqp_elem *elem;
4726
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004727 pos = anqp_add_hex(pos, end, "anqp_capability_list",
4728 anqp->capability_list);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004729 pos = anqp_add_hex(pos, end, "anqp_venue_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004730 anqp->venue_name);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004731 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004732 anqp->network_auth_type);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004733 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004734 anqp->roaming_consortium);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004735 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004736 anqp->ip_addr_type_availability);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004737 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004738 anqp->nai_realm);
4739 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004740 pos = anqp_add_hex(pos, end, "anqp_domain_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004741 anqp->domain_name);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004742 pos = anqp_add_hex(pos, end, "anqp_fils_realm_info",
4743 anqp->fils_realm_info);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004744#ifdef CONFIG_HS20
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004745 pos = anqp_add_hex(pos, end, "hs20_capability_list",
4746 anqp->hs20_capability_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004747 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004748 anqp->hs20_operator_friendly_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004749 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004750 anqp->hs20_wan_metrics);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004751 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004752 anqp->hs20_connection_capability);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004753 pos = anqp_add_hex(pos, end, "hs20_operating_class",
4754 anqp->hs20_operating_class);
4755 pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
4756 anqp->hs20_osu_providers_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004757#endif /* CONFIG_HS20 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004758
4759 dl_list_for_each(elem, &anqp->anqp_elems,
4760 struct wpa_bss_anqp_elem, list) {
4761 char title[20];
4762
4763 os_snprintf(title, sizeof(title), "anqp[%u]",
4764 elem->infoid);
4765 pos = anqp_add_hex(pos, end, title, elem->payload);
4766 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004767 }
4768#endif /* CONFIG_INTERWORKING */
4769
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004770#ifdef CONFIG_MESH
4771 if (mask & WPA_BSS_MASK_MESH_SCAN) {
4772 ie = (const u8 *) (bss + 1);
4773 ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004774 if (ret >= end - pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004775 return 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004776 if (ret > 0)
4777 pos += ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004778 }
4779#endif /* CONFIG_MESH */
4780
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004781 if (mask & WPA_BSS_MASK_SNR) {
4782 ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
4783 if (os_snprintf_error(end - pos, ret))
4784 return 0;
4785 pos += ret;
4786 }
4787
4788 if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
4789 ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
4790 bss->est_throughput);
4791 if (os_snprintf_error(end - pos, ret))
4792 return 0;
4793 pos += ret;
4794 }
4795
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004796#ifdef CONFIG_FST
4797 if (mask & WPA_BSS_MASK_FST) {
4798 ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos);
4799 if (ret < 0 || ret >= end - pos)
4800 return 0;
4801 pos += ret;
4802 }
4803#endif /* CONFIG_FST */
4804
Dmitry Shmidt29333592017-01-09 12:27:11 -08004805 if (mask & WPA_BSS_MASK_UPDATE_IDX) {
4806 ret = os_snprintf(pos, end - pos, "update_idx=%u\n",
4807 bss->last_update_idx);
4808 if (os_snprintf_error(end - pos, ret))
4809 return 0;
4810 pos += ret;
4811 }
4812
4813 if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) {
4814 ret = os_snprintf(pos, end - pos, "beacon_ie=");
4815 if (os_snprintf_error(end - pos, ret))
4816 return 0;
4817 pos += ret;
4818
4819 ie = (const u8 *) (bss + 1);
4820 ie += bss->ie_len;
4821 for (i = 0; i < bss->beacon_ie_len; i++) {
4822 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
4823 if (os_snprintf_error(end - pos, ret))
4824 return 0;
4825 pos += ret;
4826 }
4827
4828 ret = os_snprintf(pos, end - pos, "\n");
4829 if (os_snprintf_error(end - pos, ret))
4830 return 0;
4831 pos += ret;
4832 }
4833
4834#ifdef CONFIG_FILS
4835 if (mask & WPA_BSS_MASK_FILS_INDICATION) {
4836 ret = print_fils_indication(bss, pos, end);
4837 if (ret < 0)
4838 return 0;
4839 pos += ret;
4840 }
4841#endif /* CONFIG_FILS */
4842
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004843 if (mask & WPA_BSS_MASK_DELIM) {
4844 ret = os_snprintf(pos, end - pos, "====\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004845 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004846 return 0;
4847 pos += ret;
4848 }
Irfan Sheriffe2ea0082012-08-13 10:56:16 -07004849
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004850 return pos - buf;
4851}
4852
Dmitry Shmidt04949592012-07-19 12:16:46 -07004853
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004854static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
4855 const char *cmd, char *buf,
4856 size_t buflen)
4857{
4858 u8 bssid[ETH_ALEN];
4859 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004860 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004861 struct wpa_bss *bsslast = NULL;
4862 struct dl_list *next;
4863 int ret = 0;
4864 int len;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004865 char *ctmp, *end = buf + buflen;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004866 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004867
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004868 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
4869 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
4870 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004871 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004872 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
4873 list_id);
4874 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004875 unsigned int id1, id2;
4876
4877 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
4878 wpa_printf(MSG_INFO, "Wrong BSS range "
4879 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004880 return 0;
4881 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004882
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004883 if (*(cmd + 6) == '-')
4884 id1 = 0;
4885 else
4886 id1 = atoi(cmd + 6);
4887 ctmp++;
4888 if (*ctmp >= '0' && *ctmp <= '9')
4889 id2 = atoi(ctmp);
4890 else
4891 id2 = (unsigned int) -1;
4892 bss = wpa_bss_get_id_range(wpa_s, id1, id2);
4893 if (id2 == (unsigned int) -1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004894 bsslast = dl_list_last(&wpa_s->bss_id,
4895 struct wpa_bss,
4896 list_id);
4897 else {
4898 bsslast = wpa_bss_get_id(wpa_s, id2);
4899 if (bsslast == NULL && bss && id2 > id1) {
4900 struct wpa_bss *tmp = bss;
4901 for (;;) {
4902 next = tmp->list_id.next;
4903 if (next == &wpa_s->bss_id)
4904 break;
4905 tmp = dl_list_entry(
4906 next, struct wpa_bss,
4907 list_id);
4908 if (tmp->id > id2)
4909 break;
4910 bsslast = tmp;
4911 }
4912 }
4913 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004914 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004915 } else if (os_strncmp(cmd, "FIRST", 5) == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004916 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004917 else if (os_strncmp(cmd, "LAST", 4) == 0)
4918 bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004919 else if (os_strncmp(cmd, "ID-", 3) == 0) {
4920 i = atoi(cmd + 3);
4921 bss = wpa_bss_get_id(wpa_s, i);
4922 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4923 i = atoi(cmd + 5);
4924 bss = wpa_bss_get_id(wpa_s, i);
4925 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004926 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004927 if (next == &wpa_s->bss_id)
4928 bss = NULL;
4929 else
4930 bss = dl_list_entry(next, struct wpa_bss,
4931 list_id);
4932 }
Dmitry Shmidt29333592017-01-09 12:27:11 -08004933 } else if (os_strncmp(cmd, "CURRENT", 7) == 0) {
4934 bss = wpa_s->current_bss;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004935#ifdef CONFIG_P2P
4936 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
4937 if (hwaddr_aton(cmd + 13, bssid) == 0)
4938 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
4939 else
4940 bss = NULL;
4941#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004942 } else if (hwaddr_aton(cmd, bssid) == 0)
4943 bss = wpa_bss_get_bssid(wpa_s, bssid);
4944 else {
4945 struct wpa_bss *tmp;
4946 i = atoi(cmd);
4947 bss = NULL;
4948 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
4949 {
4950 if (i-- == 0) {
4951 bss = tmp;
4952 break;
4953 }
4954 }
4955 }
4956
Dmitry Shmidt04949592012-07-19 12:16:46 -07004957 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
4958 mask = strtoul(ctmp + 5, NULL, 0x10);
4959 if (mask == 0)
4960 mask = WPA_BSS_MASK_ALL;
4961 }
4962
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004963 if (bss == NULL)
4964 return 0;
4965
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004966 if (bsslast == NULL)
4967 bsslast = bss;
4968 do {
4969 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
4970 ret += len;
4971 buf += len;
4972 buflen -= len;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004973 if (bss == bsslast) {
4974 if ((mask & WPA_BSS_MASK_DELIM) && len &&
4975 (bss == dl_list_last(&wpa_s->bss_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004976 struct wpa_bss, list_id))) {
4977 int res;
4978
4979 res = os_snprintf(buf - 5, end - buf + 5,
4980 "####\n");
4981 if (os_snprintf_error(end - buf + 5, res)) {
4982 wpa_printf(MSG_DEBUG,
4983 "Could not add end delim");
4984 }
4985 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004986 break;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004987 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004988 next = bss->list_id.next;
4989 if (next == &wpa_s->bss_id)
4990 break;
4991 bss = dl_list_entry(next, struct wpa_bss, list_id);
4992 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004993
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004994 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004995}
4996
4997
4998static int wpa_supplicant_ctrl_iface_ap_scan(
4999 struct wpa_supplicant *wpa_s, char *cmd)
5000{
5001 int ap_scan = atoi(cmd);
5002 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
5003}
5004
5005
5006static int wpa_supplicant_ctrl_iface_scan_interval(
5007 struct wpa_supplicant *wpa_s, char *cmd)
5008{
5009 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005010 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005011}
5012
5013
5014static int wpa_supplicant_ctrl_iface_bss_expire_age(
5015 struct wpa_supplicant *wpa_s, char *cmd)
5016{
5017 int expire_age = atoi(cmd);
5018 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
5019}
5020
5021
5022static int wpa_supplicant_ctrl_iface_bss_expire_count(
5023 struct wpa_supplicant *wpa_s, char *cmd)
5024{
5025 int expire_count = atoi(cmd);
5026 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
5027}
5028
5029
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005030static void wpa_supplicant_ctrl_iface_bss_flush(
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07005031 struct wpa_supplicant *wpa_s, char *cmd)
5032{
5033 int flush_age = atoi(cmd);
5034
5035 if (flush_age == 0)
5036 wpa_bss_flush(wpa_s);
5037 else
5038 wpa_bss_flush_by_age(wpa_s, flush_age);
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07005039}
5040
5041
Dmitry Shmidt21de2142014-04-08 10:50:52 -07005042#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005043static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
5044{
5045 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
5046 /* MLME-DELETEKEYS.request */
5047 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
5048 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
5049 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
5050 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
5051#ifdef CONFIG_IEEE80211W
5052 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
5053 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
5054#endif /* CONFIG_IEEE80211W */
5055
5056 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
5057 0);
5058 /* MLME-SETPROTECTION.request(None) */
5059 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
5060 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
5061 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
5062 wpa_sm_drop_sa(wpa_s->wpa);
5063}
Dmitry Shmidt21de2142014-04-08 10:50:52 -07005064#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005065
5066
5067static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
5068 char *addr)
5069{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005070#ifdef CONFIG_NO_SCAN_PROCESSING
5071 return -1;
5072#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005073 u8 bssid[ETH_ALEN];
5074 struct wpa_bss *bss;
5075 struct wpa_ssid *ssid = wpa_s->current_ssid;
5076
5077 if (hwaddr_aton(addr, bssid)) {
5078 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
5079 "address '%s'", addr);
5080 return -1;
5081 }
5082
5083 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
5084
Dmitry Shmidt444d5672013-04-01 13:08:44 -07005085 if (!ssid) {
5086 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
5087 "configuration known for the target AP");
5088 return -1;
5089 }
5090
5091 bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005092 if (!bss) {
5093 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
5094 "from BSS table");
5095 return -1;
5096 }
5097
5098 /*
5099 * TODO: Find best network configuration block from configuration to
5100 * allow roaming to other networks
5101 */
5102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005103 wpa_s->reassociate = 1;
5104 wpa_supplicant_connect(wpa_s, bss, ssid);
5105
5106 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005107#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005108}
5109
5110
5111#ifdef CONFIG_P2P
5112static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
5113{
5114 unsigned int timeout = atoi(cmd);
5115 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005116 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005117 u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005118 char *pos;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005119 unsigned int search_delay;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005120 const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005121 u8 seek_count = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005122 int freq = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005123
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07005124 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
5125 wpa_dbg(wpa_s, MSG_INFO,
5126 "Reject P2P_FIND since interface is disabled");
5127 return -1;
5128 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005129 if (os_strstr(cmd, "type=social"))
5130 type = P2P_FIND_ONLY_SOCIAL;
5131 else if (os_strstr(cmd, "type=progressive"))
5132 type = P2P_FIND_PROGRESSIVE;
5133
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005134 pos = os_strstr(cmd, "dev_id=");
5135 if (pos) {
5136 pos += 7;
5137 if (hwaddr_aton(pos, dev_id))
5138 return -1;
5139 _dev_id = dev_id;
5140 }
5141
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005142 pos = os_strstr(cmd, "dev_type=");
5143 if (pos) {
5144 pos += 9;
5145 if (wps_dev_type_str2bin(pos, dev_type) < 0)
5146 return -1;
5147 _dev_type = dev_type;
5148 }
5149
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005150 pos = os_strstr(cmd, "delay=");
5151 if (pos) {
5152 pos += 6;
5153 search_delay = atoi(pos);
5154 } else
5155 search_delay = wpas_p2p_search_delay(wpa_s);
5156
Dmitry Shmidt41712582015-06-29 11:02:15 -07005157 pos = os_strstr(cmd, "freq=");
5158 if (pos) {
5159 pos += 5;
5160 freq = atoi(pos);
5161 if (freq <= 0)
5162 return -1;
5163 }
5164
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005165 /* Must be searched for last, because it adds nul termination */
5166 pos = os_strstr(cmd, " seek=");
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005167 if (pos)
5168 pos += 6;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005169 while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
5170 char *term;
5171
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005172 _seek[seek_count++] = pos;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005173 seek = _seek;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005174 term = os_strchr(pos, ' ');
5175 if (!term)
5176 break;
5177 *term = '\0';
5178 pos = os_strstr(term + 1, "seek=");
5179 if (pos)
5180 pos += 5;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005181 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005182 if (seek_count > P2P_MAX_QUERY_HASH) {
5183 seek[0] = NULL;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005184 seek_count = 1;
5185 }
5186
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005187 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005188 _dev_id, search_delay, seek_count, seek, freq);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005189}
5190
5191
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005192static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
5193{
5194 const char *last = NULL;
5195 const char *token;
5196 long int token_len;
5197 unsigned int i;
5198
5199 /* Expected predefined CPT names delimited by ':' */
5200 for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) {
5201 if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
5202 wpa_printf(MSG_ERROR,
5203 "P2PS: CPT name list is too long, expected up to %d names",
5204 P2PS_FEATURE_CAPAB_CPT_MAX);
5205 cpt[0] = 0;
5206 return -1;
5207 }
5208
5209 token_len = last - token;
5210
5211 if (token_len == 3 &&
5212 os_memcmp(token, "UDP", token_len) == 0) {
5213 cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5214 } else if (token_len == 3 &&
5215 os_memcmp(token, "MAC", token_len) == 0) {
5216 cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
5217 } else {
5218 wpa_printf(MSG_ERROR,
5219 "P2PS: Unsupported CPT name '%s'", token);
5220 cpt[0] = 0;
5221 return -1;
5222 }
5223
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005224 if (isblank((unsigned char) *last)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005225 i++;
5226 break;
5227 }
5228 }
5229 cpt[i] = 0;
5230 return 0;
5231}
5232
5233
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005234static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
5235{
5236 struct p2ps_provision *p2ps_prov;
5237 char *pos;
5238 size_t info_len = 0;
5239 char *info = NULL;
5240 u8 role = P2PS_SETUP_NONE;
5241 long long unsigned val;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005242 int i;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005243
5244 pos = os_strstr(cmd, "info=");
5245 if (pos) {
5246 pos += 5;
5247 info_len = os_strlen(pos);
5248
5249 if (info_len) {
5250 info = os_malloc(info_len + 1);
5251 if (info) {
5252 info_len = utf8_unescape(pos, info_len,
5253 info, info_len + 1);
5254 } else
5255 info_len = 0;
5256 }
5257 }
5258
5259 p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
5260 if (p2ps_prov == NULL) {
5261 os_free(info);
5262 return NULL;
5263 }
5264
5265 if (info) {
5266 os_memcpy(p2ps_prov->info, info, info_len);
5267 p2ps_prov->info[info_len] = '\0';
5268 os_free(info);
5269 }
5270
5271 pos = os_strstr(cmd, "status=");
5272 if (pos)
5273 p2ps_prov->status = atoi(pos + 7);
5274 else
5275 p2ps_prov->status = -1;
5276
5277 pos = os_strstr(cmd, "adv_id=");
5278 if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
5279 goto invalid_args;
5280 p2ps_prov->adv_id = val;
5281
5282 pos = os_strstr(cmd, "method=");
5283 if (pos)
5284 p2ps_prov->method = strtol(pos + 7, NULL, 16);
5285 else
5286 p2ps_prov->method = 0;
5287
5288 pos = os_strstr(cmd, "session=");
5289 if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
5290 goto invalid_args;
5291 p2ps_prov->session_id = val;
5292
5293 pos = os_strstr(cmd, "adv_mac=");
5294 if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
5295 goto invalid_args;
5296
5297 pos = os_strstr(cmd, "session_mac=");
5298 if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
5299 goto invalid_args;
5300
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005301 pos = os_strstr(cmd, "cpt=");
5302 if (pos) {
5303 if (p2ps_ctrl_parse_cpt_priority(pos + 4,
5304 p2ps_prov->cpt_priority))
5305 goto invalid_args;
5306 } else {
5307 p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5308 }
5309
5310 for (i = 0; p2ps_prov->cpt_priority[i]; i++)
5311 p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
5312
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005313 /* force conncap with tstCap (no sanity checks) */
5314 pos = os_strstr(cmd, "tstCap=");
5315 if (pos) {
5316 role = strtol(pos + 7, NULL, 16);
5317 } else {
5318 pos = os_strstr(cmd, "role=");
5319 if (pos) {
5320 role = strtol(pos + 5, NULL, 16);
5321 if (role != P2PS_SETUP_CLIENT &&
5322 role != P2PS_SETUP_GROUP_OWNER)
5323 role = P2PS_SETUP_NONE;
5324 }
5325 }
5326 p2ps_prov->role = role;
5327
5328 return p2ps_prov;
5329
5330invalid_args:
5331 os_free(p2ps_prov);
5332 return NULL;
5333}
5334
5335
5336static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
5337{
5338 u8 addr[ETH_ALEN];
5339 struct p2ps_provision *p2ps_prov;
5340 char *pos;
5341
5342 /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
5343
5344 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
5345
5346 if (hwaddr_aton(cmd, addr))
5347 return -1;
5348
5349 pos = cmd + 17;
5350 if (*pos != ' ')
5351 return -1;
5352
5353 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
5354 if (!p2ps_prov)
5355 return -1;
5356
5357 if (p2ps_prov->status < 0) {
5358 os_free(p2ps_prov);
5359 return -1;
5360 }
5361
5362 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
5363 p2ps_prov);
5364}
5365
5366
5367static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
5368{
5369 u8 addr[ETH_ALEN];
5370 struct p2ps_provision *p2ps_prov;
5371 char *pos;
5372
5373 /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
5374 * session=<ses_id> mac=<ses_mac> [info=<infodata>]
5375 */
5376
5377 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
5378 if (hwaddr_aton(cmd, addr))
5379 return -1;
5380
5381 pos = cmd + 17;
5382 if (*pos != ' ')
5383 return -1;
5384
5385 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
5386 if (!p2ps_prov)
5387 return -1;
5388
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005389 p2ps_prov->pd_seeker = 1;
5390
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005391 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
5392 p2ps_prov);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005393}
5394
5395
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005396static int parse_freq(int chwidth, int freq2)
5397{
5398 if (freq2 < 0)
5399 return -1;
5400 if (freq2)
5401 return VHT_CHANWIDTH_80P80MHZ;
5402
5403 switch (chwidth) {
5404 case 0:
5405 case 20:
5406 case 40:
5407 return VHT_CHANWIDTH_USE_HT;
5408 case 80:
5409 return VHT_CHANWIDTH_80MHZ;
5410 case 160:
5411 return VHT_CHANWIDTH_160MHZ;
5412 default:
5413 wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
5414 chwidth);
5415 return -1;
5416 }
5417}
5418
5419
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005420static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
5421 char *buf, size_t buflen)
5422{
5423 u8 addr[ETH_ALEN];
5424 char *pos, *pos2;
5425 char *pin = NULL;
5426 enum p2p_wps_method wps_method;
5427 int new_pin;
5428 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005429 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005430 int join;
5431 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005432 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005433 int go_intent = -1;
5434 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005435 int pd;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005436 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005437 u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
5438 size_t group_ssid_len = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005439
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005440 if (!wpa_s->global->p2p_init_wpa_s)
5441 return -1;
5442 if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
5443 wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
5444 wpa_s->global->p2p_init_wpa_s->ifname);
5445 wpa_s = wpa_s->global->p2p_init_wpa_s;
5446 }
5447
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005448 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
Dmitry Shmidt04949592012-07-19 12:16:46 -07005449 * [persistent|persistent=<network id>]
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005450 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005451 * [ht40] [vht] [auto] [ssid=<hexdump>] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005452
5453 if (hwaddr_aton(cmd, addr))
5454 return -1;
5455
5456 pos = cmd + 17;
5457 if (*pos != ' ')
5458 return -1;
5459 pos++;
5460
5461 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005462 pos2 = os_strstr(pos, " persistent=");
5463 if (pos2) {
5464 struct wpa_ssid *ssid;
5465 persistent_id = atoi(pos2 + 12);
5466 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
5467 if (ssid == NULL || ssid->disabled != 2 ||
5468 ssid->mode != WPAS_MODE_P2P_GO) {
5469 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
5470 "SSID id=%d for persistent P2P group (GO)",
5471 persistent_id);
5472 return -1;
5473 }
5474 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005475 join = os_strstr(pos, " join") != NULL;
5476 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005477 automatic = os_strstr(pos, " auto") != NULL;
5478 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005479 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5480 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5481 vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005482
5483 pos2 = os_strstr(pos, " go_intent=");
5484 if (pos2) {
5485 pos2 += 11;
5486 go_intent = atoi(pos2);
5487 if (go_intent < 0 || go_intent > 15)
5488 return -1;
5489 }
5490
5491 pos2 = os_strstr(pos, " freq=");
5492 if (pos2) {
5493 pos2 += 6;
5494 freq = atoi(pos2);
5495 if (freq <= 0)
5496 return -1;
5497 }
5498
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005499 pos2 = os_strstr(pos, " freq2=");
5500 if (pos2)
5501 freq2 = atoi(pos2 + 7);
5502
5503 pos2 = os_strstr(pos, " max_oper_chwidth=");
5504 if (pos2)
5505 chwidth = atoi(pos2 + 18);
5506
5507 max_oper_chwidth = parse_freq(chwidth, freq2);
5508 if (max_oper_chwidth < 0)
5509 return -1;
5510
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005511 pos2 = os_strstr(pos, " ssid=");
5512 if (pos2) {
5513 char *end;
5514
5515 pos2 += 6;
5516 end = os_strchr(pos2, ' ');
5517 if (!end)
5518 group_ssid_len = os_strlen(pos2) / 2;
5519 else
5520 group_ssid_len = (end - pos2) / 2;
5521 if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
5522 hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
5523 return -1;
5524 group_ssid = _group_ssid;
5525 }
5526
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005527 if (os_strncmp(pos, "pin", 3) == 0) {
5528 /* Request random PIN (to be displayed) and enable the PIN */
5529 wps_method = WPS_PIN_DISPLAY;
5530 } else if (os_strncmp(pos, "pbc", 3) == 0) {
5531 wps_method = WPS_PBC;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005532 } else if (os_strstr(pos, "p2ps") != NULL) {
5533 wps_method = WPS_P2PS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005534 } else {
5535 pin = pos;
5536 pos = os_strchr(pin, ' ');
5537 wps_method = WPS_PIN_KEYPAD;
5538 if (pos) {
5539 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005540 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005541 wps_method = WPS_PIN_DISPLAY;
5542 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07005543 if (!wps_pin_str_valid(pin)) {
5544 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
5545 return 17;
5546 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005547 }
5548
5549 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07005550 persistent_group, automatic, join,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005551 auth, go_intent, freq, freq2, persistent_id,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005552 pd, ht40, vht, max_oper_chwidth,
5553 group_ssid, group_ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005554 if (new_pin == -2) {
5555 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
5556 return 25;
5557 }
5558 if (new_pin == -3) {
5559 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
5560 return 25;
5561 }
5562 if (new_pin < 0)
5563 return -1;
5564 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
5565 ret = os_snprintf(buf, buflen, "%08d", new_pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005566 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005567 return -1;
5568 return ret;
5569 }
5570
5571 os_memcpy(buf, "OK\n", 3);
5572 return 3;
5573}
5574
5575
5576static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
5577{
5578 unsigned int timeout = atoi(cmd);
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07005579 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
5580 wpa_dbg(wpa_s, MSG_INFO,
5581 "Reject P2P_LISTEN since interface is disabled");
5582 return -1;
5583 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005584 return wpas_p2p_listen(wpa_s, timeout);
5585}
5586
5587
5588static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
5589{
5590 u8 addr[ETH_ALEN];
5591 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005592 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005593
Dmitry Shmidt04949592012-07-19 12:16:46 -07005594 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005595
5596 if (hwaddr_aton(cmd, addr))
5597 return -1;
5598
5599 pos = cmd + 17;
5600 if (*pos != ' ')
5601 return -1;
5602 pos++;
5603
Dmitry Shmidt04949592012-07-19 12:16:46 -07005604 if (os_strstr(pos, " join") != NULL)
5605 use = WPAS_P2P_PD_FOR_JOIN;
5606 else if (os_strstr(pos, " auto") != NULL)
5607 use = WPAS_P2P_PD_AUTO;
5608
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005609 return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005610}
5611
5612
5613static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
5614 size_t buflen)
5615{
5616 struct wpa_ssid *ssid = wpa_s->current_ssid;
5617
5618 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
5619 ssid->passphrase == NULL)
5620 return -1;
5621
5622 os_strlcpy(buf, ssid->passphrase, buflen);
5623 return os_strlen(buf);
5624}
5625
5626
5627static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
5628 char *buf, size_t buflen)
5629{
5630 u64 ref;
5631 int res;
5632 u8 dst_buf[ETH_ALEN], *dst;
5633 struct wpabuf *tlvs;
5634 char *pos;
5635 size_t len;
5636
5637 if (hwaddr_aton(cmd, dst_buf))
5638 return -1;
5639 dst = dst_buf;
5640 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
5641 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
5642 dst = NULL;
5643 pos = cmd + 17;
5644 if (*pos != ' ')
5645 return -1;
5646 pos++;
5647
5648 if (os_strncmp(pos, "upnp ", 5) == 0) {
5649 u8 version;
5650 pos += 5;
5651 if (hexstr2bin(pos, &version, 1) < 0)
5652 return -1;
5653 pos += 2;
5654 if (*pos != ' ')
5655 return -1;
5656 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005657 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005658#ifdef CONFIG_WIFI_DISPLAY
5659 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
5660 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
5661#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005662 } else if (os_strncmp(pos, "asp ", 4) == 0) {
5663 char *svc_str;
5664 char *svc_info = NULL;
5665 u32 id;
5666
5667 pos += 4;
5668 if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
5669 return -1;
5670
5671 pos = os_strchr(pos, ' ');
5672 if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
5673 return -1;
5674
5675 svc_str = pos + 1;
5676
5677 pos = os_strchr(svc_str, ' ');
5678
5679 if (pos)
5680 *pos++ = '\0';
5681
5682 /* All remaining data is the svc_info string */
5683 if (pos && pos[0] && pos[0] != ' ') {
5684 len = os_strlen(pos);
5685
5686 /* Unescape in place */
5687 len = utf8_unescape(pos, len, pos, len);
5688 if (len > 0xff)
5689 return -1;
5690
5691 svc_info = pos;
5692 }
5693
5694 ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
5695 svc_str, svc_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005696 } else {
5697 len = os_strlen(pos);
5698 if (len & 1)
5699 return -1;
5700 len /= 2;
5701 tlvs = wpabuf_alloc(len);
5702 if (tlvs == NULL)
5703 return -1;
5704 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
5705 wpabuf_free(tlvs);
5706 return -1;
5707 }
5708
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005709 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005710 wpabuf_free(tlvs);
5711 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005712 if (ref == 0)
5713 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005714 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005715 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005716 return -1;
5717 return res;
5718}
5719
5720
5721static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
5722 char *cmd)
5723{
5724 long long unsigned val;
5725 u64 req;
5726 if (sscanf(cmd, "%llx", &val) != 1)
5727 return -1;
5728 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005729 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005730}
5731
5732
5733static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
5734{
5735 int freq;
5736 u8 dst[ETH_ALEN];
5737 u8 dialog_token;
5738 struct wpabuf *resp_tlvs;
5739 char *pos, *pos2;
5740 size_t len;
5741
5742 pos = os_strchr(cmd, ' ');
5743 if (pos == NULL)
5744 return -1;
5745 *pos++ = '\0';
5746 freq = atoi(cmd);
5747 if (freq == 0)
5748 return -1;
5749
5750 if (hwaddr_aton(pos, dst))
5751 return -1;
5752 pos += 17;
5753 if (*pos != ' ')
5754 return -1;
5755 pos++;
5756
5757 pos2 = os_strchr(pos, ' ');
5758 if (pos2 == NULL)
5759 return -1;
5760 *pos2++ = '\0';
5761 dialog_token = atoi(pos);
5762
5763 len = os_strlen(pos2);
5764 if (len & 1)
5765 return -1;
5766 len /= 2;
5767 resp_tlvs = wpabuf_alloc(len);
5768 if (resp_tlvs == NULL)
5769 return -1;
5770 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
5771 wpabuf_free(resp_tlvs);
5772 return -1;
5773 }
5774
5775 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
5776 wpabuf_free(resp_tlvs);
5777 return 0;
5778}
5779
5780
5781static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
5782 char *cmd)
5783{
Dmitry Shmidt04949592012-07-19 12:16:46 -07005784 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
5785 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005786 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
5787 return 0;
5788}
5789
5790
5791static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
5792 char *cmd)
5793{
5794 char *pos;
5795 size_t len;
5796 struct wpabuf *query, *resp;
5797
5798 pos = os_strchr(cmd, ' ');
5799 if (pos == NULL)
5800 return -1;
5801 *pos++ = '\0';
5802
5803 len = os_strlen(cmd);
5804 if (len & 1)
5805 return -1;
5806 len /= 2;
5807 query = wpabuf_alloc(len);
5808 if (query == NULL)
5809 return -1;
5810 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5811 wpabuf_free(query);
5812 return -1;
5813 }
5814
5815 len = os_strlen(pos);
5816 if (len & 1) {
5817 wpabuf_free(query);
5818 return -1;
5819 }
5820 len /= 2;
5821 resp = wpabuf_alloc(len);
5822 if (resp == NULL) {
5823 wpabuf_free(query);
5824 return -1;
5825 }
5826 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
5827 wpabuf_free(query);
5828 wpabuf_free(resp);
5829 return -1;
5830 }
5831
5832 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
5833 wpabuf_free(query);
5834 wpabuf_free(resp);
5835 return -1;
5836 }
5837 return 0;
5838}
5839
5840
5841static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5842{
5843 char *pos;
5844 u8 version;
5845
5846 pos = os_strchr(cmd, ' ');
5847 if (pos == NULL)
5848 return -1;
5849 *pos++ = '\0';
5850
5851 if (hexstr2bin(cmd, &version, 1) < 0)
5852 return -1;
5853
5854 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
5855}
5856
5857
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005858static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
5859 u8 replace, char *cmd)
5860{
5861 char *pos;
5862 char *adv_str;
5863 u32 auto_accept, adv_id, svc_state, config_methods;
5864 char *svc_info = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005865 char *cpt_prio_str;
5866 u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005867
5868 pos = os_strchr(cmd, ' ');
5869 if (pos == NULL)
5870 return -1;
5871 *pos++ = '\0';
5872
5873 /* Auto-Accept value is mandatory, and must be one of the
5874 * single values (0, 1, 2, 4) */
5875 auto_accept = atoi(cmd);
5876 switch (auto_accept) {
5877 case P2PS_SETUP_NONE: /* No auto-accept */
5878 case P2PS_SETUP_NEW:
5879 case P2PS_SETUP_CLIENT:
5880 case P2PS_SETUP_GROUP_OWNER:
5881 break;
5882 default:
5883 return -1;
5884 }
5885
5886 /* Advertisement ID is mandatory */
5887 cmd = pos;
5888 pos = os_strchr(cmd, ' ');
5889 if (pos == NULL)
5890 return -1;
5891 *pos++ = '\0';
5892
5893 /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
5894 if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
5895 return -1;
5896
5897 /* Only allow replacements if exist, and adds if not */
5898 if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
5899 if (!replace)
5900 return -1;
5901 } else {
5902 if (replace)
5903 return -1;
5904 }
5905
5906 /* svc_state between 0 - 0xff is mandatory */
5907 if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
5908 return -1;
5909
5910 pos = os_strchr(pos, ' ');
5911 if (pos == NULL)
5912 return -1;
5913
5914 /* config_methods is mandatory */
5915 pos++;
5916 if (sscanf(pos, "%x", &config_methods) != 1)
5917 return -1;
5918
5919 if (!(config_methods &
5920 (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
5921 return -1;
5922
5923 pos = os_strchr(pos, ' ');
5924 if (pos == NULL)
5925 return -1;
5926
5927 pos++;
5928 adv_str = pos;
5929
5930 /* Advertisement string is mandatory */
5931 if (!pos[0] || pos[0] == ' ')
5932 return -1;
5933
5934 /* Terminate svc string */
5935 pos = os_strchr(pos, ' ');
5936 if (pos != NULL)
5937 *pos++ = '\0';
5938
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005939 cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL;
5940 if (cpt_prio_str) {
5941 pos = os_strchr(pos, ' ');
5942 if (pos != NULL)
5943 *pos++ = '\0';
5944
5945 if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio))
5946 return -1;
5947 } else {
5948 cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5949 cpt_prio[1] = 0;
5950 }
5951
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005952 /* Service and Response Information are optional */
5953 if (pos && pos[0]) {
5954 size_t len;
5955
5956 /* Note the bare ' included, which cannot exist legally
5957 * in unescaped string. */
5958 svc_info = os_strstr(pos, "svc_info='");
5959
5960 if (svc_info) {
5961 svc_info += 9;
5962 len = os_strlen(svc_info);
5963 utf8_unescape(svc_info, len, svc_info, len);
5964 }
5965 }
5966
5967 return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
5968 (u8) svc_state, (u16) config_methods,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005969 svc_info, cpt_prio);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005970}
5971
5972
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005973static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
5974{
5975 char *pos;
5976
5977 pos = os_strchr(cmd, ' ');
5978 if (pos == NULL)
5979 return -1;
5980 *pos++ = '\0';
5981
5982 if (os_strcmp(cmd, "bonjour") == 0)
5983 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
5984 if (os_strcmp(cmd, "upnp") == 0)
5985 return p2p_ctrl_service_add_upnp(wpa_s, pos);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005986 if (os_strcmp(cmd, "asp") == 0)
5987 return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005988 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5989 return -1;
5990}
5991
5992
5993static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
5994 char *cmd)
5995{
5996 size_t len;
5997 struct wpabuf *query;
5998 int ret;
5999
6000 len = os_strlen(cmd);
6001 if (len & 1)
6002 return -1;
6003 len /= 2;
6004 query = wpabuf_alloc(len);
6005 if (query == NULL)
6006 return -1;
6007 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
6008 wpabuf_free(query);
6009 return -1;
6010 }
6011
6012 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
6013 wpabuf_free(query);
6014 return ret;
6015}
6016
6017
6018static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
6019{
6020 char *pos;
6021 u8 version;
6022
6023 pos = os_strchr(cmd, ' ');
6024 if (pos == NULL)
6025 return -1;
6026 *pos++ = '\0';
6027
6028 if (hexstr2bin(cmd, &version, 1) < 0)
6029 return -1;
6030
6031 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
6032}
6033
6034
Dmitry Shmidt216983b2015-02-06 10:50:36 -08006035static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
6036{
6037 u32 adv_id;
6038
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07006039 if (os_strcmp(cmd, "all") == 0) {
6040 wpas_p2p_service_flush_asp(wpa_s);
6041 return 0;
6042 }
6043
Dmitry Shmidt216983b2015-02-06 10:50:36 -08006044 if (sscanf(cmd, "%x", &adv_id) != 1)
6045 return -1;
6046
6047 return wpas_p2p_service_del_asp(wpa_s, adv_id);
6048}
6049
6050
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006051static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
6052{
6053 char *pos;
6054
6055 pos = os_strchr(cmd, ' ');
6056 if (pos == NULL)
6057 return -1;
6058 *pos++ = '\0';
6059
6060 if (os_strcmp(cmd, "bonjour") == 0)
6061 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
6062 if (os_strcmp(cmd, "upnp") == 0)
6063 return p2p_ctrl_service_del_upnp(wpa_s, pos);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08006064 if (os_strcmp(cmd, "asp") == 0)
6065 return p2p_ctrl_service_del_asp(wpa_s, pos);
6066 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
6067 return -1;
6068}
6069
6070
6071static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
6072{
6073 char *pos;
6074
6075 pos = os_strchr(cmd, ' ');
6076 if (pos == NULL)
6077 return -1;
6078 *pos++ = '\0';
6079
6080 if (os_strcmp(cmd, "asp") == 0)
6081 return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
6082
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006083 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
6084 return -1;
6085}
6086
6087
6088static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
6089{
6090 u8 addr[ETH_ALEN];
6091
6092 /* <addr> */
6093
6094 if (hwaddr_aton(cmd, addr))
6095 return -1;
6096
6097 return wpas_p2p_reject(wpa_s, addr);
6098}
6099
6100
6101static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
6102{
6103 char *pos;
6104 int id;
6105 struct wpa_ssid *ssid;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006106 u8 *_peer = NULL, peer[ETH_ALEN];
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08006107 int freq = 0, pref_freq = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006108 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006109
6110 id = atoi(cmd);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006111 pos = os_strstr(cmd, " peer=");
6112 if (pos) {
6113 pos += 6;
6114 if (hwaddr_aton(pos, peer))
6115 return -1;
6116 _peer = peer;
6117 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006118 ssid = wpa_config_get_network(wpa_s->conf, id);
6119 if (ssid == NULL || ssid->disabled != 2) {
6120 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
6121 "for persistent P2P group",
6122 id);
6123 return -1;
6124 }
6125
Jouni Malinen31be0a42012-08-31 21:20:51 +03006126 pos = os_strstr(cmd, " freq=");
6127 if (pos) {
6128 pos += 6;
6129 freq = atoi(pos);
6130 if (freq <= 0)
6131 return -1;
6132 }
6133
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08006134 pos = os_strstr(cmd, " pref=");
6135 if (pos) {
6136 pos += 6;
6137 pref_freq = atoi(pos);
6138 if (pref_freq <= 0)
6139 return -1;
6140 }
6141
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07006142 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
6143 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
6144 vht;
Jouni Malinen31be0a42012-08-31 21:20:51 +03006145
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006146 pos = os_strstr(cmd, "freq2=");
6147 if (pos)
6148 freq2 = atoi(pos + 6);
6149
6150 pos = os_strstr(cmd, " max_oper_chwidth=");
6151 if (pos)
6152 chwidth = atoi(pos + 18);
6153
6154 max_oper_chwidth = parse_freq(chwidth, freq2);
6155 if (max_oper_chwidth < 0)
6156 return -1;
6157
6158 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
6159 max_oper_chwidth, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006160}
6161
6162
6163static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
6164{
6165 char *pos;
6166 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
6167
6168 pos = os_strstr(cmd, " peer=");
6169 if (!pos)
6170 return -1;
6171
6172 *pos = '\0';
6173 pos += 6;
6174 if (hwaddr_aton(pos, peer)) {
6175 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
6176 return -1;
6177 }
6178
6179 pos = os_strstr(pos, " go_dev_addr=");
6180 if (pos) {
6181 pos += 13;
6182 if (hwaddr_aton(pos, go_dev_addr)) {
6183 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
6184 pos);
6185 return -1;
6186 }
6187 go_dev = go_dev_addr;
6188 }
6189
6190 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
6191}
6192
6193
6194static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
6195{
6196 if (os_strncmp(cmd, "persistent=", 11) == 0)
6197 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
6198 if (os_strncmp(cmd, "group=", 6) == 0)
6199 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
6200
6201 return -1;
6202}
6203
6204
6205static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006206 int id, int freq, int vht_center_freq2,
6207 int ht40, int vht, int vht_chwidth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006208{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006209 struct wpa_ssid *ssid;
6210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006211 ssid = wpa_config_get_network(wpa_s->conf, id);
6212 if (ssid == NULL || ssid->disabled != 2) {
6213 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
6214 "for persistent P2P group",
6215 id);
6216 return -1;
6217 }
6218
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006219 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
6220 vht_center_freq2, 0, ht40, vht,
6221 vht_chwidth, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006222}
6223
6224
6225static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
6226{
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07006227 int freq = 0, persistent = 0, group_id = -1;
6228 int vht = wpa_s->conf->p2p_go_vht;
6229 int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006230 int max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07006231 char *token, *context = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006232
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07006233 while ((token = str_token(cmd, " ", &context))) {
6234 if (sscanf(token, "freq=%d", &freq) == 1 ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006235 sscanf(token, "freq2=%d", &freq2) == 1 ||
6236 sscanf(token, "persistent=%d", &group_id) == 1 ||
6237 sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07006238 continue;
6239 } else if (os_strcmp(token, "ht40") == 0) {
6240 ht40 = 1;
6241 } else if (os_strcmp(token, "vht") == 0) {
6242 vht = 1;
6243 ht40 = 1;
6244 } else if (os_strcmp(token, "persistent") == 0) {
6245 persistent = 1;
6246 } else {
6247 wpa_printf(MSG_DEBUG,
6248 "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
6249 token);
6250 return -1;
6251 }
6252 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006253
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006254 max_oper_chwidth = parse_freq(chwidth, freq2);
6255 if (max_oper_chwidth < 0)
6256 return -1;
6257
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07006258 if (group_id >= 0)
6259 return p2p_ctrl_group_add_persistent(wpa_s, group_id,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006260 freq, freq2, ht40, vht,
6261 max_oper_chwidth);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006262
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08006263 return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
6264 max_oper_chwidth);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006265}
6266
6267
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006268static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
6269 char *buf, size_t buflen)
6270{
6271 u8 dev_addr[ETH_ALEN];
6272 struct wpa_ssid *ssid;
6273 int res;
6274 const u8 *iaddr;
6275
6276 ssid = wpa_s->current_ssid;
6277 if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
6278 hwaddr_aton(cmd, dev_addr))
6279 return -1;
6280
6281 iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
6282 if (!iaddr)
6283 return -1;
6284 res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
6285 if (os_snprintf_error(buflen, res))
6286 return -1;
6287 return res;
6288}
6289
6290
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006291static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global,
6292 const u8 *p2p_dev_addr)
6293{
6294 struct wpa_supplicant *wpa_s;
6295
6296 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
6297 if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr))
6298 return 1;
6299 }
6300
6301 return 0;
6302}
6303
6304
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006305static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
6306 char *buf, size_t buflen)
6307{
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006308 u8 addr[ETH_ALEN], *addr_ptr, group_capab;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006309 int next, res;
6310 const struct p2p_peer_info *info;
6311 char *pos, *end;
6312 char devtype[WPS_DEV_TYPE_BUFSIZE];
6313 struct wpa_ssid *ssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006314 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006315
6316 if (!wpa_s->global->p2p)
6317 return -1;
6318
6319 if (os_strcmp(cmd, "FIRST") == 0) {
6320 addr_ptr = NULL;
6321 next = 0;
6322 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
6323 if (hwaddr_aton(cmd + 5, addr) < 0)
6324 return -1;
6325 addr_ptr = addr;
6326 next = 1;
6327 } else {
6328 if (hwaddr_aton(cmd, addr) < 0)
6329 return -1;
6330 addr_ptr = addr;
6331 next = 0;
6332 }
6333
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006334 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
6335 if (info == NULL)
6336 return -1;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006337 group_capab = info->group_capab;
6338
6339 if (group_capab &&
6340 !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) {
6341 wpa_printf(MSG_DEBUG,
6342 "P2P: Could not find any BSS with p2p_dev_addr "
6343 MACSTR ", hence override group_capab from 0x%x to 0",
6344 MAC2STR(info->p2p_device_addr), group_capab);
6345 group_capab = 0;
6346 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006347
6348 pos = buf;
6349 end = buf + buflen;
6350
6351 res = os_snprintf(pos, end - pos, MACSTR "\n"
6352 "pri_dev_type=%s\n"
6353 "device_name=%s\n"
6354 "manufacturer=%s\n"
6355 "model_name=%s\n"
6356 "model_number=%s\n"
6357 "serial_number=%s\n"
6358 "config_methods=0x%x\n"
6359 "dev_capab=0x%x\n"
6360 "group_capab=0x%x\n"
6361 "level=%d\n",
6362 MAC2STR(info->p2p_device_addr),
6363 wps_dev_type_bin2str(info->pri_dev_type,
6364 devtype, sizeof(devtype)),
6365 info->device_name,
6366 info->manufacturer,
6367 info->model_name,
6368 info->model_number,
6369 info->serial_number,
6370 info->config_methods,
6371 info->dev_capab,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006372 group_capab,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006373 info->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006374 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006375 return pos - buf;
6376 pos += res;
6377
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006378 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
6379 {
6380 const u8 *t;
6381 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
6382 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
6383 wps_dev_type_bin2str(t, devtype,
6384 sizeof(devtype)));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006385 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006386 return pos - buf;
6387 pos += res;
6388 }
6389
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006390 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006391 if (ssid) {
6392 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006393 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006394 return pos - buf;
6395 pos += res;
6396 }
6397
6398 res = p2p_get_peer_info_txt(info, pos, end - pos);
6399 if (res < 0)
6400 return pos - buf;
6401 pos += res;
6402
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07006403 if (info->vendor_elems) {
6404 res = os_snprintf(pos, end - pos, "vendor_elems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006405 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07006406 return pos - buf;
6407 pos += res;
6408
6409 pos += wpa_snprintf_hex(pos, end - pos,
6410 wpabuf_head(info->vendor_elems),
6411 wpabuf_len(info->vendor_elems));
6412
6413 res = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006414 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07006415 return pos - buf;
6416 pos += res;
6417 }
6418
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006419 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006420}
6421
6422
Dmitry Shmidt04949592012-07-19 12:16:46 -07006423static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
6424 const char *param)
6425{
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006426 unsigned int i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006427
6428 if (wpa_s->global->p2p == NULL)
6429 return -1;
6430
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006431 if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
6432 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006433
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006434 for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
6435 struct wpa_freq_range *freq;
6436 freq = &wpa_s->global->p2p_disallow_freq.range[i];
Dmitry Shmidt04949592012-07-19 12:16:46 -07006437 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006438 freq->min, freq->max);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006439 }
6440
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006441 wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006442 return 0;
6443}
6444
6445
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006446static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
6447{
6448 char *param;
6449
6450 if (wpa_s->global->p2p == NULL)
6451 return -1;
6452
6453 param = os_strchr(cmd, ' ');
6454 if (param == NULL)
6455 return -1;
6456 *param++ = '\0';
6457
6458 if (os_strcmp(cmd, "discoverability") == 0) {
6459 p2p_set_client_discoverability(wpa_s->global->p2p,
6460 atoi(param));
6461 return 0;
6462 }
6463
6464 if (os_strcmp(cmd, "managed") == 0) {
6465 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
6466 return 0;
6467 }
6468
6469 if (os_strcmp(cmd, "listen_channel") == 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006470 char *pos;
6471 u8 channel, op_class;
6472
6473 channel = atoi(param);
6474 pos = os_strchr(param, ' ');
6475 op_class = pos ? atoi(pos) : 81;
6476
6477 return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
6478 channel, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006479 }
6480
6481 if (os_strcmp(cmd, "ssid_postfix") == 0) {
6482 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
6483 os_strlen(param));
6484 }
6485
6486 if (os_strcmp(cmd, "noa") == 0) {
6487 char *pos;
6488 int count, start, duration;
6489 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
6490 count = atoi(param);
6491 pos = os_strchr(param, ',');
6492 if (pos == NULL)
6493 return -1;
6494 pos++;
6495 start = atoi(pos);
6496 pos = os_strchr(pos, ',');
6497 if (pos == NULL)
6498 return -1;
6499 pos++;
6500 duration = atoi(pos);
6501 if (count < 0 || count > 255 || start < 0 || duration < 0)
6502 return -1;
6503 if (count == 0 && duration > 0)
6504 return -1;
6505 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
6506 "start=%d duration=%d", count, start, duration);
6507 return wpas_p2p_set_noa(wpa_s, count, start, duration);
6508 }
6509
6510 if (os_strcmp(cmd, "ps") == 0)
6511 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
6512
6513 if (os_strcmp(cmd, "oppps") == 0)
6514 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
6515
6516 if (os_strcmp(cmd, "ctwindow") == 0)
6517 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
6518
6519 if (os_strcmp(cmd, "disabled") == 0) {
6520 wpa_s->global->p2p_disabled = atoi(param);
6521 wpa_printf(MSG_DEBUG, "P2P functionality %s",
6522 wpa_s->global->p2p_disabled ?
6523 "disabled" : "enabled");
6524 if (wpa_s->global->p2p_disabled) {
6525 wpas_p2p_stop_find(wpa_s);
6526 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6527 p2p_flush(wpa_s->global->p2p);
6528 }
6529 return 0;
6530 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006531
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006532 if (os_strcmp(cmd, "conc_pref") == 0) {
6533 if (os_strcmp(param, "sta") == 0)
6534 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
6535 else if (os_strcmp(param, "p2p") == 0)
6536 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006537 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006538 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006539 return -1;
6540 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006541 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07006542 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006543 return 0;
6544 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006545
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006546 if (os_strcmp(cmd, "force_long_sd") == 0) {
6547 wpa_s->force_long_sd = atoi(param);
6548 return 0;
6549 }
6550
6551 if (os_strcmp(cmd, "peer_filter") == 0) {
6552 u8 addr[ETH_ALEN];
6553 if (hwaddr_aton(param, addr))
6554 return -1;
6555 p2p_set_peer_filter(wpa_s->global->p2p, addr);
6556 return 0;
6557 }
6558
6559 if (os_strcmp(cmd, "cross_connect") == 0)
6560 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
6561
6562 if (os_strcmp(cmd, "go_apsd") == 0) {
6563 if (os_strcmp(param, "disable") == 0)
6564 wpa_s->set_ap_uapsd = 0;
6565 else {
6566 wpa_s->set_ap_uapsd = 1;
6567 wpa_s->ap_uapsd = atoi(param);
6568 }
6569 return 0;
6570 }
6571
6572 if (os_strcmp(cmd, "client_apsd") == 0) {
6573 if (os_strcmp(param, "disable") == 0)
6574 wpa_s->set_sta_uapsd = 0;
6575 else {
6576 int be, bk, vi, vo;
6577 char *pos;
6578 /* format: BE,BK,VI,VO;max SP Length */
6579 be = atoi(param);
6580 pos = os_strchr(param, ',');
6581 if (pos == NULL)
6582 return -1;
6583 pos++;
6584 bk = atoi(pos);
6585 pos = os_strchr(pos, ',');
6586 if (pos == NULL)
6587 return -1;
6588 pos++;
6589 vi = atoi(pos);
6590 pos = os_strchr(pos, ',');
6591 if (pos == NULL)
6592 return -1;
6593 pos++;
6594 vo = atoi(pos);
6595 /* ignore max SP Length for now */
6596
6597 wpa_s->set_sta_uapsd = 1;
6598 wpa_s->sta_uapsd = 0;
6599 if (be)
6600 wpa_s->sta_uapsd |= BIT(0);
6601 if (bk)
6602 wpa_s->sta_uapsd |= BIT(1);
6603 if (vi)
6604 wpa_s->sta_uapsd |= BIT(2);
6605 if (vo)
6606 wpa_s->sta_uapsd |= BIT(3);
6607 }
6608 return 0;
6609 }
6610
Dmitry Shmidt04949592012-07-19 12:16:46 -07006611 if (os_strcmp(cmd, "disallow_freq") == 0)
6612 return p2p_ctrl_disallow_freq(wpa_s, param);
6613
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006614 if (os_strcmp(cmd, "disc_int") == 0) {
6615 int min_disc_int, max_disc_int, max_disc_tu;
6616 char *pos;
6617
6618 pos = param;
6619
6620 min_disc_int = atoi(pos);
6621 pos = os_strchr(pos, ' ');
6622 if (pos == NULL)
6623 return -1;
6624 *pos++ = '\0';
6625
6626 max_disc_int = atoi(pos);
6627 pos = os_strchr(pos, ' ');
6628 if (pos == NULL)
6629 return -1;
6630 *pos++ = '\0';
6631
6632 max_disc_tu = atoi(pos);
6633
6634 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
6635 max_disc_int, max_disc_tu);
6636 }
6637
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07006638 if (os_strcmp(cmd, "per_sta_psk") == 0) {
6639 wpa_s->global->p2p_per_sta_psk = !!atoi(param);
6640 return 0;
6641 }
6642
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08006643#ifdef CONFIG_WPS_NFC
6644 if (os_strcmp(cmd, "nfc_tag") == 0)
6645 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
6646#endif /* CONFIG_WPS_NFC */
6647
6648 if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
6649 wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
6650 return 0;
6651 }
6652
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006653 if (os_strcmp(cmd, "override_pref_op_chan") == 0) {
6654 int op_class, chan;
6655
6656 op_class = atoi(param);
6657 param = os_strchr(param, ':');
6658 if (!param)
6659 return -1;
6660 param++;
6661 chan = atoi(param);
6662 p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class,
6663 chan);
6664 return 0;
6665 }
6666
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006667 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
6668 cmd);
6669
6670 return -1;
6671}
6672
6673
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006674static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
6675{
6676 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6677 wpa_s->force_long_sd = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006678
6679#ifdef CONFIG_TESTING_OPTIONS
6680 os_free(wpa_s->get_pref_freq_list_override);
6681 wpa_s->get_pref_freq_list_override = NULL;
6682#endif /* CONFIG_TESTING_OPTIONS */
6683
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006684 wpas_p2p_stop_find(wpa_s);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006685 wpa_s->parent->p2ps_method_config_any = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006686 if (wpa_s->global->p2p)
6687 p2p_flush(wpa_s->global->p2p);
6688}
6689
6690
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006691static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
6692{
6693 char *pos, *pos2;
6694 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
6695
6696 if (cmd[0]) {
6697 pos = os_strchr(cmd, ' ');
6698 if (pos == NULL)
6699 return -1;
6700 *pos++ = '\0';
6701 dur1 = atoi(cmd);
6702
6703 pos2 = os_strchr(pos, ' ');
6704 if (pos2)
6705 *pos2++ = '\0';
6706 int1 = atoi(pos);
6707 } else
6708 pos2 = NULL;
6709
6710 if (pos2) {
6711 pos = os_strchr(pos2, ' ');
6712 if (pos == NULL)
6713 return -1;
6714 *pos++ = '\0';
6715 dur2 = atoi(pos2);
6716 int2 = atoi(pos);
6717 }
6718
6719 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
6720}
6721
6722
6723static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
6724{
6725 char *pos;
6726 unsigned int period = 0, interval = 0;
6727
6728 if (cmd[0]) {
6729 pos = os_strchr(cmd, ' ');
6730 if (pos == NULL)
6731 return -1;
6732 *pos++ = '\0';
6733 period = atoi(cmd);
6734 interval = atoi(pos);
6735 }
6736
6737 return wpas_p2p_ext_listen(wpa_s, period, interval);
6738}
6739
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07006740
6741static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
6742{
6743 const char *pos;
6744 u8 peer[ETH_ALEN];
6745 int iface_addr = 0;
6746
6747 pos = cmd;
6748 if (os_strncmp(pos, "iface=", 6) == 0) {
6749 iface_addr = 1;
6750 pos += 6;
6751 }
6752 if (hwaddr_aton(pos, peer))
6753 return -1;
6754
6755 wpas_p2p_remove_client(wpa_s, peer, iface_addr);
6756 return 0;
6757}
6758
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07006759
6760static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
6761{
6762 int freq = 0, period = 0, interval = 0, count = 0;
6763
6764 if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
6765 {
6766 wpa_printf(MSG_DEBUG,
6767 "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
6768 return -1;
6769 }
6770
6771 return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
6772}
6773
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006774#endif /* CONFIG_P2P */
6775
6776
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006777static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
6778{
6779 struct wpa_freq_range_list ranges;
6780 int *freqs = NULL;
6781 struct hostapd_hw_modes *mode;
6782 u16 i;
6783
6784 if (wpa_s->hw.modes == NULL)
6785 return NULL;
6786
6787 os_memset(&ranges, 0, sizeof(ranges));
6788 if (freq_range_list_parse(&ranges, val) < 0)
6789 return NULL;
6790
6791 for (i = 0; i < wpa_s->hw.num_modes; i++) {
6792 int j;
6793
6794 mode = &wpa_s->hw.modes[i];
6795 for (j = 0; j < mode->num_channels; j++) {
6796 unsigned int freq;
6797
6798 if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
6799 continue;
6800
6801 freq = mode->channels[j].freq;
6802 if (!freq_range_list_includes(&ranges, freq))
6803 continue;
6804
6805 int_array_add_unique(&freqs, freq);
6806 }
6807 }
6808
6809 os_free(ranges.range);
6810 return freqs;
6811}
6812
6813
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006814#ifdef CONFIG_INTERWORKING
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006815
6816static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
6817{
6818 int auto_sel = 0;
6819 int *freqs = NULL;
6820
6821 if (param) {
6822 char *pos;
6823
6824 auto_sel = os_strstr(param, "auto") != NULL;
6825
6826 pos = os_strstr(param, "freq=");
6827 if (pos) {
6828 freqs = freq_range_to_channel_list(wpa_s, pos + 5);
6829 if (freqs == NULL)
6830 return -1;
6831 }
6832
6833 }
6834
6835 return interworking_select(wpa_s, auto_sel, freqs);
6836}
6837
6838
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006839static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
6840 int only_add)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006841{
6842 u8 bssid[ETH_ALEN];
6843 struct wpa_bss *bss;
6844
6845 if (hwaddr_aton(dst, bssid)) {
6846 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
6847 return -1;
6848 }
6849
6850 bss = wpa_bss_get_bssid(wpa_s, bssid);
6851 if (bss == NULL) {
6852 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
6853 MAC2STR(bssid));
6854 return -1;
6855 }
6856
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006857 if (bss->ssid_len == 0) {
6858 int found = 0;
6859
6860 wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
6861 " does not have SSID information", MAC2STR(bssid));
6862
6863 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
6864 list) {
6865 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
6866 bss->ssid_len > 0) {
6867 found = 1;
6868 break;
6869 }
6870 }
6871
6872 if (!found)
6873 return -1;
6874 wpa_printf(MSG_DEBUG,
6875 "Found another matching BSS entry with SSID");
6876 }
6877
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006878 return interworking_connect(wpa_s, bss, only_add);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006879}
6880
6881
6882static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
6883{
6884 u8 dst_addr[ETH_ALEN];
6885 int used;
6886 char *pos;
6887#define MAX_ANQP_INFO_ID 100
6888 u16 id[MAX_ANQP_INFO_ID];
6889 size_t num_id = 0;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006890 u32 subtypes = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006891 u32 mbo_subtypes = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006892
6893 used = hwaddr_aton2(dst, dst_addr);
6894 if (used < 0)
6895 return -1;
6896 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006897 if (*pos == ' ')
6898 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006899 while (num_id < MAX_ANQP_INFO_ID) {
Dmitry Shmidt15907092014-03-25 10:42:57 -07006900 if (os_strncmp(pos, "hs20:", 5) == 0) {
6901#ifdef CONFIG_HS20
6902 int num = atoi(pos + 5);
6903 if (num <= 0 || num > 31)
6904 return -1;
6905 subtypes |= BIT(num);
6906#else /* CONFIG_HS20 */
6907 return -1;
6908#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006909 } else if (os_strncmp(pos, "mbo:", 4) == 0) {
6910#ifdef CONFIG_MBO
6911 int num = atoi(pos + 4);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006912
6913 if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006914 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006915 mbo_subtypes |= BIT(num);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006916#else /* CONFIG_MBO */
6917 return -1;
6918#endif /* CONFIG_MBO */
Dmitry Shmidt15907092014-03-25 10:42:57 -07006919 } else {
6920 id[num_id] = atoi(pos);
6921 if (id[num_id])
6922 num_id++;
6923 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006924 pos = os_strchr(pos + 1, ',');
6925 if (pos == NULL)
6926 break;
6927 pos++;
6928 }
6929
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006930 if (num_id == 0 && !subtypes && !mbo_subtypes)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006931 return -1;
6932
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006933 return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006934 mbo_subtypes);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006935}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006936
6937
6938static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
6939{
6940 u8 dst_addr[ETH_ALEN];
6941 struct wpabuf *advproto, *query = NULL;
6942 int used, ret = -1;
6943 char *pos, *end;
6944 size_t len;
6945
6946 used = hwaddr_aton2(cmd, dst_addr);
6947 if (used < 0)
6948 return -1;
6949
6950 pos = cmd + used;
6951 while (*pos == ' ')
6952 pos++;
6953
6954 /* Advertisement Protocol ID */
6955 end = os_strchr(pos, ' ');
6956 if (end)
6957 len = end - pos;
6958 else
6959 len = os_strlen(pos);
6960 if (len & 0x01)
6961 return -1;
6962 len /= 2;
6963 if (len == 0)
6964 return -1;
6965 advproto = wpabuf_alloc(len);
6966 if (advproto == NULL)
6967 return -1;
6968 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
6969 goto fail;
6970
6971 if (end) {
6972 /* Optional Query Request */
6973 pos = end + 1;
6974 while (*pos == ' ')
6975 pos++;
6976
6977 len = os_strlen(pos);
6978 if (len) {
6979 if (len & 0x01)
6980 goto fail;
6981 len /= 2;
6982 if (len == 0)
6983 goto fail;
6984 query = wpabuf_alloc(len);
6985 if (query == NULL)
6986 goto fail;
6987 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
6988 goto fail;
6989 }
6990 }
6991
6992 ret = gas_send_request(wpa_s, dst_addr, advproto, query);
6993
6994fail:
6995 wpabuf_free(advproto);
6996 wpabuf_free(query);
6997
6998 return ret;
6999}
7000
7001
7002static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
7003 size_t buflen)
7004{
7005 u8 addr[ETH_ALEN];
7006 int dialog_token;
7007 int used;
7008 char *pos;
7009 size_t resp_len, start, requested_len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007010 struct wpabuf *resp;
7011 int ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007012
7013 used = hwaddr_aton2(cmd, addr);
7014 if (used < 0)
7015 return -1;
7016
7017 pos = cmd + used;
7018 while (*pos == ' ')
7019 pos++;
7020 dialog_token = atoi(pos);
7021
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007022 if (wpa_s->last_gas_resp &&
7023 os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
7024 dialog_token == wpa_s->last_gas_dialog_token)
7025 resp = wpa_s->last_gas_resp;
7026 else if (wpa_s->prev_gas_resp &&
7027 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
7028 dialog_token == wpa_s->prev_gas_dialog_token)
7029 resp = wpa_s->prev_gas_resp;
7030 else
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007031 return -1;
7032
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007033 resp_len = wpabuf_len(resp);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007034 start = 0;
7035 requested_len = resp_len;
7036
7037 pos = os_strchr(pos, ' ');
7038 if (pos) {
7039 start = atoi(pos);
7040 if (start > resp_len)
7041 return os_snprintf(buf, buflen, "FAIL-Invalid range");
7042 pos = os_strchr(pos, ',');
7043 if (pos == NULL)
7044 return -1;
7045 pos++;
7046 requested_len = atoi(pos);
7047 if (start + requested_len > resp_len)
7048 return os_snprintf(buf, buflen, "FAIL-Invalid range");
7049 }
7050
7051 if (requested_len * 2 + 1 > buflen)
7052 return os_snprintf(buf, buflen, "FAIL-Too long response");
7053
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007054 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
7055 requested_len);
7056
7057 if (start + requested_len == resp_len) {
7058 /*
7059 * Free memory by dropping the response after it has been
7060 * fetched.
7061 */
7062 if (resp == wpa_s->prev_gas_resp) {
7063 wpabuf_free(wpa_s->prev_gas_resp);
7064 wpa_s->prev_gas_resp = NULL;
7065 } else {
7066 wpabuf_free(wpa_s->last_gas_resp);
7067 wpa_s->last_gas_resp = NULL;
7068 }
7069 }
7070
7071 return ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007072}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007073#endif /* CONFIG_INTERWORKING */
7074
7075
Dmitry Shmidt04949592012-07-19 12:16:46 -07007076#ifdef CONFIG_HS20
7077
7078static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
7079{
7080 u8 dst_addr[ETH_ALEN];
7081 int used;
7082 char *pos;
7083 u32 subtypes = 0;
7084
7085 used = hwaddr_aton2(dst, dst_addr);
7086 if (used < 0)
7087 return -1;
7088 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007089 if (*pos == ' ')
7090 pos++;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007091 for (;;) {
7092 int num = atoi(pos);
7093 if (num <= 0 || num > 31)
7094 return -1;
7095 subtypes |= BIT(num);
7096 pos = os_strchr(pos + 1, ',');
7097 if (pos == NULL)
7098 break;
7099 pos++;
7100 }
7101
7102 if (subtypes == 0)
7103 return -1;
7104
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007105 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007106}
7107
7108
7109static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
7110 const u8 *addr, const char *realm)
7111{
7112 u8 *buf;
7113 size_t rlen, len;
7114 int ret;
7115
7116 rlen = os_strlen(realm);
7117 len = 3 + rlen;
7118 buf = os_malloc(len);
7119 if (buf == NULL)
7120 return -1;
7121 buf[0] = 1; /* NAI Home Realm Count */
7122 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
7123 buf[2] = rlen;
7124 os_memcpy(buf + 3, realm, rlen);
7125
7126 ret = hs20_anqp_send_req(wpa_s, addr,
7127 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007128 buf, len, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007129
7130 os_free(buf);
7131
7132 return ret;
7133}
7134
7135
7136static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
7137 char *dst)
7138{
7139 struct wpa_cred *cred = wpa_s->conf->cred;
7140 u8 dst_addr[ETH_ALEN];
7141 int used;
7142 u8 *buf;
7143 size_t len;
7144 int ret;
7145
7146 used = hwaddr_aton2(dst, dst_addr);
7147 if (used < 0)
7148 return -1;
7149
7150 while (dst[used] == ' ')
7151 used++;
7152 if (os_strncmp(dst + used, "realm=", 6) == 0)
7153 return hs20_nai_home_realm_list(wpa_s, dst_addr,
7154 dst + used + 6);
7155
7156 len = os_strlen(dst + used);
7157
7158 if (len == 0 && cred && cred->realm)
7159 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
7160
Dmitry Shmidt623d63a2014-06-13 11:05:14 -07007161 if (len & 1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07007162 return -1;
7163 len /= 2;
7164 buf = os_malloc(len);
7165 if (buf == NULL)
7166 return -1;
7167 if (hexstr2bin(dst + used, buf, len) < 0) {
7168 os_free(buf);
7169 return -1;
7170 }
7171
7172 ret = hs20_anqp_send_req(wpa_s, dst_addr,
7173 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007174 buf, len, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007175 os_free(buf);
7176
7177 return ret;
7178}
7179
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007180
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007181static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
7182 int buflen)
7183{
7184 u8 dst_addr[ETH_ALEN];
7185 int used;
7186 char *ctx = NULL, *icon, *poffset, *psize;
7187
7188 used = hwaddr_aton2(cmd, dst_addr);
7189 if (used < 0)
7190 return -1;
7191 cmd += used;
7192
7193 icon = str_token(cmd, " ", &ctx);
7194 poffset = str_token(cmd, " ", &ctx);
7195 psize = str_token(cmd, " ", &ctx);
7196 if (!icon || !poffset || !psize)
7197 return -1;
7198
7199 wpa_s->fetch_osu_icon_in_progress = 0;
7200 return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
7201 reply, buflen);
7202}
7203
7204
7205static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
7206{
7207 u8 dst_addr[ETH_ALEN];
7208 int used;
7209 char *icon;
7210
7211 if (!cmd[0])
7212 return hs20_del_icon(wpa_s, NULL, NULL);
7213
7214 used = hwaddr_aton2(cmd, dst_addr);
7215 if (used < 0)
7216 return -1;
7217
7218 while (cmd[used] == ' ')
7219 used++;
7220 icon = cmd[used] ? &cmd[used] : NULL;
7221
7222 return hs20_del_icon(wpa_s, dst_addr, icon);
7223}
7224
7225
7226static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007227{
7228 u8 dst_addr[ETH_ALEN];
7229 int used;
7230 char *icon;
7231
7232 used = hwaddr_aton2(cmd, dst_addr);
7233 if (used < 0)
7234 return -1;
7235
7236 while (cmd[used] == ' ')
7237 used++;
7238 icon = &cmd[used];
7239
7240 wpa_s->fetch_osu_icon_in_progress = 0;
7241 return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007242 (u8 *) icon, os_strlen(icon), inmem);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007243}
7244
Dmitry Shmidt04949592012-07-19 12:16:46 -07007245#endif /* CONFIG_HS20 */
7246
7247
Dmitry Shmidt04949592012-07-19 12:16:46 -07007248#ifdef CONFIG_AUTOSCAN
7249
7250static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
7251 char *cmd)
7252{
7253 enum wpa_states state = wpa_s->wpa_state;
7254 char *new_params = NULL;
7255
7256 if (os_strlen(cmd) > 0) {
7257 new_params = os_strdup(cmd);
7258 if (new_params == NULL)
7259 return -1;
7260 }
7261
7262 os_free(wpa_s->conf->autoscan);
7263 wpa_s->conf->autoscan = new_params;
7264
7265 if (wpa_s->conf->autoscan == NULL)
7266 autoscan_deinit(wpa_s);
7267 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
7268 autoscan_init(wpa_s, 1);
7269 else if (state == WPA_SCANNING)
7270 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08007271 else
7272 wpa_printf(MSG_DEBUG, "No autoscan update in state %s",
7273 wpa_supplicant_state_txt(state));
Dmitry Shmidt04949592012-07-19 12:16:46 -07007274
7275 return 0;
7276}
7277
7278#endif /* CONFIG_AUTOSCAN */
7279
7280
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007281#ifdef CONFIG_WNM
7282
7283static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
7284{
7285 int enter;
7286 int intval = 0;
7287 char *pos;
7288 int ret;
7289 struct wpabuf *tfs_req = NULL;
7290
7291 if (os_strncmp(cmd, "enter", 5) == 0)
7292 enter = 1;
7293 else if (os_strncmp(cmd, "exit", 4) == 0)
7294 enter = 0;
7295 else
7296 return -1;
7297
7298 pos = os_strstr(cmd, " interval=");
7299 if (pos)
7300 intval = atoi(pos + 10);
7301
7302 pos = os_strstr(cmd, " tfs_req=");
7303 if (pos) {
7304 char *end;
7305 size_t len;
7306 pos += 9;
7307 end = os_strchr(pos, ' ');
7308 if (end)
7309 len = end - pos;
7310 else
7311 len = os_strlen(pos);
7312 if (len & 1)
7313 return -1;
7314 len /= 2;
7315 tfs_req = wpabuf_alloc(len);
7316 if (tfs_req == NULL)
7317 return -1;
7318 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
7319 wpabuf_free(tfs_req);
7320 return -1;
7321 }
7322 }
7323
7324 ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
7325 WNM_SLEEP_MODE_EXIT, intval,
7326 tfs_req);
7327 wpabuf_free(tfs_req);
7328
7329 return ret;
7330}
7331
Dmitry Shmidt44c95782013-05-17 09:51:35 -07007332
7333static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
7334{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007335 int query_reason, list = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007336 char *btm_candidates = NULL;
Dmitry Shmidt44c95782013-05-17 09:51:35 -07007337
7338 query_reason = atoi(cmd);
7339
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007340 cmd = os_strchr(cmd, ' ');
7341 if (cmd) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007342 if (os_strncmp(cmd, " list", 5) == 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007343 list = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007344 else
7345 btm_candidates = cmd;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007346 }
Dmitry Shmidt44c95782013-05-17 09:51:35 -07007347
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007348 wpa_printf(MSG_DEBUG,
7349 "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
7350 query_reason, list ? " candidate list" : "");
7351
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007352 return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason,
7353 btm_candidates,
7354 list);
Dmitry Shmidt44c95782013-05-17 09:51:35 -07007355}
7356
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007357#endif /* CONFIG_WNM */
7358
7359
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007360static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
7361 size_t buflen)
7362{
7363 struct wpa_signal_info si;
7364 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007365 char *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007366
7367 ret = wpa_drv_signal_poll(wpa_s, &si);
7368 if (ret)
7369 return -1;
7370
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007371 pos = buf;
7372 end = buf + buflen;
7373
7374 ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007375 "NOISE=%d\nFREQUENCY=%u\n",
7376 si.current_signal, si.current_txrate / 1000,
7377 si.current_noise, si.frequency);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007378 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007379 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007380 pos += ret;
7381
7382 if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
7383 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007384 channel_width_to_string(si.chanwidth));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007385 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007386 return -1;
7387 pos += ret;
7388 }
7389
7390 if (si.center_frq1 > 0 && si.center_frq2 > 0) {
7391 ret = os_snprintf(pos, end - pos,
7392 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
7393 si.center_frq1, si.center_frq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007394 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007395 return -1;
7396 pos += ret;
7397 }
7398
7399 if (si.avg_signal) {
7400 ret = os_snprintf(pos, end - pos,
7401 "AVG_RSSI=%d\n", si.avg_signal);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007402 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007403 return -1;
7404 pos += ret;
7405 }
7406
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07007407 if (si.avg_beacon_signal) {
7408 ret = os_snprintf(pos, end - pos,
7409 "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
7410 if (os_snprintf_error(end - pos, ret))
7411 return -1;
7412 pos += ret;
7413 }
7414
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007415 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007416}
7417
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007418
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007419static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
7420 const char *cmd)
7421{
7422 const char *pos;
7423 int threshold = 0;
7424 int hysteresis = 0;
7425
7426 if (wpa_s->bgscan && wpa_s->bgscan_priv) {
7427 wpa_printf(MSG_DEBUG,
7428 "Reject SIGNAL_MONITOR command - bgscan is active");
7429 return -1;
7430 }
7431 pos = os_strstr(cmd, "THRESHOLD=");
7432 if (pos)
7433 threshold = atoi(pos + 10);
7434 pos = os_strstr(cmd, "HYSTERESIS=");
7435 if (pos)
7436 hysteresis = atoi(pos + 11);
7437 return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
7438}
7439
7440
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007441#ifdef CONFIG_TESTING_OPTIONS
7442int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
7443 enum wpa_driver_if_type if_type,
7444 unsigned int *num,
7445 unsigned int *freq_list)
7446{
7447 char *pos = wpa_s->get_pref_freq_list_override;
7448 char *end;
7449 unsigned int count = 0;
7450
7451 /* Override string format:
7452 * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */
7453
7454 while (pos) {
7455 if (atoi(pos) == (int) if_type)
7456 break;
7457 pos = os_strchr(pos, ' ');
7458 if (pos)
7459 pos++;
7460 }
7461 if (!pos)
7462 return -1;
7463 pos = os_strchr(pos, ':');
7464 if (!pos)
7465 return -1;
7466 pos++;
7467 end = os_strchr(pos, ' ');
7468 while (pos && (!end || pos < end) && count < *num) {
7469 freq_list[count++] = atoi(pos);
7470 pos = os_strchr(pos, ',');
7471 if (pos)
7472 pos++;
7473 }
7474
7475 *num = count;
7476 return 0;
7477}
7478#endif /* CONFIG_TESTING_OPTIONS */
7479
7480
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007481static int wpas_ctrl_iface_get_pref_freq_list(
7482 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
7483{
7484 unsigned int freq_list[100], num = 100, i;
7485 int ret;
7486 enum wpa_driver_if_type iface_type;
7487 char *pos, *end;
7488
7489 pos = buf;
7490 end = buf + buflen;
7491
7492 /* buf: "<interface_type>" */
7493 if (os_strcmp(cmd, "STATION") == 0)
7494 iface_type = WPA_IF_STATION;
7495 else if (os_strcmp(cmd, "AP") == 0)
7496 iface_type = WPA_IF_AP_BSS;
7497 else if (os_strcmp(cmd, "P2P_GO") == 0)
7498 iface_type = WPA_IF_P2P_GO;
7499 else if (os_strcmp(cmd, "P2P_CLIENT") == 0)
7500 iface_type = WPA_IF_P2P_CLIENT;
7501 else if (os_strcmp(cmd, "IBSS") == 0)
7502 iface_type = WPA_IF_IBSS;
7503 else if (os_strcmp(cmd, "TDLS") == 0)
7504 iface_type = WPA_IF_TDLS;
7505 else
7506 return -1;
7507
7508 wpa_printf(MSG_DEBUG,
7509 "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
7510 iface_type, buf);
7511
7512 ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
7513 if (ret)
7514 return -1;
7515
7516 for (i = 0; i < num; i++) {
7517 ret = os_snprintf(pos, end - pos, "%s%u",
7518 i > 0 ? "," : "", freq_list[i]);
7519 if (os_snprintf_error(end - pos, ret))
7520 return -1;
7521 pos += ret;
7522 }
7523
7524 return pos - buf;
7525}
7526
7527
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07007528static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
7529 char *buf, size_t buflen)
7530{
7531 int ret, i;
7532 char *pos, *end;
7533
7534 ret = os_snprintf(buf, buflen, "%016llX:\n",
7535 (long long unsigned) wpa_s->drv_flags);
7536 if (os_snprintf_error(buflen, ret))
7537 return -1;
7538
7539 pos = buf + ret;
7540 end = buf + buflen;
7541
7542 for (i = 0; i < 64; i++) {
7543 if (wpa_s->drv_flags & (1LLU << i)) {
7544 ret = os_snprintf(pos, end - pos, "%s\n",
7545 driver_flag_to_string(1LLU << i));
7546 if (os_snprintf_error(end - pos, ret))
7547 return -1;
7548 pos += ret;
7549 }
7550 }
7551
7552 return pos - buf;
7553}
7554
7555
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07007556static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
7557 size_t buflen)
7558{
7559 struct hostap_sta_driver_data sta;
7560 int ret;
7561
7562 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
7563 if (ret)
7564 return -1;
7565
7566 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007567 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007568 if (os_snprintf_error(buflen, ret))
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07007569 return -1;
7570 return ret;
7571}
7572
7573
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007574#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007575static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7576 char *buf, size_t buflen)
7577{
7578 int ret;
7579
7580 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
Dmitry Shmidt9432e122013-09-12 12:39:30 -07007581 if (ret == 0) {
7582 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
7583 struct p2p_data *p2p = wpa_s->global->p2p;
7584 if (p2p) {
7585 char country[3];
7586 country[0] = cmd[8];
7587 country[1] = cmd[9];
7588 country[2] = 0x04;
7589 p2p_set_country(p2p, country);
7590 }
7591 }
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08007592 ret = os_snprintf(buf, buflen, "%s\n", "OK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007593 if (os_snprintf_error(buflen, ret))
7594 ret = -1;
Dmitry Shmidt9432e122013-09-12 12:39:30 -07007595 }
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007596 return ret;
7597}
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08007598#endif /* ANDROID */
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007599
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07007600
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007601static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7602 char *buf, size_t buflen)
7603{
7604 int ret;
7605 char *pos;
7606 u8 *data = NULL;
7607 unsigned int vendor_id, subcmd;
7608 struct wpabuf *reply;
7609 size_t data_len = 0;
7610
7611 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
7612 vendor_id = strtoul(cmd, &pos, 16);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007613 if (!isblank((unsigned char) *pos))
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007614 return -EINVAL;
7615
7616 subcmd = strtoul(pos, &pos, 10);
7617
7618 if (*pos != '\0') {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007619 if (!isblank((unsigned char) *pos++))
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007620 return -EINVAL;
7621 data_len = os_strlen(pos);
7622 }
7623
7624 if (data_len) {
7625 data_len /= 2;
7626 data = os_malloc(data_len);
7627 if (!data)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007628 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007629
7630 if (hexstr2bin(pos, data, data_len)) {
7631 wpa_printf(MSG_DEBUG,
7632 "Vendor command: wrong parameter format");
7633 os_free(data);
7634 return -EINVAL;
7635 }
7636 }
7637
7638 reply = wpabuf_alloc((buflen - 1) / 2);
7639 if (!reply) {
7640 os_free(data);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007641 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007642 }
7643
7644 ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
7645 reply);
7646
7647 if (ret == 0)
7648 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
7649 wpabuf_len(reply));
7650
7651 wpabuf_free(reply);
7652 os_free(data);
7653
7654 return ret;
7655}
7656
7657
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007658static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
7659{
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007660#ifdef CONFIG_P2P
7661 struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
7662 wpa_s->global->p2p_init_wpa_s : wpa_s;
7663#endif /* CONFIG_P2P */
7664
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007665 wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
7666
Dmitry Shmidt29333592017-01-09 12:27:11 -08007667 if (wpas_abort_ongoing_scan(wpa_s) == 0)
7668 wpa_s->ignore_post_flush_scan_res = 1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007669
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007670 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
7671 /*
7672 * Avoid possible auto connect re-connection on getting
7673 * disconnected due to state flush.
7674 */
7675 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
7676 }
7677
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007678#ifdef CONFIG_P2P
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007679 wpas_p2p_group_remove(p2p_wpa_s, "*");
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007680 wpas_p2p_cancel(p2p_wpa_s);
7681 p2p_ctrl_flush(p2p_wpa_s);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007682 wpas_p2p_service_flush(p2p_wpa_s);
7683 p2p_wpa_s->global->p2p_disabled = 0;
7684 p2p_wpa_s->global->p2p_per_sta_psk = 0;
7685 p2p_wpa_s->conf->num_sec_device_types = 0;
7686 p2p_wpa_s->p2p_disable_ip_addr_req = 0;
7687 os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
7688 p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007689 p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08007690 p2p_wpa_s->global->pending_p2ps_group = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007691 p2p_wpa_s->global->pending_p2ps_group_freq = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007692#endif /* CONFIG_P2P */
7693
7694#ifdef CONFIG_WPS_TESTING
7695 wps_version_number = 0x20;
7696 wps_testing_dummy_cred = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08007697 wps_corrupt_pkhash = 0;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007698 wps_force_auth_types_in_use = 0;
7699 wps_force_encr_types_in_use = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007700#endif /* CONFIG_WPS_TESTING */
7701#ifdef CONFIG_WPS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007702 wpa_s->wps_fragment_size = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007703 wpas_wps_cancel(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007704 wps_registrar_flush(wpa_s->wps->registrar);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007705#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07007706 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007707 wpa_s->known_wps_freq = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007708
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007709#ifdef CONFIG_DPP
7710 wpas_dpp_deinit(wpa_s);
7711#endif /* CONFIG_DPP */
7712
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007713#ifdef CONFIG_TDLS
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007714#ifdef CONFIG_TDLS_TESTING
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007715 tdls_testing = 0;
7716#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007717 wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
7718 wpa_tdls_enable(wpa_s->wpa, 1);
7719#endif /* CONFIG_TDLS */
7720
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007721 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
7722 wpa_supplicant_stop_countermeasures(wpa_s, NULL);
7723
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007724 wpa_s->no_keep_alive = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08007725 wpa_s->own_disconnect_req = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007726
7727 os_free(wpa_s->disallow_aps_bssid);
7728 wpa_s->disallow_aps_bssid = NULL;
7729 wpa_s->disallow_aps_bssid_count = 0;
7730 os_free(wpa_s->disallow_aps_ssid);
7731 wpa_s->disallow_aps_ssid = NULL;
7732 wpa_s->disallow_aps_ssid_count = 0;
7733
7734 wpa_s->set_sta_uapsd = 0;
7735 wpa_s->sta_uapsd = 0;
7736
7737 wpa_drv_radio_disable(wpa_s, 0);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007738 wpa_blacklist_clear(wpa_s);
Dmitry Shmidt4b060592013-04-29 16:42:49 -07007739 wpa_s->extra_blacklist_count = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007740 wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
7741 wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
Dmitry Shmidt344abd32014-01-14 13:17:00 -08007742 wpa_config_flush_blobs(wpa_s->conf);
Dmitry Shmidt18463232014-01-24 12:29:41 -08007743 wpa_s->conf->auto_interworking = 0;
7744 wpa_s->conf->okc = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007745
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007746 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
7747 rsn_preauth_deinit(wpa_s->wpa);
7748
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007749 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
7750 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
7751 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
7752 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
7753
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007754 radio_remove_works(wpa_s, NULL, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007755 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007756
7757 wpa_s->next_ssid = NULL;
7758
7759#ifdef CONFIG_INTERWORKING
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007760#ifdef CONFIG_HS20
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007761 hs20_cancel_fetch_osu(wpa_s);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007762 hs20_del_icon(wpa_s, NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007763#endif /* CONFIG_HS20 */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007764#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt818ea482014-03-10 13:15:21 -07007765
7766 wpa_s->ext_mgmt_frame_handling = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007767 wpa_s->ext_eapol_frame_io = 0;
7768#ifdef CONFIG_TESTING_OPTIONS
7769 wpa_s->extra_roc_dur = 0;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007770 wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007771 wpa_s->p2p_go_csa_on_inv = 0;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07007772 wpa_s->ignore_auth_resp = 0;
7773 wpa_s->ignore_assoc_disallow = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007774 wpa_s->testing_resend_assoc = 0;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07007775 wpa_s->reject_btm_req_reason = 0;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08007776 wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007777 os_free(wpa_s->get_pref_freq_list_override);
7778 wpa_s->get_pref_freq_list_override = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007779 wpabuf_free(wpa_s->sae_commit_override);
7780 wpa_s->sae_commit_override = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007781#endif /* CONFIG_TESTING_OPTIONS */
7782
7783 wpa_s->disconnected = 0;
7784 os_free(wpa_s->next_scan_freqs);
7785 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007786 os_free(wpa_s->select_network_scan_freqs);
7787 wpa_s->select_network_scan_freqs = NULL;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007788
7789 wpa_bss_flush(wpa_s);
7790 if (!dl_list_empty(&wpa_s->bss)) {
7791 wpa_printf(MSG_DEBUG,
7792 "BSS table not empty after flush: %u entries, current_bss=%p bssid="
7793 MACSTR " pending_bssid=" MACSTR,
7794 dl_list_len(&wpa_s->bss), wpa_s->current_bss,
7795 MAC2STR(wpa_s->bssid),
7796 MAC2STR(wpa_s->pending_bssid));
7797 }
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07007798
7799 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
Dmitry Shmidtb70d0bb2015-11-16 10:43:06 -08007800 wpa_s->wnmsleep_used = 0;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07007801
7802#ifdef CONFIG_SME
7803 wpa_s->sme.last_unprot_disconnect.sec = 0;
7804#endif /* CONFIG_SME */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007805
7806 wpabuf_free(wpa_s->ric_ies);
7807 wpa_s->ric_ies = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007808}
7809
7810
7811static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
7812 char *buf, size_t buflen)
7813{
7814 struct wpa_radio_work *work;
7815 char *pos, *end;
7816 struct os_reltime now, diff;
7817
7818 pos = buf;
7819 end = buf + buflen;
7820
7821 os_get_reltime(&now);
7822
7823 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7824 {
7825 int ret;
7826
7827 os_reltime_sub(&now, &work->time, &diff);
7828 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
7829 work->type, work->wpa_s->ifname, work->freq,
7830 work->started, diff.sec, diff.usec);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007831 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007832 break;
7833 pos += ret;
7834 }
7835
7836 return pos - buf;
7837}
7838
7839
7840static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
7841{
7842 struct wpa_radio_work *work = eloop_ctx;
7843 struct wpa_external_work *ework = work->ctx;
7844
7845 wpa_dbg(work->wpa_s, MSG_DEBUG,
7846 "Timing out external radio work %u (%s)",
7847 ework->id, work->type);
7848 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007849 work->wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007850 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07007851 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007852}
7853
7854
7855static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
7856{
7857 struct wpa_external_work *ework = work->ctx;
7858
7859 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007860 if (work->started)
7861 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7862 work, NULL);
7863
Dmitry Shmidt849734c2016-05-27 09:59:01 -07007864 /*
7865 * work->type points to a buffer in ework, so need to replace
7866 * that here with a fixed string to avoid use of freed memory
7867 * in debug prints.
7868 */
7869 work->type = "freed-ext-work";
7870 work->ctx = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007871 os_free(ework);
7872 return;
7873 }
7874
7875 wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
7876 ework->id, ework->type);
7877 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007878 work->wpa_s->ext_work_in_progress = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007879 if (!ework->timeout)
7880 ework->timeout = 10;
7881 eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
7882 work, NULL);
7883}
7884
7885
7886static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
7887 char *buf, size_t buflen)
7888{
7889 struct wpa_external_work *ework;
7890 char *pos, *pos2;
7891 size_t type_len;
7892 int ret;
7893 unsigned int freq = 0;
7894
7895 /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
7896
7897 ework = os_zalloc(sizeof(*ework));
7898 if (ework == NULL)
7899 return -1;
7900
7901 pos = os_strchr(cmd, ' ');
7902 if (pos) {
7903 type_len = pos - cmd;
7904 pos++;
7905
7906 pos2 = os_strstr(pos, "freq=");
7907 if (pos2)
7908 freq = atoi(pos2 + 5);
7909
7910 pos2 = os_strstr(pos, "timeout=");
7911 if (pos2)
7912 ework->timeout = atoi(pos2 + 8);
7913 } else {
7914 type_len = os_strlen(cmd);
7915 }
7916 if (4 + type_len >= sizeof(ework->type))
7917 type_len = sizeof(ework->type) - 4 - 1;
7918 os_strlcpy(ework->type, "ext:", sizeof(ework->type));
7919 os_memcpy(ework->type + 4, cmd, type_len);
7920 ework->type[4 + type_len] = '\0';
7921
7922 wpa_s->ext_work_id++;
7923 if (wpa_s->ext_work_id == 0)
7924 wpa_s->ext_work_id++;
7925 ework->id = wpa_s->ext_work_id;
7926
7927 if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
7928 ework) < 0) {
7929 os_free(ework);
7930 return -1;
7931 }
7932
7933 ret = os_snprintf(buf, buflen, "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007934 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007935 return -1;
7936 return ret;
7937}
7938
7939
7940static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
7941{
7942 struct wpa_radio_work *work;
7943 unsigned int id = atoi(cmd);
7944
7945 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7946 {
7947 struct wpa_external_work *ework;
7948
7949 if (os_strncmp(work->type, "ext:", 4) != 0)
7950 continue;
7951 ework = work->ctx;
7952 if (id && ework->id != id)
7953 continue;
7954 wpa_dbg(wpa_s, MSG_DEBUG,
7955 "Completed external radio work %u (%s)",
7956 ework->id, ework->type);
7957 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007958 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007959 radio_work_done(work);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07007960 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007961 return 3; /* "OK\n" */
7962 }
7963
7964 return -1;
7965}
7966
7967
7968static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
7969 char *buf, size_t buflen)
7970{
7971 if (os_strcmp(cmd, "show") == 0)
7972 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
7973 if (os_strncmp(cmd, "add ", 4) == 0)
7974 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
7975 if (os_strncmp(cmd, "done ", 5) == 0)
7976 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
7977 return -1;
7978}
7979
7980
7981void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
7982{
7983 struct wpa_radio_work *work, *tmp;
7984
Dmitry Shmidt18463232014-01-24 12:29:41 -08007985 if (!wpa_s || !wpa_s->radio)
7986 return;
7987
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007988 dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
7989 struct wpa_radio_work, list) {
7990 struct wpa_external_work *ework;
7991
7992 if (os_strncmp(work->type, "ext:", 4) != 0)
7993 continue;
7994 ework = work->ctx;
7995 wpa_dbg(wpa_s, MSG_DEBUG,
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07007996 "Flushing%s external radio work %u (%s)",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007997 work->started ? " started" : "", ework->id,
7998 ework->type);
7999 if (work->started)
8000 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
8001 work, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008002 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07008003 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008004 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07008005}
8006
8007
Dmitry Shmidt051af732013-10-22 13:52:46 -07008008static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
8009{
8010 struct wpa_supplicant *wpa_s = eloop_ctx;
8011 eapol_sm_notify_ctrl_response(wpa_s->eapol);
8012}
8013
8014
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008015static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
8016 unsigned int *scan_id_count, int scan_id[])
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008017{
8018 const char *pos = value;
8019
8020 while (pos) {
8021 if (*pos == ' ' || *pos == '\0')
8022 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008023 if (*scan_id_count == MAX_SCAN_ID)
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008024 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008025 scan_id[(*scan_id_count)++] = atoi(pos);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008026 pos = os_strchr(pos, ',');
8027 if (pos)
8028 pos++;
8029 }
8030
8031 return 0;
8032}
8033
8034
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008035static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
8036 char *reply, int reply_size, int *reply_len)
8037{
8038 char *pos;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008039 unsigned int manual_scan_passive = 0;
8040 unsigned int manual_scan_use_id = 0;
8041 unsigned int manual_scan_only_new = 0;
8042 unsigned int scan_only = 0;
8043 unsigned int scan_id_count = 0;
8044 int scan_id[MAX_SCAN_ID];
8045 void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
8046 struct wpa_scan_results *scan_res);
8047 int *manual_scan_freqs = NULL;
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008048 struct wpa_ssid_value *ssid = NULL, *ns;
8049 unsigned int ssid_count = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008050
8051 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
8052 *reply_len = -1;
8053 return;
8054 }
8055
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008056 if (radio_work_pending(wpa_s, "scan")) {
8057 wpa_printf(MSG_DEBUG,
8058 "Pending scan scheduled - reject new request");
8059 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
8060 return;
8061 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008062
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07008063#ifdef CONFIG_INTERWORKING
8064 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
8065 wpa_printf(MSG_DEBUG,
8066 "Interworking select in progress - reject new scan");
8067 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
8068 return;
8069 }
8070#endif /* CONFIG_INTERWORKING */
8071
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008072 if (params) {
8073 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008074 scan_only = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008075
8076 pos = os_strstr(params, "freq=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008077 if (pos) {
8078 manual_scan_freqs = freq_range_to_channel_list(wpa_s,
8079 pos + 5);
8080 if (manual_scan_freqs == NULL) {
8081 *reply_len = -1;
8082 goto done;
8083 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008084 }
8085
8086 pos = os_strstr(params, "passive=");
8087 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008088 manual_scan_passive = !!atoi(pos + 8);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008089
8090 pos = os_strstr(params, "use_id=");
8091 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008092 manual_scan_use_id = atoi(pos + 7);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008093
8094 pos = os_strstr(params, "only_new=1");
8095 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008096 manual_scan_only_new = 1;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008097
8098 pos = os_strstr(params, "scan_id=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008099 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
8100 scan_id) < 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008101 *reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008102 goto done;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07008103 }
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008104
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008105 pos = os_strstr(params, "bssid=");
8106 if (pos) {
8107 u8 bssid[ETH_ALEN];
8108
8109 pos += 6;
8110 if (hwaddr_aton(pos, bssid)) {
8111 wpa_printf(MSG_ERROR, "Invalid BSSID %s", pos);
8112 *reply_len = -1;
8113 goto done;
8114 }
8115 os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
8116 }
8117
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008118 pos = params;
8119 while (pos && *pos != '\0') {
8120 if (os_strncmp(pos, "ssid ", 5) == 0) {
8121 char *end;
8122
8123 pos += 5;
8124 end = pos;
8125 while (*end) {
8126 if (*end == '\0' || *end == ' ')
8127 break;
8128 end++;
8129 }
8130
8131 ns = os_realloc_array(
8132 ssid, ssid_count + 1,
8133 sizeof(struct wpa_ssid_value));
8134 if (ns == NULL) {
8135 *reply_len = -1;
8136 goto done;
8137 }
8138 ssid = ns;
8139
8140 if ((end - pos) & 0x01 ||
8141 end - pos > 2 * SSID_MAX_LEN ||
8142 hexstr2bin(pos, ssid[ssid_count].ssid,
8143 (end - pos) / 2) < 0) {
8144 wpa_printf(MSG_DEBUG,
8145 "Invalid SSID value '%s'",
8146 pos);
8147 *reply_len = -1;
8148 goto done;
8149 }
8150 ssid[ssid_count].ssid_len = (end - pos) / 2;
8151 wpa_hexdump_ascii(MSG_DEBUG, "scan SSID",
8152 ssid[ssid_count].ssid,
8153 ssid[ssid_count].ssid_len);
8154 ssid_count++;
8155 pos = end;
8156 }
8157
8158 pos = os_strchr(pos, ' ');
8159 if (pos)
8160 pos++;
8161 }
8162 }
8163
8164 wpa_s->num_ssids_from_scan_req = ssid_count;
8165 os_free(wpa_s->ssids_from_scan_req);
8166 if (ssid_count) {
8167 wpa_s->ssids_from_scan_req = ssid;
8168 ssid = NULL;
8169 } else {
8170 wpa_s->ssids_from_scan_req = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008171 }
8172
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008173 if (scan_only)
8174 scan_res_handler = scan_only_handler;
8175 else if (wpa_s->scan_res_handler == scan_only_handler)
8176 scan_res_handler = NULL;
8177 else
8178 scan_res_handler = wpa_s->scan_res_handler;
8179
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008180 if (!wpa_s->sched_scanning && !wpa_s->scanning &&
8181 ((wpa_s->wpa_state <= WPA_SCANNING) ||
8182 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008183 wpa_s->manual_scan_passive = manual_scan_passive;
8184 wpa_s->manual_scan_use_id = manual_scan_use_id;
8185 wpa_s->manual_scan_only_new = manual_scan_only_new;
8186 wpa_s->scan_id_count = scan_id_count;
8187 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
8188 wpa_s->scan_res_handler = scan_res_handler;
8189 os_free(wpa_s->manual_scan_freqs);
8190 wpa_s->manual_scan_freqs = manual_scan_freqs;
8191 manual_scan_freqs = NULL;
8192
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008193 wpa_s->normal_scans = 0;
8194 wpa_s->scan_req = MANUAL_SCAN_REQ;
8195 wpa_s->after_wps = 0;
8196 wpa_s->known_wps_freq = 0;
8197 wpa_supplicant_req_scan(wpa_s, 0, 0);
8198 if (wpa_s->manual_scan_use_id) {
8199 wpa_s->manual_scan_id++;
8200 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
8201 wpa_s->manual_scan_id);
8202 *reply_len = os_snprintf(reply, reply_size, "%u\n",
8203 wpa_s->manual_scan_id);
8204 }
8205 } else if (wpa_s->sched_scanning) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008206 wpa_s->manual_scan_passive = manual_scan_passive;
8207 wpa_s->manual_scan_use_id = manual_scan_use_id;
8208 wpa_s->manual_scan_only_new = manual_scan_only_new;
8209 wpa_s->scan_id_count = scan_id_count;
8210 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
8211 wpa_s->scan_res_handler = scan_res_handler;
8212 os_free(wpa_s->manual_scan_freqs);
8213 wpa_s->manual_scan_freqs = manual_scan_freqs;
8214 manual_scan_freqs = NULL;
8215
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008216 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
8217 wpa_supplicant_cancel_sched_scan(wpa_s);
8218 wpa_s->scan_req = MANUAL_SCAN_REQ;
8219 wpa_supplicant_req_scan(wpa_s, 0, 0);
8220 if (wpa_s->manual_scan_use_id) {
8221 wpa_s->manual_scan_id++;
8222 *reply_len = os_snprintf(reply, reply_size, "%u\n",
8223 wpa_s->manual_scan_id);
8224 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
8225 wpa_s->manual_scan_id);
8226 }
8227 } else {
8228 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
8229 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
8230 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008231
8232done:
8233 os_free(manual_scan_freqs);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07008234 os_free(ssid);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008235}
8236
8237
Dmitry Shmidt818ea482014-03-10 13:15:21 -07008238#ifdef CONFIG_TESTING_OPTIONS
8239
8240static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
8241 unsigned int freq, const u8 *dst,
8242 const u8 *src, const u8 *bssid,
8243 const u8 *data, size_t data_len,
8244 enum offchannel_send_action_result
8245 result)
8246{
8247 wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
8248 " src=" MACSTR " bssid=" MACSTR " result=%s",
8249 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
8250 result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
8251 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
8252 "NO_ACK" : "FAILED"));
8253}
8254
8255
8256static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
8257{
8258 char *pos, *param;
8259 size_t len;
8260 u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
8261 int res, used;
8262 int freq = 0, no_cck = 0, wait_time = 0;
8263
8264 /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
8265 * <action=Action frame payload> */
8266
8267 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
8268
8269 pos = cmd;
8270 used = hwaddr_aton2(pos, da);
8271 if (used < 0)
8272 return -1;
8273 pos += used;
8274 while (*pos == ' ')
8275 pos++;
8276 used = hwaddr_aton2(pos, bssid);
8277 if (used < 0)
8278 return -1;
8279 pos += used;
8280
8281 param = os_strstr(pos, " freq=");
8282 if (param) {
8283 param += 6;
8284 freq = atoi(param);
8285 }
8286
8287 param = os_strstr(pos, " no_cck=");
8288 if (param) {
8289 param += 8;
8290 no_cck = atoi(param);
8291 }
8292
8293 param = os_strstr(pos, " wait_time=");
8294 if (param) {
8295 param += 11;
8296 wait_time = atoi(param);
8297 }
8298
8299 param = os_strstr(pos, " action=");
8300 if (param == NULL)
8301 return -1;
8302 param += 8;
8303
8304 len = os_strlen(param);
8305 if (len & 1)
8306 return -1;
8307 len /= 2;
8308
8309 buf = os_malloc(len);
8310 if (buf == NULL)
8311 return -1;
8312
8313 if (hexstr2bin(param, buf, len) < 0) {
8314 os_free(buf);
8315 return -1;
8316 }
8317
8318 res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
8319 buf, len, wait_time,
8320 wpas_ctrl_iface_mgmt_tx_cb, no_cck);
8321 os_free(buf);
8322 return res;
8323}
8324
8325
8326static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
8327{
8328 wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
8329 offchannel_send_action_done(wpa_s);
8330}
8331
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07008332
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008333static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
8334 char *cmd)
8335{
8336 char *pos, *param;
8337 size_t len;
8338 u8 *buf;
8339 int freq = 0, datarate = 0, ssi_signal = 0;
8340 union wpa_event_data event;
8341
8342 if (!wpa_s->ext_mgmt_frame_handling)
8343 return -1;
8344
8345 /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
8346
8347 wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
8348
8349 pos = cmd;
8350 param = os_strstr(pos, "freq=");
8351 if (param) {
8352 param += 5;
8353 freq = atoi(param);
8354 }
8355
8356 param = os_strstr(pos, " datarate=");
8357 if (param) {
8358 param += 10;
8359 datarate = atoi(param);
8360 }
8361
8362 param = os_strstr(pos, " ssi_signal=");
8363 if (param) {
8364 param += 12;
8365 ssi_signal = atoi(param);
8366 }
8367
8368 param = os_strstr(pos, " frame=");
8369 if (param == NULL)
8370 return -1;
8371 param += 7;
8372
8373 len = os_strlen(param);
8374 if (len & 1)
8375 return -1;
8376 len /= 2;
8377
8378 buf = os_malloc(len);
8379 if (buf == NULL)
8380 return -1;
8381
8382 if (hexstr2bin(param, buf, len) < 0) {
8383 os_free(buf);
8384 return -1;
8385 }
8386
8387 os_memset(&event, 0, sizeof(event));
8388 event.rx_mgmt.freq = freq;
8389 event.rx_mgmt.frame = buf;
8390 event.rx_mgmt.frame_len = len;
8391 event.rx_mgmt.ssi_signal = ssi_signal;
8392 event.rx_mgmt.datarate = datarate;
8393 wpa_s->ext_mgmt_frame_handling = 0;
8394 wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
8395 wpa_s->ext_mgmt_frame_handling = 1;
8396
8397 os_free(buf);
8398
8399 return 0;
8400}
8401
8402
Paul Stewart092955c2017-02-06 09:13:09 -08008403static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
8404 char *param)
8405{
8406 struct wpa_scan_res *res;
8407 struct os_reltime now;
8408 char *pos, *end;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008409 int ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008410
8411 if (!param)
8412 return -1;
8413
8414 if (os_strcmp(param, "START") == 0) {
8415 wpa_bss_update_start(wpa_s);
8416 return 0;
8417 }
8418
8419 if (os_strcmp(param, "END") == 0) {
8420 wpa_bss_update_end(wpa_s, NULL, 1);
8421 return 0;
8422 }
8423
8424 if (os_strncmp(param, "BSS ", 4) != 0)
8425 return -1;
8426 param += 3;
8427
8428 res = os_zalloc(sizeof(*res) + os_strlen(param) / 2);
8429 if (!res)
8430 return -1;
8431
8432 pos = os_strstr(param, " flags=");
8433 if (pos)
8434 res->flags = strtol(pos + 7, NULL, 16);
8435
8436 pos = os_strstr(param, " bssid=");
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008437 if (pos && hwaddr_aton(pos + 7, res->bssid))
8438 goto fail;
Paul Stewart092955c2017-02-06 09:13:09 -08008439
8440 pos = os_strstr(param, " freq=");
8441 if (pos)
8442 res->freq = atoi(pos + 6);
8443
8444 pos = os_strstr(param, " beacon_int=");
8445 if (pos)
8446 res->beacon_int = atoi(pos + 12);
8447
8448 pos = os_strstr(param, " caps=");
8449 if (pos)
8450 res->caps = strtol(pos + 6, NULL, 16);
8451
8452 pos = os_strstr(param, " qual=");
8453 if (pos)
8454 res->qual = atoi(pos + 6);
8455
8456 pos = os_strstr(param, " noise=");
8457 if (pos)
8458 res->noise = atoi(pos + 7);
8459
8460 pos = os_strstr(param, " level=");
8461 if (pos)
8462 res->level = atoi(pos + 7);
8463
8464 pos = os_strstr(param, " tsf=");
8465 if (pos)
8466 res->tsf = strtoll(pos + 5, NULL, 16);
8467
8468 pos = os_strstr(param, " age=");
8469 if (pos)
8470 res->age = atoi(pos + 5);
8471
8472 pos = os_strstr(param, " est_throughput=");
8473 if (pos)
8474 res->est_throughput = atoi(pos + 16);
8475
8476 pos = os_strstr(param, " snr=");
8477 if (pos)
8478 res->snr = atoi(pos + 5);
8479
8480 pos = os_strstr(param, " parent_tsf=");
8481 if (pos)
8482 res->parent_tsf = strtoll(pos + 7, NULL, 16);
8483
8484 pos = os_strstr(param, " tsf_bssid=");
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008485 if (pos && hwaddr_aton(pos + 11, res->tsf_bssid))
8486 goto fail;
Paul Stewart092955c2017-02-06 09:13:09 -08008487
8488 pos = os_strstr(param, " ie=");
8489 if (pos) {
8490 pos += 4;
8491 end = os_strchr(pos, ' ');
8492 if (!end)
8493 end = pos + os_strlen(pos);
8494 res->ie_len = (end - pos) / 2;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008495 if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len))
8496 goto fail;
Paul Stewart092955c2017-02-06 09:13:09 -08008497 }
8498
8499 pos = os_strstr(param, " beacon_ie=");
8500 if (pos) {
8501 pos += 11;
8502 end = os_strchr(pos, ' ');
8503 if (!end)
8504 end = pos + os_strlen(pos);
8505 res->beacon_ie_len = (end - pos) / 2;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008506 if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len,
8507 res->beacon_ie_len))
8508 goto fail;
Paul Stewart092955c2017-02-06 09:13:09 -08008509 }
8510
8511 os_get_reltime(&now);
8512 wpa_bss_update_scan_res(wpa_s, res, &now);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008513 ret = 0;
8514fail:
Paul Stewart092955c2017-02-06 09:13:09 -08008515 os_free(res);
8516
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008517 return ret;
Paul Stewart092955c2017-02-06 09:13:09 -08008518}
8519
8520
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07008521static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
8522{
8523 char *pos, *param;
8524 union wpa_event_data event;
8525 enum wpa_event_type ev;
8526
8527 /* <event name> [parameters..] */
8528
8529 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
8530
8531 pos = cmd;
8532 param = os_strchr(pos, ' ');
8533 if (param)
8534 *param++ = '\0';
8535
8536 os_memset(&event, 0, sizeof(event));
8537
8538 if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
8539 ev = EVENT_INTERFACE_ENABLED;
8540 } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
8541 ev = EVENT_INTERFACE_DISABLED;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008542 } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
8543 ev = EVENT_AVOID_FREQUENCIES;
8544 if (param == NULL)
8545 param = "";
8546 if (freq_range_list_parse(&event.freq_range, param) < 0)
8547 return -1;
8548 wpa_supplicant_event(wpa_s, ev, &event);
8549 os_free(event.freq_range.range);
8550 return 0;
Paul Stewart092955c2017-02-06 09:13:09 -08008551 } else if (os_strcmp(cmd, "SCAN_RES") == 0) {
8552 return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07008553 } else {
8554 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
8555 cmd);
8556 return -1;
8557 }
8558
8559 wpa_supplicant_event(wpa_s, ev, &event);
8560
8561 return 0;
8562}
8563
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008564
8565static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
8566{
8567 char *pos;
8568 u8 src[ETH_ALEN], *buf;
8569 int used;
8570 size_t len;
8571
8572 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
8573
8574 pos = cmd;
8575 used = hwaddr_aton2(pos, src);
8576 if (used < 0)
8577 return -1;
8578 pos += used;
8579 while (*pos == ' ')
8580 pos++;
8581
8582 len = os_strlen(pos);
8583 if (len & 1)
8584 return -1;
8585 len /= 2;
8586
8587 buf = os_malloc(len);
8588 if (buf == NULL)
8589 return -1;
8590
8591 if (hexstr2bin(pos, buf, len) < 0) {
8592 os_free(buf);
8593 return -1;
8594 }
8595
8596 wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
8597 os_free(buf);
8598
8599 return 0;
8600}
8601
8602
8603static u16 ipv4_hdr_checksum(const void *buf, size_t len)
8604{
8605 size_t i;
8606 u32 sum = 0;
8607 const u16 *pos = buf;
8608
8609 for (i = 0; i < len / 2; i++)
8610 sum += *pos++;
8611
8612 while (sum >> 16)
8613 sum = (sum & 0xffff) + (sum >> 16);
8614
8615 return sum ^ 0xffff;
8616}
8617
8618
8619#define HWSIM_PACKETLEN 1500
8620#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
8621
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07008622static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
8623 size_t len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008624{
8625 struct wpa_supplicant *wpa_s = ctx;
8626 const struct ether_header *eth;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008627 struct iphdr ip;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008628 const u8 *pos;
8629 unsigned int i;
8630
8631 if (len != HWSIM_PACKETLEN)
8632 return;
8633
8634 eth = (const struct ether_header *) buf;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008635 os_memcpy(&ip, eth + 1, sizeof(ip));
8636 pos = &buf[sizeof(*eth) + sizeof(ip)];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008637
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008638 if (ip.ihl != 5 || ip.version != 4 ||
8639 ntohs(ip.tot_len) != HWSIM_IP_LEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008640 return;
8641
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008642 for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008643 if (*pos != (u8) i)
8644 return;
8645 pos++;
8646 }
8647
8648 wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
8649 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
8650}
8651
8652
8653static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
8654 char *cmd)
8655{
8656 int enabled = atoi(cmd);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008657 char *pos;
8658 const char *ifname;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008659
8660 if (!enabled) {
8661 if (wpa_s->l2_test) {
8662 l2_packet_deinit(wpa_s->l2_test);
8663 wpa_s->l2_test = NULL;
8664 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
8665 }
8666 return 0;
8667 }
8668
8669 if (wpa_s->l2_test)
8670 return 0;
8671
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008672 pos = os_strstr(cmd, " ifname=");
8673 if (pos)
8674 ifname = pos + 8;
8675 else
8676 ifname = wpa_s->ifname;
8677
8678 wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008679 ETHERTYPE_IP, wpas_data_test_rx,
8680 wpa_s, 1);
8681 if (wpa_s->l2_test == NULL)
8682 return -1;
8683
8684 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
8685
8686 return 0;
8687}
8688
8689
8690static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
8691{
8692 u8 dst[ETH_ALEN], src[ETH_ALEN];
8693 char *pos;
8694 int used;
8695 long int val;
8696 u8 tos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008697 u8 buf[2 + HWSIM_PACKETLEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008698 struct ether_header *eth;
8699 struct iphdr *ip;
8700 u8 *dpos;
8701 unsigned int i;
8702
8703 if (wpa_s->l2_test == NULL)
8704 return -1;
8705
8706 /* format: <dst> <src> <tos> */
8707
8708 pos = cmd;
8709 used = hwaddr_aton2(pos, dst);
8710 if (used < 0)
8711 return -1;
8712 pos += used;
8713 while (*pos == ' ')
8714 pos++;
8715 used = hwaddr_aton2(pos, src);
8716 if (used < 0)
8717 return -1;
8718 pos += used;
8719
8720 val = strtol(pos, NULL, 0);
8721 if (val < 0 || val > 0xff)
8722 return -1;
8723 tos = val;
8724
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008725 eth = (struct ether_header *) &buf[2];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008726 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
8727 os_memcpy(eth->ether_shost, src, ETH_ALEN);
8728 eth->ether_type = htons(ETHERTYPE_IP);
8729 ip = (struct iphdr *) (eth + 1);
8730 os_memset(ip, 0, sizeof(*ip));
8731 ip->ihl = 5;
8732 ip->version = 4;
8733 ip->ttl = 64;
8734 ip->tos = tos;
8735 ip->tot_len = htons(HWSIM_IP_LEN);
8736 ip->protocol = 1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008737 ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
8738 ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008739 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
8740 dpos = (u8 *) (ip + 1);
8741 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
8742 *dpos++ = i;
8743
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008744 if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008745 HWSIM_PACKETLEN) < 0)
8746 return -1;
8747
8748 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
8749 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
8750
8751 return 0;
8752}
8753
8754
8755static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
8756 char *cmd)
8757{
8758 u8 *buf;
8759 struct ether_header *eth;
8760 struct l2_packet_data *l2 = NULL;
8761 size_t len;
8762 u16 ethertype;
8763 int res = -1;
8764
8765 len = os_strlen(cmd);
8766 if (len & 1 || len < ETH_HLEN * 2)
8767 return -1;
8768 len /= 2;
8769
8770 buf = os_malloc(len);
8771 if (buf == NULL)
8772 return -1;
8773
8774 if (hexstr2bin(cmd, buf, len) < 0)
8775 goto done;
8776
8777 eth = (struct ether_header *) buf;
8778 ethertype = ntohs(eth->ether_type);
8779
8780 l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
8781 wpas_data_test_rx, wpa_s, 1);
8782 if (l2 == NULL)
8783 goto done;
8784
8785 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
8786 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
8787done:
8788 if (l2)
8789 l2_packet_deinit(l2);
8790 os_free(buf);
8791
8792 return res < 0 ? -1 : 0;
8793}
8794
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008795
8796static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
8797{
8798#ifdef WPA_TRACE_BFD
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008799 char *pos;
8800
8801 wpa_trace_fail_after = atoi(cmd);
8802 pos = os_strchr(cmd, ':');
8803 if (pos) {
8804 pos++;
8805 os_strlcpy(wpa_trace_fail_func, pos,
8806 sizeof(wpa_trace_fail_func));
8807 } else {
8808 wpa_trace_fail_after = 0;
8809 }
8810 return 0;
8811#else /* WPA_TRACE_BFD */
8812 return -1;
8813#endif /* WPA_TRACE_BFD */
8814}
8815
8816
8817static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
8818 char *buf, size_t buflen)
8819{
8820#ifdef WPA_TRACE_BFD
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008821 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
8822 wpa_trace_fail_func);
8823#else /* WPA_TRACE_BFD */
8824 return -1;
8825#endif /* WPA_TRACE_BFD */
8826}
8827
Jouni Malinenc4818362015-10-04 11:45:13 +03008828
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008829static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
8830{
8831#ifdef WPA_TRACE_BFD
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008832 char *pos;
8833
8834 wpa_trace_test_fail_after = atoi(cmd);
8835 pos = os_strchr(cmd, ':');
8836 if (pos) {
8837 pos++;
8838 os_strlcpy(wpa_trace_test_fail_func, pos,
8839 sizeof(wpa_trace_test_fail_func));
8840 } else {
8841 wpa_trace_test_fail_after = 0;
8842 }
8843 return 0;
8844#else /* WPA_TRACE_BFD */
8845 return -1;
8846#endif /* WPA_TRACE_BFD */
8847}
8848
8849
8850static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
8851 char *buf, size_t buflen)
8852{
8853#ifdef WPA_TRACE_BFD
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008854 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
8855 wpa_trace_test_fail_func);
8856#else /* WPA_TRACE_BFD */
8857 return -1;
8858#endif /* WPA_TRACE_BFD */
8859}
8860
8861
Jouni Malinenc4818362015-10-04 11:45:13 +03008862static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
8863{
8864 struct wpa_supplicant *wpa_s = eloop_ctx;
8865 int i, count = (intptr_t) timeout_ctx;
8866
8867 wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
8868 count);
8869 for (i = 0; i < count; i++) {
8870 wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
8871 i + 1, count);
8872 }
8873}
8874
8875
8876static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
8877{
8878 int count;
8879
8880 count = atoi(cmd);
8881 if (count <= 0)
8882 return -1;
8883
8884 return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
8885 (void *) (intptr_t) count);
8886}
8887
Dmitry Shmidt818ea482014-03-10 13:15:21 -07008888
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008889static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
8890 const char *cmd)
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008891{
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008892 struct wpabuf *buf;
8893 size_t len;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008894
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008895 len = os_strlen(cmd);
8896 if (len & 1)
8897 return -1;
8898 len /= 2;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008899
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008900 if (len == 0) {
8901 buf = NULL;
8902 } else {
8903 buf = wpabuf_alloc(len);
8904 if (buf == NULL)
8905 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008906
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008907 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
8908 wpabuf_free(buf);
8909 return -1;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008910 }
8911 }
8912
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008913 wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
8914 return 0;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008915}
8916
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008917
8918static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
8919{
8920 u8 zero[WPA_TK_MAX_LEN];
8921
8922 if (wpa_s->last_tk_alg == WPA_ALG_NONE)
8923 return -1;
8924
8925 wpa_printf(MSG_INFO, "TESTING: Reset PN");
8926 os_memset(zero, 0, sizeof(zero));
8927
8928 /* First, use a zero key to avoid any possible duplicate key avoidance
8929 * in the driver. */
8930 if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
8931 wpa_s->last_tk_key_idx, 1, zero, 6,
8932 zero, wpa_s->last_tk_len) < 0)
8933 return -1;
8934
8935 /* Set the previously configured key to reset its TSC/RSC */
8936 return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
8937 wpa_s->last_tk_key_idx, 1, zero, 6,
8938 wpa_s->last_tk, wpa_s->last_tk_len);
8939}
8940
8941
8942static int wpas_ctrl_key_request(struct wpa_supplicant *wpa_s, const char *cmd)
8943{
8944 const char *pos = cmd;
8945 int error, pairwise;
8946
8947 error = atoi(pos);
8948 pos = os_strchr(pos, ' ');
8949 if (!pos)
8950 return -1;
8951 pairwise = atoi(pos);
8952 wpa_sm_key_request(wpa_s->wpa, error, pairwise);
8953 return 0;
8954}
8955
8956
8957static int wpas_ctrl_resend_assoc(struct wpa_supplicant *wpa_s)
8958{
8959#ifdef CONFIG_SME
8960 struct wpa_driver_associate_params params;
8961 int ret;
8962
8963 os_memset(&params, 0, sizeof(params));
8964 params.bssid = wpa_s->bssid;
8965 params.ssid = wpa_s->sme.ssid;
8966 params.ssid_len = wpa_s->sme.ssid_len;
8967 params.freq.freq = wpa_s->sme.freq;
8968 if (wpa_s->last_assoc_req_wpa_ie) {
8969 params.wpa_ie = wpabuf_head(wpa_s->last_assoc_req_wpa_ie);
8970 params.wpa_ie_len = wpabuf_len(wpa_s->last_assoc_req_wpa_ie);
8971 }
8972 params.pairwise_suite = wpa_s->pairwise_cipher;
8973 params.group_suite = wpa_s->group_cipher;
8974 params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
8975 params.key_mgmt_suite = wpa_s->key_mgmt;
8976 params.wpa_proto = wpa_s->wpa_proto;
8977 params.mgmt_frame_protection = wpa_s->sme.mfp;
8978 params.rrm_used = wpa_s->rrm.rrm_used;
8979 if (wpa_s->sme.prev_bssid_set)
8980 params.prev_bssid = wpa_s->sme.prev_bssid;
8981 wpa_printf(MSG_INFO, "TESTING: Resend association request");
8982 ret = wpa_drv_associate(wpa_s, &params);
8983 wpa_s->testing_resend_assoc = 1;
8984 return ret;
8985#else /* CONFIG_SME */
8986 return -1;
8987#endif /* CONFIG_SME */
8988}
8989
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008990#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008991
8992
8993static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
8994{
8995 char *pos = cmd;
8996 int frame;
8997 size_t len;
8998 struct wpabuf *buf;
8999 struct ieee802_11_elems elems;
9000
9001 frame = atoi(pos);
9002 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
9003 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009004 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009005
9006 pos = os_strchr(pos, ' ');
9007 if (pos == NULL)
9008 return -1;
9009 pos++;
9010
9011 len = os_strlen(pos);
9012 if (len == 0)
9013 return 0;
9014 if (len & 1)
9015 return -1;
9016 len /= 2;
9017
9018 buf = wpabuf_alloc(len);
9019 if (buf == NULL)
9020 return -1;
9021
9022 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
9023 wpabuf_free(buf);
9024 return -1;
9025 }
9026
9027 if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
9028 ParseFailed) {
9029 wpabuf_free(buf);
9030 return -1;
9031 }
9032
9033 if (wpa_s->vendor_elem[frame] == NULL) {
9034 wpa_s->vendor_elem[frame] = buf;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009035 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009036 return 0;
9037 }
9038
9039 if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
9040 wpabuf_free(buf);
9041 return -1;
9042 }
9043
9044 wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
9045 wpabuf_free(buf);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009046 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009047
9048 return 0;
9049}
9050
9051
9052static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
9053 char *buf, size_t buflen)
9054{
9055 int frame = atoi(cmd);
9056
9057 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
9058 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009059 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009060
9061 if (wpa_s->vendor_elem[frame] == NULL)
9062 return 0;
9063
9064 return wpa_snprintf_hex(buf, buflen,
9065 wpabuf_head_u8(wpa_s->vendor_elem[frame]),
9066 wpabuf_len(wpa_s->vendor_elem[frame]));
9067}
9068
9069
9070static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
9071{
9072 char *pos = cmd;
9073 int frame;
9074 size_t len;
9075 u8 *buf;
9076 struct ieee802_11_elems elems;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009077 int res;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009078
9079 frame = atoi(pos);
9080 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
9081 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009082 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009083
9084 pos = os_strchr(pos, ' ');
9085 if (pos == NULL)
9086 return -1;
9087 pos++;
9088
9089 if (*pos == '*') {
9090 wpabuf_free(wpa_s->vendor_elem[frame]);
9091 wpa_s->vendor_elem[frame] = NULL;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009092 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009093 return 0;
9094 }
9095
9096 if (wpa_s->vendor_elem[frame] == NULL)
9097 return -1;
9098
9099 len = os_strlen(pos);
9100 if (len == 0)
9101 return 0;
9102 if (len & 1)
9103 return -1;
9104 len /= 2;
9105
9106 buf = os_malloc(len);
9107 if (buf == NULL)
9108 return -1;
9109
9110 if (hexstr2bin(pos, buf, len) < 0) {
9111 os_free(buf);
9112 return -1;
9113 }
9114
9115 if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
9116 os_free(buf);
9117 return -1;
9118 }
9119
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009120 res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009121 os_free(buf);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009122 return res;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009123}
9124
9125
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009126static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
9127{
9128 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009129 size_t len;
9130 const u8 *data;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009131
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009132 /*
9133 * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
9134 * BSSID[6]
9135 * BSSID Information[4]
9136 * Operating Class[1]
9137 * Channel Number[1]
9138 * PHY Type[1]
9139 * Optional Subelements[variable]
9140 */
9141#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
9142
9143 if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009144 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009145 goto out;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009146 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009147
9148 data = wpabuf_head_u8(neighbor_rep);
9149 len = wpabuf_len(neighbor_rep);
9150
9151 while (len >= 2 + NR_IE_MIN_LEN) {
9152 const u8 *nr;
9153 char lci[256 * 2 + 1];
9154 char civic[256 * 2 + 1];
9155 u8 nr_len = data[1];
9156 const u8 *pos = data, *end;
9157
9158 if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
9159 nr_len < NR_IE_MIN_LEN) {
9160 wpa_printf(MSG_DEBUG,
9161 "CTRL: Invalid Neighbor Report element: id=%u len=%u",
9162 data[0], nr_len);
9163 goto out;
9164 }
9165
9166 if (2U + nr_len > len) {
9167 wpa_printf(MSG_DEBUG,
9168 "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
9169 data[0], len, nr_len);
9170 goto out;
9171 }
9172 pos += 2;
9173 end = pos + nr_len;
9174
9175 nr = pos;
9176 pos += NR_IE_MIN_LEN;
9177
9178 lci[0] = '\0';
9179 civic[0] = '\0';
9180 while (end - pos > 2) {
9181 u8 s_id, s_len;
9182
9183 s_id = *pos++;
9184 s_len = *pos++;
9185 if (s_len > end - pos)
9186 goto out;
9187 if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
9188 /* Measurement Token[1] */
9189 /* Measurement Report Mode[1] */
9190 /* Measurement Type[1] */
9191 /* Measurement Report[variable] */
9192 switch (pos[2]) {
9193 case MEASURE_TYPE_LCI:
9194 if (lci[0])
9195 break;
9196 wpa_snprintf_hex(lci, sizeof(lci),
9197 pos, s_len);
9198 break;
9199 case MEASURE_TYPE_LOCATION_CIVIC:
9200 if (civic[0])
9201 break;
9202 wpa_snprintf_hex(civic, sizeof(civic),
9203 pos, s_len);
9204 break;
9205 }
9206 }
9207
9208 pos += s_len;
9209 }
9210
9211 wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
9212 "bssid=" MACSTR
9213 " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
9214 MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
9215 nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
9216 nr[ETH_ALEN + 6],
9217 lci[0] ? " lci=" : "", lci,
9218 civic[0] ? " civic=" : "", civic);
9219
9220 data = end;
9221 len -= 2 + nr_len;
9222 }
9223
9224out:
9225 wpabuf_free(neighbor_rep);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009226}
9227
9228
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009229static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
9230 char *cmd)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009231{
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009232 struct wpa_ssid_value ssid, *ssid_p = NULL;
9233 int ret, lci = 0, civic = 0;
9234 char *ssid_s;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009235
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009236 ssid_s = os_strstr(cmd, "ssid=");
9237 if (ssid_s) {
9238 if (ssid_parse(ssid_s + 5, &ssid)) {
9239 wpa_printf(MSG_ERROR,
9240 "CTRL: Send Neighbor Report: bad SSID");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009241 return -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009242 }
9243
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009244 ssid_p = &ssid;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009245
9246 /*
9247 * Move cmd after the SSID text that may include "lci" or
9248 * "civic".
9249 */
9250 cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
9251 if (cmd)
9252 cmd++;
9253
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009254 }
9255
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009256 if (cmd && os_strstr(cmd, "lci"))
9257 lci = 1;
9258
9259 if (cmd && os_strstr(cmd, "civic"))
9260 civic = 1;
9261
9262 ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009263 wpas_ctrl_neighbor_rep_cb,
9264 wpa_s);
9265
9266 return ret;
9267}
9268
9269
9270static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
9271{
9272 eapol_sm_erp_flush(wpa_s->eapol);
9273 return 0;
9274}
9275
9276
9277static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
9278 char *cmd)
9279{
9280 char *token, *context = NULL;
9281 unsigned int enable = ~0, type = 0;
9282 u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
9283 u8 *addr = NULL, *mask = NULL;
9284
9285 while ((token = str_token(cmd, " ", &context))) {
9286 if (os_strcasecmp(token, "scan") == 0) {
9287 type |= MAC_ADDR_RAND_SCAN;
9288 } else if (os_strcasecmp(token, "sched") == 0) {
9289 type |= MAC_ADDR_RAND_SCHED_SCAN;
9290 } else if (os_strcasecmp(token, "pno") == 0) {
9291 type |= MAC_ADDR_RAND_PNO;
9292 } else if (os_strcasecmp(token, "all") == 0) {
9293 type = wpa_s->mac_addr_rand_supported;
9294 } else if (os_strncasecmp(token, "enable=", 7) == 0) {
9295 enable = atoi(token + 7);
9296 } else if (os_strncasecmp(token, "addr=", 5) == 0) {
9297 addr = _addr;
9298 if (hwaddr_aton(token + 5, addr)) {
9299 wpa_printf(MSG_INFO,
9300 "CTRL: Invalid MAC address: %s",
9301 token);
9302 return -1;
9303 }
9304 } else if (os_strncasecmp(token, "mask=", 5) == 0) {
9305 mask = _mask;
9306 if (hwaddr_aton(token + 5, mask)) {
9307 wpa_printf(MSG_INFO,
9308 "CTRL: Invalid MAC address mask: %s",
9309 token);
9310 return -1;
9311 }
9312 } else {
9313 wpa_printf(MSG_INFO,
9314 "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
9315 token);
9316 return -1;
9317 }
9318 }
9319
9320 if (!type) {
9321 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
9322 return -1;
9323 }
9324
9325 if ((wpa_s->mac_addr_rand_supported & type) != type) {
9326 wpa_printf(MSG_INFO,
9327 "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
9328 type, wpa_s->mac_addr_rand_supported);
9329 return -1;
9330 }
9331
9332 if (enable > 1) {
9333 wpa_printf(MSG_INFO,
9334 "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
9335 return -1;
9336 }
9337
9338 if (!enable) {
9339 wpas_mac_addr_rand_scan_clear(wpa_s, type);
9340 if (wpa_s->pno) {
9341 if (type & MAC_ADDR_RAND_PNO) {
9342 wpas_stop_pno(wpa_s);
9343 wpas_start_pno(wpa_s);
9344 }
9345 } else if (wpa_s->sched_scanning &&
9346 (type & MAC_ADDR_RAND_SCHED_SCAN)) {
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07009347 wpas_scan_restart_sched_scan(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009348 }
9349 return 0;
9350 }
9351
9352 if ((addr && !mask) || (!addr && mask)) {
9353 wpa_printf(MSG_INFO,
9354 "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
9355 return -1;
9356 }
9357
9358 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
9359 wpa_printf(MSG_INFO,
9360 "CTRL: MAC_RAND_SCAN cannot allow multicast address");
9361 return -1;
9362 }
9363
9364 if (type & MAC_ADDR_RAND_SCAN) {
9365 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
9366 addr, mask);
9367 }
9368
9369 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
9370 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
9371 addr, mask);
9372
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07009373 if (wpa_s->sched_scanning && !wpa_s->pno)
9374 wpas_scan_restart_sched_scan(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009375 }
9376
9377 if (type & MAC_ADDR_RAND_PNO) {
9378 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
9379 addr, mask);
9380 if (wpa_s->pno) {
9381 wpas_stop_pno(wpa_s);
9382 wpas_start_pno(wpa_s);
9383 }
9384 }
9385
9386 return 0;
9387}
9388
9389
Dmitry Shmidte4663042016-04-04 10:07:49 -07009390static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
9391 char *buf, size_t buflen)
9392{
9393 size_t reply_len;
9394
9395 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
9396#ifdef CONFIG_AP
9397 reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
9398 buflen - reply_len);
9399#endif /* CONFIG_AP */
9400 return reply_len;
9401}
9402
9403
9404static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
9405{
9406 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
9407#ifdef CONFIG_AP
9408 wpas_ap_pmksa_cache_flush(wpa_s);
9409#endif /* CONFIG_AP */
9410}
9411
9412
Dmitry Shmidt29333592017-01-09 12:27:11 -08009413#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
9414
9415static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
9416 const char *cmd, char *buf, size_t buflen)
9417{
9418 struct rsn_pmksa_cache_entry *entry;
9419 struct wpa_ssid *ssid;
9420 char *pos, *pos2, *end;
9421 int ret;
9422 struct os_reltime now;
9423
9424 ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
9425 if (!ssid)
9426 return -1;
9427
9428 pos = buf;
9429 end = buf + buflen;
9430
9431 os_get_reltime(&now);
9432
9433 /*
9434 * Entry format:
9435 * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
9436 * <expiration in seconds> <akmp> <opportunistic>
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009437 * [FILS Cache Identifier]
Dmitry Shmidt29333592017-01-09 12:27:11 -08009438 */
9439
9440 for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
9441 entry = entry->next) {
9442 if (entry->network_ctx != ssid)
9443 continue;
9444
9445 pos2 = pos;
9446 ret = os_snprintf(pos2, end - pos2, MACSTR " ",
9447 MAC2STR(entry->aa));
9448 if (os_snprintf_error(end - pos2, ret))
9449 break;
9450 pos2 += ret;
9451
9452 pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid,
9453 PMKID_LEN);
9454
9455 ret = os_snprintf(pos2, end - pos2, " ");
9456 if (os_snprintf_error(end - pos2, ret))
9457 break;
9458 pos2 += ret;
9459
9460 pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk,
9461 entry->pmk_len);
9462
9463 ret = os_snprintf(pos2, end - pos2, " %d %d %d %d",
9464 (int) (entry->reauth_time - now.sec),
9465 (int) (entry->expiration - now.sec),
9466 entry->akmp,
9467 entry->opportunistic);
9468 if (os_snprintf_error(end - pos2, ret))
9469 break;
9470 pos2 += ret;
9471
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009472 if (entry->fils_cache_id_set) {
9473 ret = os_snprintf(pos2, end - pos2, " %02x%02x",
9474 entry->fils_cache_id[0],
9475 entry->fils_cache_id[1]);
9476 if (os_snprintf_error(end - pos2, ret))
9477 break;
9478 pos2 += ret;
9479 }
9480
Dmitry Shmidt29333592017-01-09 12:27:11 -08009481 ret = os_snprintf(pos2, end - pos2, "\n");
9482 if (os_snprintf_error(end - pos2, ret))
9483 break;
9484 pos2 += ret;
9485
9486 pos = pos2;
9487 }
9488
9489 return pos - buf;
9490}
9491
9492
9493static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
9494 char *cmd)
9495{
9496 struct rsn_pmksa_cache_entry *entry;
9497 struct wpa_ssid *ssid;
9498 char *pos, *pos2;
9499 int ret = -1;
9500 struct os_reltime now;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009501 int reauth_time = 0, expiration = 0, i;
Dmitry Shmidt29333592017-01-09 12:27:11 -08009502
9503 /*
9504 * Entry format:
9505 * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
9506 * <expiration in seconds> <akmp> <opportunistic>
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009507 * [FILS Cache Identifier]
Dmitry Shmidt29333592017-01-09 12:27:11 -08009508 */
9509
9510 ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
9511 if (!ssid)
9512 return -1;
9513
9514 pos = os_strchr(cmd, ' ');
9515 if (!pos)
9516 return -1;
9517 pos++;
9518
9519 entry = os_zalloc(sizeof(*entry));
9520 if (!entry)
9521 return -1;
9522
9523 if (hwaddr_aton(pos, entry->aa))
9524 goto fail;
9525
9526 pos = os_strchr(pos, ' ');
9527 if (!pos)
9528 goto fail;
9529 pos++;
9530
9531 if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0)
9532 goto fail;
9533
9534 pos = os_strchr(pos, ' ');
9535 if (!pos)
9536 goto fail;
9537 pos++;
9538
9539 pos2 = os_strchr(pos, ' ');
9540 if (!pos2)
9541 goto fail;
9542 entry->pmk_len = (pos2 - pos) / 2;
9543 if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX ||
9544 hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0)
9545 goto fail;
9546
9547 pos = os_strchr(pos, ' ');
9548 if (!pos)
9549 goto fail;
9550 pos++;
9551
9552 if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
9553 &entry->akmp, &entry->opportunistic) != 4)
9554 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009555 for (i = 0; i < 4; i++) {
9556 pos = os_strchr(pos, ' ');
9557 if (!pos) {
9558 if (i < 3)
9559 goto fail;
9560 break;
9561 }
9562 pos++;
9563 }
9564 if (pos) {
9565 if (hexstr2bin(pos, entry->fils_cache_id,
9566 FILS_CACHE_ID_LEN) < 0)
9567 goto fail;
9568 entry->fils_cache_id_set = 1;
9569 }
Dmitry Shmidt29333592017-01-09 12:27:11 -08009570 os_get_reltime(&now);
9571 entry->expiration = now.sec + expiration;
9572 entry->reauth_time = now.sec + reauth_time;
9573
9574 entry->network_ctx = ssid;
9575
9576 wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
9577 entry = NULL;
9578 ret = 0;
9579fail:
9580 os_free(entry);
9581 return ret;
9582}
9583
Paul Stewart092955c2017-02-06 09:13:09 -08009584
9585#ifdef CONFIG_MESH
9586
9587static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s,
9588 const char *cmd, char *buf,
9589 size_t buflen)
9590{
9591 u8 spa[ETH_ALEN];
9592
9593 if (!wpa_s->ifmsh)
9594 return -1;
9595
9596 if (os_strcasecmp(cmd, "any") == 0)
9597 return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen);
9598
9599 if (hwaddr_aton(cmd, spa))
9600 return -1;
9601
9602 return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen);
9603}
9604
9605
9606static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
9607 char *cmd)
9608{
9609 /*
9610 * We do not check mesh interface existance because PMKSA should be
9611 * stored before wpa_s->ifmsh creation to suppress commit message
9612 * creation.
9613 */
9614 return wpas_ap_pmksa_cache_add_external(wpa_s, cmd);
9615}
9616
9617#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -08009618#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
9619
9620
Paul Stewart092955c2017-02-06 09:13:09 -08009621#ifdef CONFIG_FILS
9622static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s,
9623 const char *cmd)
9624{
9625 struct fils_hlp_req *req;
9626 const char *pos;
9627
9628 /* format: <dst> <packet starting from ethertype> */
9629
9630 req = os_zalloc(sizeof(*req));
9631 if (!req)
9632 return -1;
9633
9634 if (hwaddr_aton(cmd, req->dst))
9635 goto fail;
9636
9637 pos = os_strchr(cmd, ' ');
9638 if (!pos)
9639 goto fail;
9640 pos++;
9641 req->pkt = wpabuf_parse_bin(pos);
9642 if (!req->pkt)
9643 goto fail;
9644
9645 dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
9646 return 0;
9647fail:
9648 wpabuf_free(req->pkt);
9649 os_free(req);
9650 return -1;
9651}
9652#endif /* CONFIG_FILS */
9653
9654
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009655static int wpas_ctrl_cmd_debug_level(const char *cmd)
9656{
9657 if (os_strcmp(cmd, "PING") == 0 ||
9658 os_strncmp(cmd, "BSS ", 4) == 0 ||
9659 os_strncmp(cmd, "GET_NETWORK ", 12) == 0 ||
9660 os_strncmp(cmd, "STATUS", 6) == 0 ||
9661 os_strncmp(cmd, "STA ", 4) == 0 ||
9662 os_strncmp(cmd, "STA-", 4) == 0)
9663 return MSG_EXCESSIVE;
9664 return MSG_DEBUG;
9665}
9666
9667
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009668char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
9669 char *buf, size_t *resp_len)
9670{
9671 char *reply;
9672 const int reply_size = 4096;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009673 int reply_len;
9674
9675 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009676 os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
9677 os_strncmp(buf, "PMKSA_ADD ", 10) == 0 ||
9678 os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009679 if (wpa_debug_show_keys)
9680 wpa_dbg(wpa_s, MSG_DEBUG,
9681 "Control interface command '%s'", buf);
9682 else
9683 wpa_dbg(wpa_s, MSG_DEBUG,
9684 "Control interface command '%s [REMOVED]'",
9685 os_strncmp(buf, WPA_CTRL_RSP,
9686 os_strlen(WPA_CTRL_RSP)) == 0 ?
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009687 WPA_CTRL_RSP :
9688 (os_strncmp(buf, "SET_NETWORK ", 12) == 0 ?
9689 "SET_NETWORK" : "key-add"));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009690 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
Dmitry Shmidt21de2142014-04-08 10:50:52 -07009691 os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009692 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
9693 (const u8 *) buf, os_strlen(buf));
9694 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009695 int level = wpas_ctrl_cmd_debug_level(buf);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07009696 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009697 }
9698
9699 reply = os_malloc(reply_size);
9700 if (reply == NULL) {
9701 *resp_len = 1;
9702 return NULL;
9703 }
9704
9705 os_memcpy(reply, "OK\n", 3);
9706 reply_len = 3;
9707
9708 if (os_strcmp(buf, "PING") == 0) {
9709 os_memcpy(reply, "PONG\n", 5);
9710 reply_len = 5;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009711 } else if (os_strcmp(buf, "IFNAME") == 0) {
9712 reply_len = os_strlen(wpa_s->ifname);
9713 os_memcpy(reply, wpa_s->ifname, reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009714 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
9715 if (wpa_debug_reopen_file() < 0)
9716 reply_len = -1;
9717 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
9718 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
9719 } else if (os_strcmp(buf, "MIB") == 0) {
9720 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
9721 if (reply_len >= 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009722 reply_len += eapol_sm_get_mib(wpa_s->eapol,
9723 reply + reply_len,
9724 reply_size - reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009725 }
9726 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
9727 reply_len = wpa_supplicant_ctrl_iface_status(
9728 wpa_s, buf + 6, reply, reply_size);
9729 } else if (os_strcmp(buf, "PMKSA") == 0) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07009730 reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009731 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07009732 wpas_ctrl_iface_pmksa_flush(wpa_s);
Dmitry Shmidt29333592017-01-09 12:27:11 -08009733#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
9734 } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) {
9735 reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10,
9736 reply, reply_size);
9737 } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
9738 if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
9739 reply_len = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08009740#ifdef CONFIG_MESH
9741 } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) {
9742 reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15,
9743 reply, reply_size);
9744 } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
9745 if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0)
9746 reply_len = -1;
9747#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -08009748#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009749 } else if (os_strncmp(buf, "SET ", 4) == 0) {
9750 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
9751 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009752 } else if (os_strncmp(buf, "DUMP", 4) == 0) {
9753 reply_len = wpa_config_dump_values(wpa_s->conf,
9754 reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009755 } else if (os_strncmp(buf, "GET ", 4) == 0) {
9756 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
9757 reply, reply_size);
9758 } else if (os_strcmp(buf, "LOGON") == 0) {
9759 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
9760 } else if (os_strcmp(buf, "LOGOFF") == 0) {
9761 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
9762 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
9763 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
9764 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009765 else
9766 wpas_request_connection(wpa_s);
Dmitry Shmidt98660862014-03-11 17:26:21 -07009767 } else if (os_strcmp(buf, "REATTACH") == 0) {
9768 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
9769 !wpa_s->current_ssid)
9770 reply_len = -1;
9771 else {
9772 wpa_s->reattach = 1;
9773 wpas_request_connection(wpa_s);
9774 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009775 } else if (os_strcmp(buf, "RECONNECT") == 0) {
9776 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
9777 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009778 else if (wpa_s->disconnected)
9779 wpas_request_connection(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009780#ifdef IEEE8021X_EAPOL
9781 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
9782 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
9783 reply_len = -1;
9784#endif /* IEEE8021X_EAPOL */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009785#ifdef CONFIG_IEEE80211R
9786 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
9787 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
9788 reply_len = -1;
9789#endif /* CONFIG_IEEE80211R */
9790#ifdef CONFIG_WPS
9791 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
9792 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
9793 if (res == -2) {
9794 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9795 reply_len = 17;
9796 } else if (res)
9797 reply_len = -1;
9798 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
9799 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
9800 if (res == -2) {
9801 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9802 reply_len = 17;
9803 } else if (res)
9804 reply_len = -1;
9805 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
9806 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
9807 reply,
9808 reply_size);
9809 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
9810 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
9811 wpa_s, buf + 14, reply, reply_size);
9812 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
9813 if (wpas_wps_cancel(wpa_s))
9814 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009815#ifdef CONFIG_WPS_NFC
9816 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
9817 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
9818 reply_len = -1;
9819 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
9820 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
9821 reply_len = -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08009822 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
9823 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
9824 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009825 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
9826 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
9827 wpa_s, buf + 14, reply, reply_size);
9828 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
9829 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
9830 buf + 17))
9831 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009832 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
9833 reply_len = wpas_ctrl_nfc_get_handover_req(
9834 wpa_s, buf + 21, reply, reply_size);
9835 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
9836 reply_len = wpas_ctrl_nfc_get_handover_sel(
9837 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08009838 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
9839 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
9840 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009841#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009842 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
9843 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
9844 reply_len = -1;
9845#ifdef CONFIG_AP
9846 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
9847 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
9848 wpa_s, buf + 11, reply, reply_size);
9849#endif /* CONFIG_AP */
9850#ifdef CONFIG_WPS_ER
9851 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
9852 if (wpas_wps_er_start(wpa_s, NULL))
9853 reply_len = -1;
9854 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
9855 if (wpas_wps_er_start(wpa_s, buf + 13))
9856 reply_len = -1;
9857 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009858 wpas_wps_er_stop(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009859 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
9860 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
9861 reply_len = -1;
9862 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
9863 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
9864 if (ret == -2) {
9865 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9866 reply_len = 17;
9867 } else if (ret == -3) {
9868 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
9869 reply_len = 18;
9870 } else if (ret == -4) {
9871 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
9872 reply_len = 20;
9873 } else if (ret)
9874 reply_len = -1;
9875 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
9876 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
9877 reply_len = -1;
9878 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
9879 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
9880 buf + 18))
9881 reply_len = -1;
9882 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
9883 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
9884 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009885#ifdef CONFIG_WPS_NFC
9886 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
9887 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
9888 wpa_s, buf + 24, reply, reply_size);
9889#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009890#endif /* CONFIG_WPS_ER */
9891#endif /* CONFIG_WPS */
9892#ifdef CONFIG_IBSS_RSN
9893 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
9894 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
9895 reply_len = -1;
9896#endif /* CONFIG_IBSS_RSN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009897#ifdef CONFIG_MESH
9898 } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
9899 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
9900 wpa_s, buf + 19, reply, reply_size);
9901 } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
9902 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
9903 wpa_s, "", reply, reply_size);
9904 } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
9905 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
9906 reply_len = -1;
9907 } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
9908 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
9909 buf + 18))
9910 reply_len = -1;
Dmitry Shmidte4663042016-04-04 10:07:49 -07009911 } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
9912 if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
9913 reply_len = -1;
9914 } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
9915 if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
9916 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009917#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009918#ifdef CONFIG_P2P
9919 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009920 if (p2p_ctrl_find(wpa_s, buf + 8))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009921 reply_len = -1;
9922 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
9923 if (p2p_ctrl_find(wpa_s, ""))
9924 reply_len = -1;
9925 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
9926 wpas_p2p_stop_find(wpa_s);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009927 } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
9928 if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
9929 reply_len = -1;
9930 } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
9931 if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
9932 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009933 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
9934 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
9935 reply_size);
9936 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
9937 if (p2p_ctrl_listen(wpa_s, buf + 11))
9938 reply_len = -1;
9939 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
9940 if (p2p_ctrl_listen(wpa_s, ""))
9941 reply_len = -1;
9942 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
9943 if (wpas_p2p_group_remove(wpa_s, buf + 17))
9944 reply_len = -1;
9945 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009946 if (p2p_ctrl_group_add(wpa_s, ""))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009947 reply_len = -1;
9948 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
9949 if (p2p_ctrl_group_add(wpa_s, buf + 14))
9950 reply_len = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009951 } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
9952 reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
9953 reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009954 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
9955 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
9956 reply_len = -1;
9957 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
9958 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
9959 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
9960 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
9961 reply_size);
9962 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
9963 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
9964 reply_len = -1;
9965 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
9966 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
9967 reply_len = -1;
9968 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
9969 wpas_p2p_sd_service_update(wpa_s);
9970 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
9971 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
9972 reply_len = -1;
9973 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
9974 wpas_p2p_service_flush(wpa_s);
9975 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
9976 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
9977 reply_len = -1;
9978 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
9979 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
9980 reply_len = -1;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009981 } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
9982 if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
9983 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009984 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
9985 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
9986 reply_len = -1;
9987 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
9988 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
9989 reply_len = -1;
9990 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
9991 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
9992 reply_size);
9993 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
9994 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
9995 reply_len = -1;
9996 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
Dmitry Shmidt444d5672013-04-01 13:08:44 -07009997 p2p_ctrl_flush(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009998 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
9999 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
10000 reply_len = -1;
10001 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
10002 if (wpas_p2p_cancel(wpa_s))
10003 reply_len = -1;
10004 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
10005 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
10006 reply_len = -1;
10007 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
10008 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
10009 reply_len = -1;
10010 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
10011 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
10012 reply_len = -1;
10013 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
10014 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
10015 reply_len = -1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -070010016 } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
10017 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
10018 reply_len = -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010019 } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
10020 if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
10021 reply_len = -1;
10022 } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
10023 if (wpas_p2p_lo_stop(wpa_s))
10024 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010025#endif /* CONFIG_P2P */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070010026#ifdef CONFIG_WIFI_DISPLAY
10027 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
10028 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
10029 reply_len = -1;
10030 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
10031 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
10032 reply, reply_size);
10033#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010034#ifdef CONFIG_INTERWORKING
10035 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
10036 if (interworking_fetch_anqp(wpa_s) < 0)
10037 reply_len = -1;
10038 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
10039 interworking_stop_fetch_anqp(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010040 } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
10041 if (ctrl_interworking_select(wpa_s, NULL) < 0)
10042 reply_len = -1;
10043 } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
10044 if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010045 reply_len = -1;
10046 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010047 if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010048 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010049 } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
10050 int id;
10051
10052 id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
10053 if (id < 0)
10054 reply_len = -1;
10055 else {
10056 reply_len = os_snprintf(reply, reply_size, "%d\n", id);
10057 if (os_snprintf_error(reply_size, reply_len))
10058 reply_len = -1;
10059 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010060 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
10061 if (get_anqp(wpa_s, buf + 9) < 0)
10062 reply_len = -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070010063 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
10064 if (gas_request(wpa_s, buf + 12) < 0)
10065 reply_len = -1;
10066 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
10067 reply_len = gas_response_get(wpa_s, buf + 17, reply,
10068 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010069#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -070010070#ifdef CONFIG_HS20
10071 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
10072 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
10073 reply_len = -1;
10074 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
10075 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
10076 reply_len = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080010077 } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
Dmitry Shmidt7d56b752015-12-22 10:59:44 -080010078 if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
10079 reply_len = -1;
10080 } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
10081 if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
10082 reply_len = -1;
10083 } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
10084 reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
10085 } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
10086 if (del_hs20_icon(wpa_s, buf + 14) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080010087 reply_len = -1;
10088 } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010089 if (hs20_fetch_osu(wpa_s, 0) < 0)
10090 reply_len = -1;
10091 } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
10092 if (hs20_fetch_osu(wpa_s, 1) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080010093 reply_len = -1;
10094 } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
10095 hs20_cancel_fetch_osu(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -070010096#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010097 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
10098 {
10099 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
10100 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
10101 reply_len = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -070010102 else {
10103 /*
10104 * Notify response from timeout to allow the control
10105 * interface response to be sent first.
10106 */
10107 eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
10108 wpa_s, NULL);
10109 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010110 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
10111 if (wpa_supplicant_reload_configuration(wpa_s))
10112 reply_len = -1;
10113 } else if (os_strcmp(buf, "TERMINATE") == 0) {
10114 wpa_supplicant_terminate_proc(wpa_s->global);
10115 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
10116 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
10117 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -070010118 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010119 reply_len = wpa_supplicant_ctrl_iface_blacklist(
10120 wpa_s, buf + 9, reply, reply_size);
10121 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
10122 reply_len = wpa_supplicant_ctrl_iface_log_level(
10123 wpa_s, buf + 9, reply, reply_size);
Vinit Deshpandeda134e92014-12-02 10:59:29 -080010124 } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
10125 reply_len = wpa_supplicant_ctrl_iface_list_networks(
10126 wpa_s, buf + 14, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010127 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
10128 reply_len = wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -080010129 wpa_s, NULL, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010130 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070010131 wpas_request_disconnection(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010132 } else if (os_strcmp(buf, "SCAN") == 0) {
10133 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
10134 } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
10135 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010136 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
10137 reply_len = wpa_supplicant_ctrl_iface_scan_results(
10138 wpa_s, reply, reply_size);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010139 } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
10140 if (wpas_abort_ongoing_scan(wpa_s) < 0)
10141 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010142 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
10143 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
10144 reply_len = -1;
10145 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
10146 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
10147 reply_len = -1;
10148 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
10149 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
10150 reply_len = -1;
10151 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
10152 reply_len = wpa_supplicant_ctrl_iface_add_network(
10153 wpa_s, reply, reply_size);
10154 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
10155 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
10156 reply_len = -1;
10157 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
10158 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
10159 reply_len = -1;
10160 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
10161 reply_len = wpa_supplicant_ctrl_iface_get_network(
10162 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt684785c2014-05-12 13:34:29 -070010163 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010164 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12,
10165 wpa_s))
Dmitry Shmidt684785c2014-05-12 13:34:29 -070010166 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -070010167 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
10168 reply_len = wpa_supplicant_ctrl_iface_list_creds(
10169 wpa_s, reply, reply_size);
10170 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
10171 reply_len = wpa_supplicant_ctrl_iface_add_cred(
10172 wpa_s, reply, reply_size);
10173 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
10174 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
10175 reply_len = -1;
10176 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
10177 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
10178 reply_len = -1;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -070010179 } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
10180 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
10181 reply,
10182 reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010183#ifndef CONFIG_NO_CONFIG_WRITE
10184 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
10185 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
10186 reply_len = -1;
10187#endif /* CONFIG_NO_CONFIG_WRITE */
10188 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
10189 reply_len = wpa_supplicant_ctrl_iface_get_capability(
10190 wpa_s, buf + 15, reply, reply_size);
10191 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
10192 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
10193 reply_len = -1;
10194 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
10195 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
10196 reply_len = -1;
10197 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
10198 reply_len = wpa_supplicant_global_iface_list(
10199 wpa_s->global, reply, reply_size);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010200 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010201 reply_len = wpa_supplicant_global_iface_interfaces(
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010202 wpa_s->global, buf + 10, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010203 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
10204 reply_len = wpa_supplicant_ctrl_iface_bss(
10205 wpa_s, buf + 4, reply, reply_size);
10206#ifdef CONFIG_AP
10207 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
10208 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
10209 } else if (os_strncmp(buf, "STA ", 4) == 0) {
10210 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
10211 reply_size);
10212 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
10213 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
10214 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -070010215 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
10216 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
10217 reply_len = -1;
10218 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
10219 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
10220 reply_len = -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010221 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
10222 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
10223 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010224 } else if (os_strcmp(buf, "STOP_AP") == 0) {
10225 if (wpas_ap_stop_ap(wpa_s))
10226 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010227#endif /* CONFIG_AP */
10228 } else if (os_strcmp(buf, "SUSPEND") == 0) {
10229 wpas_notify_suspend(wpa_s->global);
10230 } else if (os_strcmp(buf, "RESUME") == 0) {
10231 wpas_notify_resume(wpa_s->global);
Dmitry Shmidt21de2142014-04-08 10:50:52 -070010232#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010233 } else if (os_strcmp(buf, "DROP_SA") == 0) {
10234 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
Dmitry Shmidt21de2142014-04-08 10:50:52 -070010235#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010236 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
10237 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
10238 reply_len = -1;
10239 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010240 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010241 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
10242 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
10243 reply_len = -1;
10244 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
10245 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
10246 buf + 17))
10247 reply_len = -1;
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -070010248 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010249 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010250#ifdef CONFIG_TDLS
10251 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
10252 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
10253 reply_len = -1;
10254 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
10255 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
10256 reply_len = -1;
10257 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
10258 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
10259 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010260 } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
10261 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
10262 buf + 17))
10263 reply_len = -1;
10264 } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
10265 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
10266 buf + 24))
10267 reply_len = -1;
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -070010268 } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) {
10269 reply_len = wpa_supplicant_ctrl_iface_tdls_link_status(
10270 wpa_s, buf + 17, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010271#endif /* CONFIG_TDLS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010272 } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
10273 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
10274 } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
10275 if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
10276 reply_len = -1;
10277 } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
10278 if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
10279 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010280 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
10281 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
10282 reply_size);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -080010283 } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
10284 if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
10285 reply_len = -1;
Yuhao Zhengfcd6f212012-07-27 10:37:52 -070010286 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
10287 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
10288 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -070010289#ifdef CONFIG_AUTOSCAN
10290 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
10291 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
10292 reply_len = -1;
10293#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010294 } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
10295 reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
10296 reply_size);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080010297#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -070010298 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
10299 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
10300 reply_size);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080010301#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010302 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
10303 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
10304 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010305 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080010306 pmksa_cache_clear_current(wpa_s->wpa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010307 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080010308#ifdef CONFIG_WNM
10309 } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
10310 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
10311 reply_len = -1;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080010312 } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
10313 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
Dmitry Shmidt44c95782013-05-17 09:51:35 -070010314 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080010315#endif /* CONFIG_WNM */
Dmitry Shmidt444d5672013-04-01 13:08:44 -070010316 } else if (os_strcmp(buf, "FLUSH") == 0) {
10317 wpa_supplicant_ctrl_iface_flush(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010318 } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
10319 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
10320 reply_size);
Dmitry Shmidt818ea482014-03-10 13:15:21 -070010321#ifdef CONFIG_TESTING_OPTIONS
10322 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
10323 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
10324 reply_len = -1;
10325 } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
10326 wpas_ctrl_iface_mgmt_tx_done(wpa_s);
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010327 } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
10328 if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
10329 reply_len = -1;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -070010330 } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
10331 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
10332 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010333 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
10334 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
10335 reply_len = -1;
10336 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
10337 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
10338 reply_len = -1;
10339 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
10340 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
10341 reply_len = -1;
10342 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
10343 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
10344 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010345 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
10346 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
10347 reply_len = -1;
10348 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
10349 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010350 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
10351 if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0)
10352 reply_len = -1;
10353 } else if (os_strcmp(buf, "GET_FAIL") == 0) {
10354 reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
Jouni Malinenc4818362015-10-04 11:45:13 +030010355 } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
10356 if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
10357 reply_len = -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -080010358 } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
10359 if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
10360 reply_len = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010361 } else if (os_strcmp(buf, "RESET_PN") == 0) {
10362 if (wpas_ctrl_reset_pn(wpa_s) < 0)
10363 reply_len = -1;
10364 } else if (os_strncmp(buf, "KEY_REQUEST ", 12) == 0) {
10365 if (wpas_ctrl_key_request(wpa_s, buf + 12) < 0)
10366 reply_len = -1;
10367 } else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
10368 if (wpas_ctrl_resend_assoc(wpa_s) < 0)
10369 reply_len = -1;
Dmitry Shmidt818ea482014-03-10 13:15:21 -070010370#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -070010371 } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
10372 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
10373 reply_len = -1;
10374 } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
10375 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
10376 reply_size);
10377 } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
10378 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
10379 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010380 } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010381 if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010382 reply_len = -1;
10383 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
10384 wpas_ctrl_iface_erp_flush(wpa_s);
10385 } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
10386 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
10387 reply_len = -1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010388 } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
10389 reply_len = wpas_ctrl_iface_get_pref_freq_list(
10390 wpa_s, buf + 19, reply, reply_size);
Paul Stewart092955c2017-02-06 09:13:09 -080010391#ifdef CONFIG_FILS
10392 } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) {
10393 if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17))
10394 reply_len = -1;
10395 } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
10396 wpas_flush_fils_hlp_req(wpa_s);
10397#endif /* CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010398#ifdef CONFIG_DPP
10399 } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
10400 int res;
10401
10402 res = wpas_dpp_qr_code(wpa_s, buf + 12);
10403 if (res < 0) {
10404 reply_len = -1;
10405 } else {
10406 reply_len = os_snprintf(reply, reply_size, "%d", res);
10407 if (os_snprintf_error(reply_size, reply_len))
10408 reply_len = -1;
10409 }
10410 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
10411 int res;
10412
10413 res = wpas_dpp_bootstrap_gen(wpa_s, buf + 18);
10414 if (res < 0) {
10415 reply_len = -1;
10416 } else {
10417 reply_len = os_snprintf(reply, reply_size, "%d", res);
10418 if (os_snprintf_error(reply_size, reply_len))
10419 reply_len = -1;
10420 }
10421 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
10422 if (wpas_dpp_bootstrap_remove(wpa_s, buf + 21) < 0)
10423 reply_len = -1;
10424 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
10425 const char *uri;
10426
10427 uri = wpas_dpp_bootstrap_get_uri(wpa_s, atoi(buf + 22));
10428 if (!uri) {
10429 reply_len = -1;
10430 } else {
10431 reply_len = os_snprintf(reply, reply_size, "%s", uri);
10432 if (os_snprintf_error(reply_size, reply_len))
10433 reply_len = -1;
10434 }
10435 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
10436 reply_len = wpas_dpp_bootstrap_info(wpa_s, atoi(buf + 19),
10437 reply, reply_size);
10438 } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
10439 if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
10440 reply_len = -1;
10441 } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
10442 if (wpas_dpp_listen(wpa_s, buf + 11) < 0)
10443 reply_len = -1;
10444 } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
10445 wpas_dpp_listen_stop(wpa_s);
10446 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
10447 int res;
10448
10449 res = wpas_dpp_configurator_add(wpa_s, buf + 20);
10450 if (res < 0) {
10451 reply_len = -1;
10452 } else {
10453 reply_len = os_snprintf(reply, reply_size, "%d", res);
10454 if (os_snprintf_error(reply_size, reply_len))
10455 reply_len = -1;
10456 }
10457 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
10458 if (wpas_dpp_configurator_remove(wpa_s, buf + 24) < 0)
10459 reply_len = -1;
10460 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
10461 if (wpas_dpp_configurator_sign(wpa_s, buf + 22) < 0)
10462 reply_len = -1;
10463 } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
10464 int res;
10465
10466 res = wpas_dpp_pkex_add(wpa_s, buf + 12);
10467 if (res < 0) {
10468 reply_len = -1;
10469 } else {
10470 reply_len = os_snprintf(reply, reply_size, "%d", res);
10471 if (os_snprintf_error(reply_size, reply_len))
10472 reply_len = -1;
10473 }
10474 } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
10475 if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0)
10476 reply_len = -1;
10477#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010478 } else {
10479 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
10480 reply_len = 16;
10481 }
10482
10483 if (reply_len < 0) {
10484 os_memcpy(reply, "FAIL\n", 5);
10485 reply_len = 5;
10486 }
10487
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010488 *resp_len = reply_len;
10489 return reply;
10490}
10491
10492
10493static int wpa_supplicant_global_iface_add(struct wpa_global *global,
10494 char *cmd)
10495{
10496 struct wpa_interface iface;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010497 char *pos, *extra;
10498 struct wpa_supplicant *wpa_s;
10499 unsigned int create_iface = 0;
10500 u8 mac_addr[ETH_ALEN];
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010501 enum wpa_driver_if_type type = WPA_IF_STATION;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010502
10503 /*
10504 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010505 * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010506 */
10507 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
10508
10509 os_memset(&iface, 0, sizeof(iface));
10510
10511 do {
10512 iface.ifname = pos = cmd;
10513 pos = os_strchr(pos, '\t');
10514 if (pos)
10515 *pos++ = '\0';
10516 if (iface.ifname[0] == '\0')
10517 return -1;
10518 if (pos == NULL)
10519 break;
10520
10521 iface.confname = pos;
10522 pos = os_strchr(pos, '\t');
10523 if (pos)
10524 *pos++ = '\0';
10525 if (iface.confname[0] == '\0')
10526 iface.confname = NULL;
10527 if (pos == NULL)
10528 break;
10529
10530 iface.driver = pos;
10531 pos = os_strchr(pos, '\t');
10532 if (pos)
10533 *pos++ = '\0';
10534 if (iface.driver[0] == '\0')
10535 iface.driver = NULL;
10536 if (pos == NULL)
10537 break;
10538
10539 iface.ctrl_interface = pos;
10540 pos = os_strchr(pos, '\t');
10541 if (pos)
10542 *pos++ = '\0';
10543 if (iface.ctrl_interface[0] == '\0')
10544 iface.ctrl_interface = NULL;
10545 if (pos == NULL)
10546 break;
10547
10548 iface.driver_param = pos;
10549 pos = os_strchr(pos, '\t');
10550 if (pos)
10551 *pos++ = '\0';
10552 if (iface.driver_param[0] == '\0')
10553 iface.driver_param = NULL;
10554 if (pos == NULL)
10555 break;
10556
10557 iface.bridge_ifname = pos;
10558 pos = os_strchr(pos, '\t');
10559 if (pos)
10560 *pos++ = '\0';
10561 if (iface.bridge_ifname[0] == '\0')
10562 iface.bridge_ifname = NULL;
10563 if (pos == NULL)
10564 break;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010565
10566 extra = pos;
10567 pos = os_strchr(pos, '\t');
10568 if (pos)
10569 *pos++ = '\0';
Dmitry Shmidt83474442015-04-15 13:47:09 -070010570 if (!extra[0])
10571 break;
10572
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010573 if (os_strcmp(extra, "create") == 0) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010574 create_iface = 1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010575 if (!pos)
10576 break;
10577
10578 if (os_strcmp(pos, "sta") == 0) {
10579 type = WPA_IF_STATION;
10580 } else if (os_strcmp(pos, "ap") == 0) {
10581 type = WPA_IF_AP_BSS;
10582 } else {
10583 wpa_printf(MSG_DEBUG,
10584 "INTERFACE_ADD unsupported interface type: '%s'",
10585 pos);
10586 return -1;
10587 }
10588 } else {
Dmitry Shmidt83474442015-04-15 13:47:09 -070010589 wpa_printf(MSG_DEBUG,
10590 "INTERFACE_ADD unsupported extra parameter: '%s'",
10591 extra);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010592 return -1;
Dmitry Shmidt83474442015-04-15 13:47:09 -070010593 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010594 } while (0);
10595
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010596 if (create_iface) {
10597 wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
10598 iface.ifname);
10599 if (!global->ifaces)
10600 return -1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010601 if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010602 NULL, NULL, NULL, mac_addr, NULL) < 0) {
10603 wpa_printf(MSG_ERROR,
10604 "CTRL_IFACE interface creation failed");
10605 return -1;
10606 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010607
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010608 wpa_printf(MSG_DEBUG,
10609 "CTRL_IFACE interface '%s' created with MAC addr: "
10610 MACSTR, iface.ifname, MAC2STR(mac_addr));
10611 }
10612
10613 if (wpa_supplicant_get_iface(global, iface.ifname))
10614 goto fail;
10615
10616 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
10617 if (!wpa_s)
10618 goto fail;
10619 wpa_s->added_vif = create_iface;
10620 return 0;
10621
10622fail:
10623 if (create_iface)
10624 wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
10625 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010626}
10627
10628
10629static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
10630 char *cmd)
10631{
10632 struct wpa_supplicant *wpa_s;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010633 int ret;
10634 unsigned int delete_iface;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010635
10636 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
10637
10638 wpa_s = wpa_supplicant_get_iface(global, cmd);
10639 if (wpa_s == NULL)
10640 return -1;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -070010641 delete_iface = wpa_s->added_vif;
10642 ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
10643 if (!ret && delete_iface) {
10644 wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
10645 cmd);
10646 ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
10647 }
10648 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010649}
10650
10651
10652static void wpa_free_iface_info(struct wpa_interface_info *iface)
10653{
10654 struct wpa_interface_info *prev;
10655
10656 while (iface) {
10657 prev = iface;
10658 iface = iface->next;
10659
10660 os_free(prev->ifname);
10661 os_free(prev->desc);
10662 os_free(prev);
10663 }
10664}
10665
10666
10667static int wpa_supplicant_global_iface_list(struct wpa_global *global,
10668 char *buf, int len)
10669{
10670 int i, res;
10671 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
10672 char *pos, *end;
10673
10674 for (i = 0; wpa_drivers[i]; i++) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070010675 const struct wpa_driver_ops *drv = wpa_drivers[i];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010676 if (drv->get_interfaces == NULL)
10677 continue;
10678 tmp = drv->get_interfaces(global->drv_priv[i]);
10679 if (tmp == NULL)
10680 continue;
10681
10682 if (last == NULL)
10683 iface = last = tmp;
10684 else
10685 last->next = tmp;
10686 while (last->next)
10687 last = last->next;
10688 }
10689
10690 pos = buf;
10691 end = buf + len;
10692 for (tmp = iface; tmp; tmp = tmp->next) {
10693 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
10694 tmp->drv_name, tmp->ifname,
10695 tmp->desc ? tmp->desc : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010696 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010697 *pos = '\0';
10698 break;
10699 }
10700 pos += res;
10701 }
10702
10703 wpa_free_iface_info(iface);
10704
10705 return pos - buf;
10706}
10707
10708
10709static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010710 const char *input,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010711 char *buf, int len)
10712{
10713 int res;
10714 char *pos, *end;
10715 struct wpa_supplicant *wpa_s;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010716 int show_ctrl = 0;
10717
10718 if (input)
10719 show_ctrl = !!os_strstr(input, "ctrl");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010720
10721 wpa_s = global->ifaces;
10722 pos = buf;
10723 end = buf + len;
10724
10725 while (wpa_s) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010726 if (show_ctrl)
10727 res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
10728 wpa_s->ifname,
10729 wpa_s->conf->ctrl_interface ?
10730 wpa_s->conf->ctrl_interface : "N/A");
10731 else
10732 res = os_snprintf(pos, end - pos, "%s\n",
10733 wpa_s->ifname);
10734
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010735 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010736 *pos = '\0';
10737 break;
10738 }
10739 pos += res;
10740 wpa_s = wpa_s->next;
10741 }
10742 return pos - buf;
10743}
10744
10745
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010746static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
10747 const char *ifname,
10748 char *cmd, size_t *resp_len)
10749{
10750 struct wpa_supplicant *wpa_s;
10751
10752 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
10753 if (os_strcmp(ifname, wpa_s->ifname) == 0)
10754 break;
10755 }
10756
10757 if (wpa_s == NULL) {
10758 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
10759 if (resp)
10760 *resp_len = os_strlen(resp);
10761 else
10762 *resp_len = 1;
10763 return resp;
10764 }
10765
10766 return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
10767}
10768
10769
10770static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
10771 char *buf, size_t *resp_len)
10772{
10773#ifdef CONFIG_P2P
10774 static const char * cmd[] = {
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -070010775 "LIST_NETWORKS",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010776 "P2P_FIND",
10777 "P2P_STOP_FIND",
10778 "P2P_LISTEN",
10779 "P2P_GROUP_ADD",
10780 "P2P_GET_PASSPHRASE",
10781 "P2P_SERVICE_UPDATE",
10782 "P2P_SERVICE_FLUSH",
10783 "P2P_FLUSH",
10784 "P2P_CANCEL",
10785 "P2P_PRESENCE_REQ",
10786 "P2P_EXT_LISTEN",
Paul Stewart092955c2017-02-06 09:13:09 -080010787#ifdef CONFIG_AP
10788 "STA-FIRST",
10789#endif /* CONFIG_AP */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010790 NULL
10791 };
10792 static const char * prefix[] = {
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -080010793#ifdef ANDROID
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -070010794 "DRIVER ",
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -080010795#endif /* ANDROID */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010796 "GET_CAPABILITY ",
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -070010797 "GET_NETWORK ",
10798 "REMOVE_NETWORK ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010799 "P2P_FIND ",
10800 "P2P_CONNECT ",
10801 "P2P_LISTEN ",
10802 "P2P_GROUP_REMOVE ",
10803 "P2P_GROUP_ADD ",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010804 "P2P_GROUP_MEMBER ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010805 "P2P_PROV_DISC ",
10806 "P2P_SERV_DISC_REQ ",
10807 "P2P_SERV_DISC_CANCEL_REQ ",
10808 "P2P_SERV_DISC_RESP ",
10809 "P2P_SERV_DISC_EXTERNAL ",
10810 "P2P_SERVICE_ADD ",
10811 "P2P_SERVICE_DEL ",
Dmitry Shmidt216983b2015-02-06 10:50:36 -080010812 "P2P_SERVICE_REP ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010813 "P2P_REJECT ",
10814 "P2P_INVITE ",
10815 "P2P_PEER ",
10816 "P2P_SET ",
10817 "P2P_UNAUTHORIZE ",
10818 "P2P_PRESENCE_REQ ",
10819 "P2P_EXT_LISTEN ",
Dmitry Shmidt391c59f2013-09-03 12:16:28 -070010820 "P2P_REMOVE_CLIENT ",
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080010821 "WPS_NFC_TOKEN ",
10822 "WPS_NFC_TAG_READ ",
Dmitry Shmidt413dde72014-04-11 10:23:22 -070010823 "NFC_GET_HANDOVER_SEL ",
10824 "NFC_GET_HANDOVER_REQ ",
10825 "NFC_REPORT_HANDOVER ",
Dmitry Shmidt216983b2015-02-06 10:50:36 -080010826 "P2P_ASP_PROVISION ",
10827 "P2P_ASP_PROVISION_RESP ",
Paul Stewart092955c2017-02-06 09:13:09 -080010828#ifdef CONFIG_AP
10829 "STA ",
10830 "STA-NEXT ",
10831#endif /* CONFIG_AP */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010832 NULL
10833 };
10834 int found = 0;
10835 int i;
10836
10837 if (global->p2p_init_wpa_s == NULL)
10838 return NULL;
10839
10840 for (i = 0; !found && cmd[i]; i++) {
10841 if (os_strcmp(buf, cmd[i]) == 0)
10842 found = 1;
10843 }
10844
10845 for (i = 0; !found && prefix[i]; i++) {
10846 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
10847 found = 1;
10848 }
10849
10850 if (found)
10851 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
10852 buf, resp_len);
10853#endif /* CONFIG_P2P */
10854 return NULL;
10855}
10856
10857
10858static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
10859 char *buf, size_t *resp_len)
10860{
10861#ifdef CONFIG_WIFI_DISPLAY
10862 if (global->p2p_init_wpa_s == NULL)
10863 return NULL;
10864 if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
10865 os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
10866 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
10867 buf, resp_len);
10868#endif /* CONFIG_WIFI_DISPLAY */
10869 return NULL;
10870}
10871
10872
10873static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
10874 char *buf, size_t *resp_len)
10875{
10876 char *ret;
10877
10878 ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
10879 if (ret)
10880 return ret;
10881
10882 ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
10883 if (ret)
10884 return ret;
10885
10886 return NULL;
10887}
10888
10889
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010890static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
10891{
10892 char *value;
10893
10894 value = os_strchr(cmd, ' ');
10895 if (value == NULL)
10896 return -1;
10897 *value++ = '\0';
10898
10899 wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
10900
10901#ifdef CONFIG_WIFI_DISPLAY
10902 if (os_strcasecmp(cmd, "wifi_display") == 0) {
10903 wifi_display_enable(global, !!atoi(value));
10904 return 0;
10905 }
10906#endif /* CONFIG_WIFI_DISPLAY */
10907
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010908 /* Restore cmd to its original value to allow redirection */
10909 value[-1] = ' ';
10910
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010911 return -1;
10912}
10913
10914
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010915static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global,
10916 char *cmd)
10917{
10918 struct wpa_supplicant *wpa_s[2]; /* src, dst */
10919 char *p;
10920 unsigned int i;
10921
10922 /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id>
10923 * <variable name> */
10924
10925 for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) {
10926 p = os_strchr(cmd, ' ');
10927 if (p == NULL)
10928 return -1;
10929 *p = '\0';
10930
10931 wpa_s[i] = global->ifaces;
10932 for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) {
10933 if (os_strcmp(cmd, wpa_s[i]->ifname) == 0)
10934 break;
10935 }
10936
10937 if (!wpa_s[i]) {
10938 wpa_printf(MSG_DEBUG,
10939 "CTRL_IFACE: Could not find iface=%s", cmd);
10940 return -1;
10941 }
10942
10943 cmd = p + 1;
10944 }
10945
10946 return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]);
10947}
10948
10949
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010950#ifndef CONFIG_NO_CONFIG_WRITE
10951static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
10952{
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010953 int ret = 0, saved = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010954 struct wpa_supplicant *wpa_s;
10955
10956 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
10957 if (!wpa_s->conf->update_config) {
10958 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
10959 continue;
10960 }
10961
10962 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
10963 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
10964 ret = 1;
10965 } else {
10966 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010967 saved++;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010968 }
10969 }
10970
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010971 if (!saved && !ret) {
10972 wpa_dbg(wpa_s, MSG_DEBUG,
10973 "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
10974 ret = 1;
10975 }
10976
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010977 return ret;
10978}
10979#endif /* CONFIG_NO_CONFIG_WRITE */
10980
10981
10982static int wpas_global_ctrl_iface_status(struct wpa_global *global,
10983 char *buf, size_t buflen)
10984{
10985 char *pos, *end;
10986 int ret;
10987 struct wpa_supplicant *wpa_s;
10988
10989 pos = buf;
10990 end = buf + buflen;
10991
10992#ifdef CONFIG_P2P
10993 if (global->p2p && !global->p2p_disabled) {
10994 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
10995 "\n"
10996 "p2p_state=%s\n",
10997 MAC2STR(global->p2p_dev_addr),
10998 p2p_get_state_txt(global->p2p));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010999 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011000 return pos - buf;
11001 pos += ret;
11002 } else if (global->p2p) {
11003 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011004 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011005 return pos - buf;
11006 pos += ret;
11007 }
11008#endif /* CONFIG_P2P */
11009
11010#ifdef CONFIG_WIFI_DISPLAY
11011 ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
11012 !!global->wifi_display);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011013 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011014 return pos - buf;
11015 pos += ret;
11016#endif /* CONFIG_WIFI_DISPLAY */
11017
11018 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
11019 ret = os_snprintf(pos, end - pos, "ifname=%s\n"
11020 "address=" MACSTR "\n",
11021 wpa_s->ifname, MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011022 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011023 return pos - buf;
11024 pos += ret;
11025 }
11026
11027 return pos - buf;
11028}
11029
11030
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011031#ifdef CONFIG_FST
11032
11033static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global,
11034 char *cmd, char *buf,
11035 size_t reply_size)
11036{
11037 char ifname[IFNAMSIZ + 1];
11038 struct fst_iface_cfg cfg;
11039 struct wpa_supplicant *wpa_s;
11040 struct fst_wpa_obj iface_obj;
11041
11042 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
11043 wpa_s = wpa_supplicant_get_iface(global, ifname);
11044 if (wpa_s) {
11045 if (wpa_s->fst) {
11046 wpa_printf(MSG_INFO, "FST: Already attached");
11047 return -1;
11048 }
11049 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
11050 wpa_s->fst = fst_attach(ifname, wpa_s->own_addr,
11051 &iface_obj, &cfg);
11052 if (wpa_s->fst)
11053 return os_snprintf(buf, reply_size, "OK\n");
11054 }
11055 }
11056
11057 return -1;
11058}
11059
11060
11061static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global,
11062 char *cmd, char *buf,
11063 size_t reply_size)
11064{
11065 char ifname[IFNAMSIZ + 1];
11066 struct wpa_supplicant *wpa_s;
11067
11068 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
11069 wpa_s = wpa_supplicant_get_iface(global, ifname);
11070 if (wpa_s) {
11071 if (!fst_iface_detach(ifname)) {
11072 wpa_s->fst = NULL;
11073 return os_snprintf(buf, reply_size, "OK\n");
11074 }
11075 }
11076 }
11077
11078 return -1;
11079}
11080
11081#endif /* CONFIG_FST */
11082
11083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011084char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
11085 char *buf, size_t *resp_len)
11086{
11087 char *reply;
11088 const int reply_size = 2048;
11089 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011090 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011091
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070011092 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
11093 char *pos = os_strchr(buf + 7, ' ');
11094 if (pos) {
11095 *pos++ = '\0';
11096 return wpas_global_ctrl_iface_ifname(global,
11097 buf + 7, pos,
11098 resp_len);
11099 }
11100 }
11101
11102 reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
11103 if (reply)
11104 return reply;
11105
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011106 if (os_strcmp(buf, "PING") == 0)
11107 level = MSG_EXCESSIVE;
11108 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011109 (const u8 *) buf, os_strlen(buf));
11110
11111 reply = os_malloc(reply_size);
11112 if (reply == NULL) {
11113 *resp_len = 1;
11114 return NULL;
11115 }
11116
11117 os_memcpy(reply, "OK\n", 3);
11118 reply_len = 3;
11119
11120 if (os_strcmp(buf, "PING") == 0) {
11121 os_memcpy(reply, "PONG\n", 5);
11122 reply_len = 5;
11123 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
11124 if (wpa_supplicant_global_iface_add(global, buf + 14))
11125 reply_len = -1;
11126 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
11127 if (wpa_supplicant_global_iface_remove(global, buf + 17))
11128 reply_len = -1;
11129 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
11130 reply_len = wpa_supplicant_global_iface_list(
11131 global, reply, reply_size);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080011132 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011133 reply_len = wpa_supplicant_global_iface_interfaces(
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080011134 global, buf + 10, reply, reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011135#ifdef CONFIG_FST
11136 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
11137 reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
11138 reply,
11139 reply_size);
11140 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
11141 reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11,
11142 reply,
11143 reply_size);
11144 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
11145 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
11146#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011147 } else if (os_strcmp(buf, "TERMINATE") == 0) {
11148 wpa_supplicant_terminate_proc(global);
11149 } else if (os_strcmp(buf, "SUSPEND") == 0) {
11150 wpas_notify_suspend(global);
11151 } else if (os_strcmp(buf, "RESUME") == 0) {
11152 wpas_notify_resume(global);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011153 } else if (os_strncmp(buf, "SET ", 4) == 0) {
Dmitry Shmidt61593f02014-04-21 16:27:35 -070011154 if (wpas_global_ctrl_iface_set(global, buf + 4)) {
11155#ifdef CONFIG_P2P
11156 if (global->p2p_init_wpa_s) {
11157 os_free(reply);
11158 /* Check if P2P redirection would work for this
11159 * command. */
11160 return wpa_supplicant_ctrl_iface_process(
11161 global->p2p_init_wpa_s,
11162 buf, resp_len);
11163 }
11164#endif /* CONFIG_P2P */
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011165 reply_len = -1;
Dmitry Shmidt61593f02014-04-21 16:27:35 -070011166 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011167 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
11168 if (wpas_global_ctrl_iface_dup_network(global, buf + 12))
11169 reply_len = -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011170#ifndef CONFIG_NO_CONFIG_WRITE
11171 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
11172 if (wpas_global_ctrl_iface_save_config(global))
11173 reply_len = -1;
11174#endif /* CONFIG_NO_CONFIG_WRITE */
11175 } else if (os_strcmp(buf, "STATUS") == 0) {
11176 reply_len = wpas_global_ctrl_iface_status(global, reply,
11177 reply_size);
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -080011178#ifdef CONFIG_MODULE_TESTS
11179 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -080011180 if (wpas_module_tests() < 0)
11181 reply_len = -1;
11182#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011183 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
11184 if (wpa_debug_reopen_file() < 0)
11185 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011186 } else {
11187 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
11188 reply_len = 16;
11189 }
11190
11191 if (reply_len < 0) {
11192 os_memcpy(reply, "FAIL\n", 5);
11193 reply_len = 5;
11194 }
11195
11196 *resp_len = reply_len;
11197 return reply;
11198}