blob: a7549437468eb1249db328ac636a69d8343b0ad1 [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 Shmidt8d520ff2011-05-09 14:06:53 -070055
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056static int wpa_supplicant_global_iface_list(struct wpa_global *global,
57 char *buf, int len);
58static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080059 const char *input,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070060 char *buf, int len);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -070061static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
62 char *val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063
Dmitry Shmidt04949592012-07-19 12:16:46 -070064static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
65{
66 char *pos;
67 u8 addr[ETH_ALEN], *filter = NULL, *n;
68 size_t count = 0;
69
70 pos = val;
71 while (pos) {
72 if (*pos == '\0')
73 break;
74 if (hwaddr_aton(pos, addr)) {
75 os_free(filter);
76 return -1;
77 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070078 n = os_realloc_array(filter, count + 1, ETH_ALEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -070079 if (n == NULL) {
80 os_free(filter);
81 return -1;
82 }
83 filter = n;
84 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
85 count++;
86
87 pos = os_strchr(pos, ' ');
88 if (pos)
89 pos++;
90 }
91
92 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
93 os_free(wpa_s->bssid_filter);
94 wpa_s->bssid_filter = filter;
95 wpa_s->bssid_filter_count = count;
96
97 return 0;
98}
99
100
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800101static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
102{
103 char *pos;
104 u8 addr[ETH_ALEN], *bssid = NULL, *n;
105 struct wpa_ssid_value *ssid = NULL, *ns;
106 size_t count = 0, ssid_count = 0;
107 struct wpa_ssid *c;
108
109 /*
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800110 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800111 * SSID_SPEC ::= ssid <SSID_HEX>
112 * BSSID_SPEC ::= bssid <BSSID_HEX>
113 */
114
115 pos = val;
116 while (pos) {
117 if (*pos == '\0')
118 break;
119 if (os_strncmp(pos, "bssid ", 6) == 0) {
120 int res;
121 pos += 6;
122 res = hwaddr_aton2(pos, addr);
123 if (res < 0) {
124 os_free(ssid);
125 os_free(bssid);
126 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
127 "BSSID value '%s'", pos);
128 return -1;
129 }
130 pos += res;
131 n = os_realloc_array(bssid, count + 1, ETH_ALEN);
132 if (n == NULL) {
133 os_free(ssid);
134 os_free(bssid);
135 return -1;
136 }
137 bssid = n;
138 os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
139 count++;
140 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
141 char *end;
142 pos += 5;
143
144 end = pos;
145 while (*end) {
146 if (*end == '\0' || *end == ' ')
147 break;
148 end++;
149 }
150
151 ns = os_realloc_array(ssid, ssid_count + 1,
152 sizeof(struct wpa_ssid_value));
153 if (ns == NULL) {
154 os_free(ssid);
155 os_free(bssid);
156 return -1;
157 }
158 ssid = ns;
159
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700160 if ((end - pos) & 0x01 ||
161 end - pos > 2 * SSID_MAX_LEN ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800162 hexstr2bin(pos, ssid[ssid_count].ssid,
163 (end - pos) / 2) < 0) {
164 os_free(ssid);
165 os_free(bssid);
166 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
167 "SSID value '%s'", pos);
168 return -1;
169 }
170 ssid[ssid_count].ssid_len = (end - pos) / 2;
171 wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
172 ssid[ssid_count].ssid,
173 ssid[ssid_count].ssid_len);
174 ssid_count++;
175 pos = end;
176 } else {
177 wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
178 "'%s'", pos);
179 os_free(ssid);
180 os_free(bssid);
181 return -1;
182 }
183
184 pos = os_strchr(pos, ' ');
185 if (pos)
186 pos++;
187 }
188
189 wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
190 os_free(wpa_s->disallow_aps_bssid);
191 wpa_s->disallow_aps_bssid = bssid;
192 wpa_s->disallow_aps_bssid_count = count;
193
194 wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
195 os_free(wpa_s->disallow_aps_ssid);
196 wpa_s->disallow_aps_ssid = ssid;
197 wpa_s->disallow_aps_ssid_count = ssid_count;
198
199 if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
200 return 0;
201
202 c = wpa_s->current_ssid;
203 if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
204 return 0;
205
206 if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
207 !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
208 return 0;
209
210 wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
211 "because current AP was marked disallowed");
212
213#ifdef CONFIG_SME
214 wpa_s->sme.prev_bssid_set = 0;
215#endif /* CONFIG_SME */
216 wpa_s->reassociate = 1;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800217 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800218 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
219 wpa_supplicant_req_scan(wpa_s, 0, 0);
220
221 return 0;
222}
223
224
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700225#ifndef CONFIG_NO_CONFIG_BLOBS
226static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
227{
228 char *name = pos;
229 struct wpa_config_blob *blob;
230 size_t len;
231
232 pos = os_strchr(pos, ' ');
233 if (pos == NULL)
234 return -1;
235 *pos++ = '\0';
236 len = os_strlen(pos);
237 if (len & 1)
238 return -1;
239
240 wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
241 blob = os_zalloc(sizeof(*blob));
242 if (blob == NULL)
243 return -1;
244 blob->name = os_strdup(name);
245 blob->data = os_malloc(len / 2);
246 if (blob->name == NULL || blob->data == NULL) {
247 wpa_config_free_blob(blob);
248 return -1;
249 }
250
251 if (hexstr2bin(pos, blob->data, len / 2) < 0) {
252 wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
253 wpa_config_free_blob(blob);
254 return -1;
255 }
256 blob->len = len / 2;
257
258 wpa_config_set_blob(wpa_s->conf, blob);
259
260 return 0;
261}
262#endif /* CONFIG_NO_CONFIG_BLOBS */
263
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700264
265static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
266{
267 char *params;
268 char *pos;
269 int *freqs = NULL;
270 int ret;
271
272 if (atoi(cmd)) {
273 params = os_strchr(cmd, ' ');
274 os_free(wpa_s->manual_sched_scan_freqs);
275 if (params) {
276 params++;
277 pos = os_strstr(params, "freq=");
278 if (pos)
279 freqs = freq_range_to_channel_list(wpa_s,
280 pos + 5);
281 }
282 wpa_s->manual_sched_scan_freqs = freqs;
283 ret = wpas_start_pno(wpa_s);
284 } else {
285 ret = wpas_stop_pno(wpa_s);
286 }
287 return ret;
288}
289
290
Ravi Joshie6ccb162015-07-16 17:45:41 -0700291static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
292{
293 union wpa_event_data event;
294
295 if (os_strcmp(band, "AUTO") == 0)
296 wpa_s->setband = WPA_SETBAND_AUTO;
297 else if (os_strcmp(band, "5G") == 0)
298 wpa_s->setband = WPA_SETBAND_5G;
299 else if (os_strcmp(band, "2G") == 0)
300 wpa_s->setband = WPA_SETBAND_2G;
301 else
302 return -1;
303
304 if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
305 os_memset(&event, 0, sizeof(event));
306 event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
307 event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
308 wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event);
309 }
310
311 return 0;
312}
313
314
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700315static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
316 const char *cmd)
317{
318 struct wpabuf *lci;
319
320 if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
321 wpabuf_free(wpa_s->lci);
322 wpa_s->lci = NULL;
323 return 0;
324 }
325
326 lci = wpabuf_parse_bin(cmd);
327 if (!lci)
328 return -1;
329
330 if (os_get_reltime(&wpa_s->lci_time)) {
331 wpabuf_free(lci);
332 return -1;
333 }
334
335 wpabuf_free(wpa_s->lci);
336 wpa_s->lci = lci;
337
338 return 0;
339}
340
341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
343 char *cmd)
344{
345 char *value;
346 int ret = 0;
347
348 value = os_strchr(cmd, ' ');
349 if (value == NULL)
350 return -1;
351 *value++ = '\0';
352
353 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
354 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
355 eapol_sm_configure(wpa_s->eapol,
356 atoi(value), -1, -1, -1);
357 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
358 eapol_sm_configure(wpa_s->eapol,
359 -1, atoi(value), -1, -1);
360 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
361 eapol_sm_configure(wpa_s->eapol,
362 -1, -1, atoi(value), -1);
363 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
364 eapol_sm_configure(wpa_s->eapol,
365 -1, -1, -1, atoi(value));
366 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
367 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
368 atoi(value)))
369 ret = -1;
370 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
371 0) {
372 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
373 atoi(value)))
374 ret = -1;
375 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
376 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
377 ret = -1;
378 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
379 wpa_s->wps_fragment_size = atoi(value);
380#ifdef CONFIG_WPS_TESTING
381 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
382 long int val;
383 val = strtol(value, NULL, 0);
384 if (val < 0 || val > 0xff) {
385 ret = -1;
386 wpa_printf(MSG_DEBUG, "WPS: Invalid "
387 "wps_version_number %ld", val);
388 } else {
389 wps_version_number = val;
390 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
391 "version %u.%u",
392 (wps_version_number & 0xf0) >> 4,
393 wps_version_number & 0x0f);
394 }
395 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
396 wps_testing_dummy_cred = atoi(value);
397 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
398 wps_testing_dummy_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800399 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
400 wps_corrupt_pkhash = atoi(value);
401 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
402 wps_corrupt_pkhash);
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800403 } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
404 if (value[0] == '\0') {
405 wps_force_auth_types_in_use = 0;
406 } else {
407 wps_force_auth_types = strtol(value, NULL, 0);
408 wps_force_auth_types_in_use = 1;
409 }
410 } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
411 if (value[0] == '\0') {
412 wps_force_encr_types_in_use = 0;
413 } else {
414 wps_force_encr_types = strtol(value, NULL, 0);
415 wps_force_encr_types_in_use = 1;
416 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417#endif /* CONFIG_WPS_TESTING */
418 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
419 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
420 ret = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800421#ifdef CONFIG_TDLS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700422#ifdef CONFIG_TDLS_TESTING
423 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700424 tdls_testing = strtol(value, NULL, 0);
425 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
426#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700427 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
428 int disabled = atoi(value);
429 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
430 if (disabled) {
431 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
432 ret = -1;
433 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
434 ret = -1;
435 wpa_tdls_enable(wpa_s->wpa, !disabled);
436#endif /* CONFIG_TDLS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800437 } else if (os_strcasecmp(cmd, "pno") == 0) {
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700438 ret = wpas_ctrl_pno(wpa_s, value);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700439 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
440 int disabled = atoi(value);
441 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
442 ret = -1;
443 else if (disabled)
444 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
445 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
446 if (os_strcmp(value, "disable") == 0)
447 wpa_s->set_sta_uapsd = 0;
448 else {
449 int be, bk, vi, vo;
450 char *pos;
451 /* format: BE,BK,VI,VO;max SP Length */
452 be = atoi(value);
453 pos = os_strchr(value, ',');
454 if (pos == NULL)
455 return -1;
456 pos++;
457 bk = atoi(pos);
458 pos = os_strchr(pos, ',');
459 if (pos == NULL)
460 return -1;
461 pos++;
462 vi = atoi(pos);
463 pos = os_strchr(pos, ',');
464 if (pos == NULL)
465 return -1;
466 pos++;
467 vo = atoi(pos);
468 /* ignore max SP Length for now */
469
470 wpa_s->set_sta_uapsd = 1;
471 wpa_s->sta_uapsd = 0;
472 if (be)
473 wpa_s->sta_uapsd |= BIT(0);
474 if (bk)
475 wpa_s->sta_uapsd |= BIT(1);
476 if (vi)
477 wpa_s->sta_uapsd |= BIT(2);
478 if (vo)
479 wpa_s->sta_uapsd |= BIT(3);
480 }
Jouni Malinen21d6bc82012-04-10 16:17:59 -0700481 } else if (os_strcasecmp(cmd, "ps") == 0) {
482 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700483#ifdef CONFIG_WIFI_DISPLAY
484 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800485 int enabled = !!atoi(value);
486 if (enabled && !wpa_s->global->p2p)
487 ret = -1;
488 else
489 wifi_display_enable(wpa_s->global, enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700490#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700491 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
492 ret = set_bssid_filter(wpa_s, value);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800493 } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
494 ret = set_disallow_aps(wpa_s, value);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800495 } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
496 wpa_s->no_keep_alive = !!atoi(value);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700497#ifdef CONFIG_TESTING_OPTIONS
498 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
499 wpa_s->ext_mgmt_frame_handling = !!atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800500 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
501 wpa_s->ext_eapol_frame_io = !!atoi(value);
502#ifdef CONFIG_AP
503 if (wpa_s->ap_iface) {
504 wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
505 wpa_s->ext_eapol_frame_io;
506 }
507#endif /* CONFIG_AP */
508 } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
509 wpa_s->extra_roc_dur = atoi(value);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800510 } else if (os_strcasecmp(cmd, "test_failure") == 0) {
511 wpa_s->test_failure = atoi(value);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800512 } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
513 wpa_s->p2p_go_csa_on_inv = !!atoi(value);
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700514 } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
515 wpa_s->ignore_auth_resp = !!atoi(value);
516 } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
517 wpa_s->ignore_assoc_disallow = !!atoi(value);
518 } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
519 wpa_s->reject_btm_req_reason = atoi(value);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700520#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700521#ifndef CONFIG_NO_CONFIG_BLOBS
522 } else if (os_strcmp(cmd, "blob") == 0) {
523 ret = wpas_ctrl_set_blob(wpa_s, value);
524#endif /* CONFIG_NO_CONFIG_BLOBS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800525 } else if (os_strcasecmp(cmd, "setband") == 0) {
Ravi Joshie6ccb162015-07-16 17:45:41 -0700526 ret = wpas_ctrl_set_band(wpa_s, value);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800527#ifdef CONFIG_MBO
528 } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
529 ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
530 } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
531 wpas_mbo_update_cell_capa(wpa_s, atoi(value));
532#endif /* CONFIG_MBO */
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700533 } else if (os_strcasecmp(cmd, "lci") == 0) {
534 ret = wpas_ctrl_iface_set_lci(wpa_s, value);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800535 } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) {
536 ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700537 } else {
538 value[-1] = '=';
539 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
540 if (ret == 0)
541 wpa_supplicant_update_config(wpa_s);
542 }
543
544 return ret;
545}
546
547
548static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
549 char *cmd, char *buf, size_t buflen)
550{
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700551 int res = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700552
553 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
554
555 if (os_strcmp(cmd, "version") == 0) {
556 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700557 } else if (os_strcasecmp(cmd, "country") == 0) {
558 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
559 res = os_snprintf(buf, buflen, "%c%c",
560 wpa_s->conf->country[0],
561 wpa_s->conf->country[1]);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700562#ifdef CONFIG_WIFI_DISPLAY
563 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800564 int enabled;
565 if (wpa_s->global->p2p == NULL ||
566 wpa_s->global->p2p_disabled)
567 enabled = 0;
568 else
569 enabled = wpa_s->global->wifi_display;
570 res = os_snprintf(buf, buflen, "%d", enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700571#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700572#ifdef CONFIG_TESTING_GET_GTK
573 } else if (os_strcmp(cmd, "gtk") == 0) {
574 if (wpa_s->last_gtk_len == 0)
575 return -1;
576 res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
577 wpa_s->last_gtk_len);
578 return res;
579#endif /* CONFIG_TESTING_GET_GTK */
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800580 } else if (os_strcmp(cmd, "tls_library") == 0) {
581 res = tls_get_library_version(buf, buflen);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800582 } else {
583 res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700584 }
585
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800586 if (os_snprintf_error(buflen, res))
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700587 return -1;
588 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700589}
590
591
592#ifdef IEEE8021X_EAPOL
593static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
594 char *addr)
595{
596 u8 bssid[ETH_ALEN];
597 struct wpa_ssid *ssid = wpa_s->current_ssid;
598
599 if (hwaddr_aton(addr, bssid)) {
600 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
601 "'%s'", addr);
602 return -1;
603 }
604
605 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
606 rsn_preauth_deinit(wpa_s->wpa);
607 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
608 return -1;
609
610 return 0;
611}
612#endif /* IEEE8021X_EAPOL */
613
614
615#ifdef CONFIG_PEERKEY
616/* MLME-STKSTART.request(peer) */
617static int wpa_supplicant_ctrl_iface_stkstart(
618 struct wpa_supplicant *wpa_s, char *addr)
619{
620 u8 peer[ETH_ALEN];
621
622 if (hwaddr_aton(addr, peer)) {
623 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
624 "address '%s'", addr);
625 return -1;
626 }
627
628 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
629 MAC2STR(peer));
630
631 return wpa_sm_stkstart(wpa_s->wpa, peer);
632}
633#endif /* CONFIG_PEERKEY */
634
635
636#ifdef CONFIG_TDLS
637
638static int wpa_supplicant_ctrl_iface_tdls_discover(
639 struct wpa_supplicant *wpa_s, char *addr)
640{
641 u8 peer[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800642 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643
644 if (hwaddr_aton(addr, peer)) {
645 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
646 "address '%s'", addr);
647 return -1;
648 }
649
650 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
651 MAC2STR(peer));
652
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800653 if (wpa_tdls_is_external_setup(wpa_s->wpa))
654 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
655 else
656 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
657
658 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700659}
660
661
662static int wpa_supplicant_ctrl_iface_tdls_setup(
663 struct wpa_supplicant *wpa_s, char *addr)
664{
665 u8 peer[ETH_ALEN];
666 int ret;
667
668 if (hwaddr_aton(addr, peer)) {
669 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
670 "address '%s'", addr);
671 return -1;
672 }
673
674 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
675 MAC2STR(peer));
676
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800677 if ((wpa_s->conf->tdls_external_control) &&
678 wpa_tdls_is_external_setup(wpa_s->wpa))
679 return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
680
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800681 wpa_tdls_remove(wpa_s->wpa, peer);
682
683 if (wpa_tdls_is_external_setup(wpa_s->wpa))
684 ret = wpa_tdls_start(wpa_s->wpa, peer);
685 else
686 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800687
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700688 return ret;
689}
690
691
692static int wpa_supplicant_ctrl_iface_tdls_teardown(
693 struct wpa_supplicant *wpa_s, char *addr)
694{
695 u8 peer[ETH_ALEN];
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700696 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700697
Dmitry Shmidt43cb5782014-06-16 16:23:22 -0700698 if (os_strcmp(addr, "*") == 0) {
699 /* remove everyone */
700 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
701 wpa_tdls_teardown_peers(wpa_s->wpa);
702 return 0;
703 }
704
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700705 if (hwaddr_aton(addr, peer)) {
706 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
707 "address '%s'", addr);
708 return -1;
709 }
710
711 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
712 MAC2STR(peer));
713
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800714 if ((wpa_s->conf->tdls_external_control) &&
715 wpa_tdls_is_external_setup(wpa_s->wpa))
716 return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
717
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700718 if (wpa_tdls_is_external_setup(wpa_s->wpa))
719 ret = wpa_tdls_teardown_link(
720 wpa_s->wpa, peer,
721 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
722 else
723 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
724
725 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700726}
727
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700728
729static int ctrl_iface_get_capability_tdls(
730 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
731{
732 int ret;
733
734 ret = os_snprintf(buf, buflen, "%s\n",
735 wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
736 (wpa_s->drv_flags &
737 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
738 "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800739 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700740 return -1;
741 return ret;
742}
743
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800744
745static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
746 struct wpa_supplicant *wpa_s, char *cmd)
747{
748 u8 peer[ETH_ALEN];
749 struct hostapd_freq_params freq_params;
750 u8 oper_class;
751 char *pos, *end;
752
753 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
754 wpa_printf(MSG_INFO,
755 "tdls_chanswitch: Only supported with external setup");
756 return -1;
757 }
758
759 os_memset(&freq_params, 0, sizeof(freq_params));
760
761 pos = os_strchr(cmd, ' ');
762 if (pos == NULL)
763 return -1;
764 *pos++ = '\0';
765
766 oper_class = strtol(pos, &end, 10);
767 if (pos == end) {
768 wpa_printf(MSG_INFO,
769 "tdls_chanswitch: Invalid op class provided");
770 return -1;
771 }
772
773 pos = end;
774 freq_params.freq = atoi(pos);
775 if (freq_params.freq == 0) {
776 wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
777 return -1;
778 }
779
780#define SET_FREQ_SETTING(str) \
781 do { \
782 const char *pos2 = os_strstr(pos, " " #str "="); \
783 if (pos2) { \
784 pos2 += sizeof(" " #str "=") - 1; \
785 freq_params.str = atoi(pos2); \
786 } \
787 } while (0)
788
789 SET_FREQ_SETTING(center_freq1);
790 SET_FREQ_SETTING(center_freq2);
791 SET_FREQ_SETTING(bandwidth);
792 SET_FREQ_SETTING(sec_channel_offset);
793#undef SET_FREQ_SETTING
794
795 freq_params.ht_enabled = !!os_strstr(pos, " ht");
796 freq_params.vht_enabled = !!os_strstr(pos, " vht");
797
798 if (hwaddr_aton(cmd, peer)) {
799 wpa_printf(MSG_DEBUG,
800 "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
801 cmd);
802 return -1;
803 }
804
805 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
806 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
807 MAC2STR(peer), oper_class, freq_params.freq,
808 freq_params.center_freq1, freq_params.center_freq2,
809 freq_params.bandwidth, freq_params.sec_channel_offset,
810 freq_params.ht_enabled ? " HT" : "",
811 freq_params.vht_enabled ? " VHT" : "");
812
813 return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
814 &freq_params);
815}
816
817
818static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
819 struct wpa_supplicant *wpa_s, char *cmd)
820{
821 u8 peer[ETH_ALEN];
822
823 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
824 wpa_printf(MSG_INFO,
825 "tdls_chanswitch: Only supported with external setup");
826 return -1;
827 }
828
829 if (hwaddr_aton(cmd, peer)) {
830 wpa_printf(MSG_DEBUG,
831 "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
832 cmd);
833 return -1;
834 }
835
836 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
837 MAC2STR(peer));
838
839 return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
840}
841
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -0700842
843static int wpa_supplicant_ctrl_iface_tdls_link_status(
844 struct wpa_supplicant *wpa_s, const char *addr,
845 char *buf, size_t buflen)
846{
847 u8 peer[ETH_ALEN];
848 const char *tdls_status;
849 int ret;
850
851 if (hwaddr_aton(addr, peer)) {
852 wpa_printf(MSG_DEBUG,
853 "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'",
854 addr);
855 return -1;
856 }
857 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR,
858 MAC2STR(peer));
859
860 tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
861 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status);
862 ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status);
863 if (os_snprintf_error(buflen, ret))
864 return -1;
865
866 return ret;
867}
868
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700869#endif /* CONFIG_TDLS */
870
871
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800872static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
873{
874 char *token, *context = NULL;
875 struct wmm_ac_ts_setup_params params = {
876 .tsid = 0xff,
877 .direction = 0xff,
878 };
879
880 while ((token = str_token(cmd, " ", &context))) {
881 if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
882 sscanf(token, "up=%i", &params.user_priority) == 1 ||
883 sscanf(token, "nominal_msdu_size=%i",
884 &params.nominal_msdu_size) == 1 ||
885 sscanf(token, "mean_data_rate=%i",
886 &params.mean_data_rate) == 1 ||
887 sscanf(token, "min_phy_rate=%i",
888 &params.minimum_phy_rate) == 1 ||
889 sscanf(token, "sba=%i",
890 &params.surplus_bandwidth_allowance) == 1)
891 continue;
892
893 if (os_strcasecmp(token, "downlink") == 0) {
894 params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
895 } else if (os_strcasecmp(token, "uplink") == 0) {
896 params.direction = WMM_TSPEC_DIRECTION_UPLINK;
897 } else if (os_strcasecmp(token, "bidi") == 0) {
898 params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
899 } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
900 params.fixed_nominal_msdu = 1;
901 } else {
902 wpa_printf(MSG_DEBUG,
903 "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
904 token);
905 return -1;
906 }
907
908 }
909
910 return wpas_wmm_ac_addts(wpa_s, &params);
911}
912
913
914static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
915{
916 u8 tsid = atoi(cmd);
917
918 return wpas_wmm_ac_delts(wpa_s, tsid);
919}
920
921
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700922#ifdef CONFIG_IEEE80211R
923static int wpa_supplicant_ctrl_iface_ft_ds(
924 struct wpa_supplicant *wpa_s, char *addr)
925{
926 u8 target_ap[ETH_ALEN];
927 struct wpa_bss *bss;
928 const u8 *mdie;
929
930 if (hwaddr_aton(addr, target_ap)) {
931 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
932 "address '%s'", addr);
933 return -1;
934 }
935
936 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
937
938 bss = wpa_bss_get_bssid(wpa_s, target_ap);
939 if (bss)
940 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
941 else
942 mdie = NULL;
943
944 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
945}
946#endif /* CONFIG_IEEE80211R */
947
948
949#ifdef CONFIG_WPS
950static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
951 char *cmd)
952{
953 u8 bssid[ETH_ALEN], *_bssid = bssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700954#ifdef CONFIG_P2P
955 u8 p2p_dev_addr[ETH_ALEN];
956#endif /* CONFIG_P2P */
957#ifdef CONFIG_AP
958 u8 *_p2p_dev_addr = NULL;
959#endif /* CONFIG_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800960
Dmitry Shmidtc0a8db02013-11-08 11:18:33 -0800961 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700962 _bssid = NULL;
963#ifdef CONFIG_P2P
964 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
965 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
966 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
967 "P2P Device Address '%s'",
968 cmd + 13);
969 return -1;
970 }
971 _p2p_dev_addr = p2p_dev_addr;
972#endif /* CONFIG_P2P */
973 } else if (hwaddr_aton(cmd, bssid)) {
974 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
975 cmd);
976 return -1;
977 }
978
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800979#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700980 if (wpa_s->ap_iface)
981 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
982#endif /* CONFIG_AP */
983
984 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
985}
986
987
988static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
989 char *cmd, char *buf,
990 size_t buflen)
991{
992 u8 bssid[ETH_ALEN], *_bssid = bssid;
993 char *pin;
994 int ret;
995
996 pin = os_strchr(cmd, ' ');
997 if (pin)
998 *pin++ = '\0';
999
1000 if (os_strcmp(cmd, "any") == 0)
1001 _bssid = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001002 else if (os_strcmp(cmd, "get") == 0) {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001003 if (wps_generate_pin((unsigned int *) &ret) < 0)
1004 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001005 goto done;
1006 } else if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001007 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
1008 cmd);
1009 return -1;
1010 }
1011
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001012#ifdef CONFIG_AP
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001013 if (wpa_s->ap_iface) {
1014 int timeout = 0;
1015 char *pos;
1016
1017 if (pin) {
1018 pos = os_strchr(pin, ' ');
1019 if (pos) {
1020 *pos++ = '\0';
1021 timeout = atoi(pos);
1022 }
1023 }
1024
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001025 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001026 buf, buflen, timeout);
1027 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001028#endif /* CONFIG_AP */
1029
1030 if (pin) {
1031 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
1032 DEV_PW_DEFAULT);
1033 if (ret < 0)
1034 return -1;
1035 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001036 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001037 return -1;
1038 return ret;
1039 }
1040
1041 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
1042 if (ret < 0)
1043 return -1;
1044
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001045done:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001046 /* Return the generated PIN */
1047 ret = os_snprintf(buf, buflen, "%08d", ret);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001048 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001049 return -1;
1050 return ret;
1051}
1052
1053
1054static int wpa_supplicant_ctrl_iface_wps_check_pin(
1055 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1056{
1057 char pin[9];
1058 size_t len;
1059 char *pos;
1060 int ret;
1061
1062 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
1063 (u8 *) cmd, os_strlen(cmd));
1064 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
1065 if (*pos < '0' || *pos > '9')
1066 continue;
1067 pin[len++] = *pos;
1068 if (len == 9) {
1069 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
1070 return -1;
1071 }
1072 }
1073 if (len != 4 && len != 8) {
1074 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
1075 return -1;
1076 }
1077 pin[len] = '\0';
1078
1079 if (len == 8) {
1080 unsigned int pin_val;
1081 pin_val = atoi(pin);
1082 if (!wps_pin_valid(pin_val)) {
1083 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
1084 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001085 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086 return -1;
1087 return ret;
1088 }
1089 }
1090
1091 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001092 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001093 return -1;
1094
1095 return ret;
1096}
1097
1098
Dmitry Shmidt04949592012-07-19 12:16:46 -07001099#ifdef CONFIG_WPS_NFC
1100
1101static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
1102 char *cmd)
1103{
1104 u8 bssid[ETH_ALEN], *_bssid = bssid;
1105
1106 if (cmd == NULL || cmd[0] == '\0')
1107 _bssid = NULL;
1108 else if (hwaddr_aton(cmd, bssid))
1109 return -1;
1110
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001111 return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
1112 0, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001113}
1114
1115
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001116static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
1117 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1118{
1119 int ndef;
1120 struct wpabuf *buf;
1121 int res;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001122 char *pos;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001123
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001124 pos = os_strchr(cmd, ' ');
1125 if (pos)
1126 *pos++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001127 if (os_strcmp(cmd, "WPS") == 0)
1128 ndef = 0;
1129 else if (os_strcmp(cmd, "NDEF") == 0)
1130 ndef = 1;
1131 else
1132 return -1;
1133
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001134 buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001135 if (buf == NULL)
1136 return -1;
1137
1138 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1139 wpabuf_len(buf));
1140 reply[res++] = '\n';
1141 reply[res] = '\0';
1142
1143 wpabuf_free(buf);
1144
1145 return res;
1146}
1147
1148
Dmitry Shmidt04949592012-07-19 12:16:46 -07001149static int wpa_supplicant_ctrl_iface_wps_nfc_token(
1150 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1151{
1152 int ndef;
1153 struct wpabuf *buf;
1154 int res;
1155
1156 if (os_strcmp(cmd, "WPS") == 0)
1157 ndef = 0;
1158 else if (os_strcmp(cmd, "NDEF") == 0)
1159 ndef = 1;
1160 else
1161 return -1;
1162
1163 buf = wpas_wps_nfc_token(wpa_s, ndef);
1164 if (buf == NULL)
1165 return -1;
1166
1167 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1168 wpabuf_len(buf));
1169 reply[res++] = '\n';
1170 reply[res] = '\0';
1171
1172 wpabuf_free(buf);
1173
1174 return res;
1175}
1176
1177
1178static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
1179 struct wpa_supplicant *wpa_s, char *pos)
1180{
1181 size_t len;
1182 struct wpabuf *buf;
1183 int ret;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001184 char *freq;
1185 int forced_freq = 0;
1186
1187 freq = strstr(pos, " freq=");
1188 if (freq) {
1189 *freq = '\0';
1190 freq += 6;
1191 forced_freq = atoi(freq);
1192 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001193
1194 len = os_strlen(pos);
1195 if (len & 0x01)
1196 return -1;
1197 len /= 2;
1198
1199 buf = wpabuf_alloc(len);
1200 if (buf == NULL)
1201 return -1;
1202 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
1203 wpabuf_free(buf);
1204 return -1;
1205 }
1206
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001207 ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001208 wpabuf_free(buf);
1209
1210 return ret;
1211}
1212
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001213
1214static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001215 char *reply, size_t max_len,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001216 int ndef)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001217{
1218 struct wpabuf *buf;
1219 int res;
1220
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001221 buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001222 if (buf == NULL)
1223 return -1;
1224
1225 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1226 wpabuf_len(buf));
1227 reply[res++] = '\n';
1228 reply[res] = '\0';
1229
1230 wpabuf_free(buf);
1231
1232 return res;
1233}
1234
1235
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001236#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001237static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
1238 char *reply, size_t max_len,
1239 int ndef)
1240{
1241 struct wpabuf *buf;
1242 int res;
1243
1244 buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
1245 if (buf == NULL) {
1246 wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
1247 return -1;
1248 }
1249
1250 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1251 wpabuf_len(buf));
1252 reply[res++] = '\n';
1253 reply[res] = '\0';
1254
1255 wpabuf_free(buf);
1256
1257 return res;
1258}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001259#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001260
1261
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001262static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
1263 char *cmd, char *reply,
1264 size_t max_len)
1265{
1266 char *pos;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001267 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001268
1269 pos = os_strchr(cmd, ' ');
1270 if (pos == NULL)
1271 return -1;
1272 *pos++ = '\0';
1273
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001274 if (os_strcmp(cmd, "WPS") == 0)
1275 ndef = 0;
1276 else if (os_strcmp(cmd, "NDEF") == 0)
1277 ndef = 1;
1278 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001279 return -1;
1280
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001281 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001282 if (!ndef)
1283 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001284 return wpas_ctrl_nfc_get_handover_req_wps(
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001285 wpa_s, reply, max_len, ndef);
1286 }
1287
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001288#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001289 if (os_strcmp(pos, "P2P-CR") == 0) {
1290 return wpas_ctrl_nfc_get_handover_req_p2p(
1291 wpa_s, reply, max_len, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001292 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001293#endif /* CONFIG_P2P */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001294
1295 return -1;
1296}
1297
1298
1299static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001300 char *reply, size_t max_len,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001301 int ndef, int cr, char *uuid)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001302{
1303 struct wpabuf *buf;
1304 int res;
1305
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001306 buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001307 if (buf == NULL)
1308 return -1;
1309
1310 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1311 wpabuf_len(buf));
1312 reply[res++] = '\n';
1313 reply[res] = '\0';
1314
1315 wpabuf_free(buf);
1316
1317 return res;
1318}
1319
1320
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001321#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001322static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
1323 char *reply, size_t max_len,
1324 int ndef, int tag)
1325{
1326 struct wpabuf *buf;
1327 int res;
1328
1329 buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
1330 if (buf == NULL)
1331 return -1;
1332
1333 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1334 wpabuf_len(buf));
1335 reply[res++] = '\n';
1336 reply[res] = '\0';
1337
1338 wpabuf_free(buf);
1339
1340 return res;
1341}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001342#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001343
1344
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001345static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
1346 char *cmd, char *reply,
1347 size_t max_len)
1348{
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001349 char *pos, *pos2;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001350 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001351
1352 pos = os_strchr(cmd, ' ');
1353 if (pos == NULL)
1354 return -1;
1355 *pos++ = '\0';
1356
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001357 if (os_strcmp(cmd, "WPS") == 0)
1358 ndef = 0;
1359 else if (os_strcmp(cmd, "NDEF") == 0)
1360 ndef = 1;
1361 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001362 return -1;
1363
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001364 pos2 = os_strchr(pos, ' ');
1365 if (pos2)
1366 *pos2++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001367 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001368 if (!ndef)
1369 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001370 return wpas_ctrl_nfc_get_handover_sel_wps(
1371 wpa_s, reply, max_len, ndef,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001372 os_strcmp(pos, "WPS-CR") == 0, pos2);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001373 }
1374
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001375#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001376 if (os_strcmp(pos, "P2P-CR") == 0) {
1377 return wpas_ctrl_nfc_get_handover_sel_p2p(
1378 wpa_s, reply, max_len, ndef, 0);
1379 }
1380
1381 if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
1382 return wpas_ctrl_nfc_get_handover_sel_p2p(
1383 wpa_s, reply, max_len, ndef, 1);
1384 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001385#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001386
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001387 return -1;
1388}
1389
1390
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001391static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
1392 char *cmd)
1393{
1394 size_t len;
1395 struct wpabuf *req, *sel;
1396 int ret;
1397 char *pos, *role, *type, *pos2;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001398#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001399 char *freq;
1400 int forced_freq = 0;
1401
1402 freq = strstr(cmd, " freq=");
1403 if (freq) {
1404 *freq = '\0';
1405 freq += 6;
1406 forced_freq = atoi(freq);
1407 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001408#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001409
1410 role = cmd;
1411 pos = os_strchr(role, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001412 if (pos == NULL) {
1413 wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001414 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001415 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001416 *pos++ = '\0';
1417
1418 type = pos;
1419 pos = os_strchr(type, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001420 if (pos == NULL) {
1421 wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001422 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001423 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001424 *pos++ = '\0';
1425
1426 pos2 = os_strchr(pos, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001427 if (pos2 == NULL) {
1428 wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001429 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001430 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001431 *pos2++ = '\0';
1432
1433 len = os_strlen(pos);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001434 if (len & 0x01) {
1435 wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001436 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001437 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001438 len /= 2;
1439
1440 req = wpabuf_alloc(len);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001441 if (req == NULL) {
1442 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001443 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001444 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001445 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001446 wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001447 wpabuf_free(req);
1448 return -1;
1449 }
1450
1451 len = os_strlen(pos2);
1452 if (len & 0x01) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001453 wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001454 wpabuf_free(req);
1455 return -1;
1456 }
1457 len /= 2;
1458
1459 sel = wpabuf_alloc(len);
1460 if (sel == NULL) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001461 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001462 wpabuf_free(req);
1463 return -1;
1464 }
1465 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001466 wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001467 wpabuf_free(req);
1468 wpabuf_free(sel);
1469 return -1;
1470 }
1471
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001472 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
1473 role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
1474
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001475 if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
1476 ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001477#ifdef CONFIG_AP
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001478 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
1479 {
1480 ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
1481 if (ret < 0)
1482 ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001483#endif /* CONFIG_AP */
1484#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001485 } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
1486 {
1487 ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
1488 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
1489 {
1490 ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
1491 forced_freq);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001492#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001493 } else {
1494 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
1495 "reported: role=%s type=%s", role, type);
1496 ret = -1;
1497 }
1498 wpabuf_free(req);
1499 wpabuf_free(sel);
1500
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001501 if (ret)
1502 wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
1503
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001504 return ret;
1505}
1506
Dmitry Shmidt04949592012-07-19 12:16:46 -07001507#endif /* CONFIG_WPS_NFC */
1508
1509
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001510static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
1511 char *cmd)
1512{
1513 u8 bssid[ETH_ALEN];
1514 char *pin;
1515 char *new_ssid;
1516 char *new_auth;
1517 char *new_encr;
1518 char *new_key;
1519 struct wps_new_ap_settings ap;
1520
1521 pin = os_strchr(cmd, ' ');
1522 if (pin == NULL)
1523 return -1;
1524 *pin++ = '\0';
1525
1526 if (hwaddr_aton(cmd, bssid)) {
1527 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1528 cmd);
1529 return -1;
1530 }
1531
1532 new_ssid = os_strchr(pin, ' ');
1533 if (new_ssid == NULL)
1534 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
1535 *new_ssid++ = '\0';
1536
1537 new_auth = os_strchr(new_ssid, ' ');
1538 if (new_auth == NULL)
1539 return -1;
1540 *new_auth++ = '\0';
1541
1542 new_encr = os_strchr(new_auth, ' ');
1543 if (new_encr == NULL)
1544 return -1;
1545 *new_encr++ = '\0';
1546
1547 new_key = os_strchr(new_encr, ' ');
1548 if (new_key == NULL)
1549 return -1;
1550 *new_key++ = '\0';
1551
1552 os_memset(&ap, 0, sizeof(ap));
1553 ap.ssid_hex = new_ssid;
1554 ap.auth = new_auth;
1555 ap.encr = new_encr;
1556 ap.key_hex = new_key;
1557 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1558}
1559
1560
1561#ifdef CONFIG_AP
1562static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1563 char *cmd, char *buf,
1564 size_t buflen)
1565{
1566 int timeout = 300;
1567 char *pos;
1568 const char *pin_txt;
1569
1570 if (!wpa_s->ap_iface)
1571 return -1;
1572
1573 pos = os_strchr(cmd, ' ');
1574 if (pos)
1575 *pos++ = '\0';
1576
1577 if (os_strcmp(cmd, "disable") == 0) {
1578 wpas_wps_ap_pin_disable(wpa_s);
1579 return os_snprintf(buf, buflen, "OK\n");
1580 }
1581
1582 if (os_strcmp(cmd, "random") == 0) {
1583 if (pos)
1584 timeout = atoi(pos);
1585 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1586 if (pin_txt == NULL)
1587 return -1;
1588 return os_snprintf(buf, buflen, "%s", pin_txt);
1589 }
1590
1591 if (os_strcmp(cmd, "get") == 0) {
1592 pin_txt = wpas_wps_ap_pin_get(wpa_s);
1593 if (pin_txt == NULL)
1594 return -1;
1595 return os_snprintf(buf, buflen, "%s", pin_txt);
1596 }
1597
1598 if (os_strcmp(cmd, "set") == 0) {
1599 char *pin;
1600 if (pos == NULL)
1601 return -1;
1602 pin = pos;
1603 pos = os_strchr(pos, ' ');
1604 if (pos) {
1605 *pos++ = '\0';
1606 timeout = atoi(pos);
1607 }
1608 if (os_strlen(pin) > buflen)
1609 return -1;
1610 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1611 return -1;
1612 return os_snprintf(buf, buflen, "%s", pin);
1613 }
1614
1615 return -1;
1616}
1617#endif /* CONFIG_AP */
1618
1619
1620#ifdef CONFIG_WPS_ER
1621static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1622 char *cmd)
1623{
1624 char *uuid = cmd, *pin, *pos;
1625 u8 addr_buf[ETH_ALEN], *addr = NULL;
1626 pin = os_strchr(uuid, ' ');
1627 if (pin == NULL)
1628 return -1;
1629 *pin++ = '\0';
1630 pos = os_strchr(pin, ' ');
1631 if (pos) {
1632 *pos++ = '\0';
1633 if (hwaddr_aton(pos, addr_buf) == 0)
1634 addr = addr_buf;
1635 }
1636 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1637}
1638
1639
1640static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1641 char *cmd)
1642{
1643 char *uuid = cmd, *pin;
1644 pin = os_strchr(uuid, ' ');
1645 if (pin == NULL)
1646 return -1;
1647 *pin++ = '\0';
1648 return wpas_wps_er_learn(wpa_s, uuid, pin);
1649}
1650
1651
1652static int wpa_supplicant_ctrl_iface_wps_er_set_config(
1653 struct wpa_supplicant *wpa_s, char *cmd)
1654{
1655 char *uuid = cmd, *id;
1656 id = os_strchr(uuid, ' ');
1657 if (id == NULL)
1658 return -1;
1659 *id++ = '\0';
1660 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1661}
1662
1663
1664static int wpa_supplicant_ctrl_iface_wps_er_config(
1665 struct wpa_supplicant *wpa_s, char *cmd)
1666{
1667 char *pin;
1668 char *new_ssid;
1669 char *new_auth;
1670 char *new_encr;
1671 char *new_key;
1672 struct wps_new_ap_settings ap;
1673
1674 pin = os_strchr(cmd, ' ');
1675 if (pin == NULL)
1676 return -1;
1677 *pin++ = '\0';
1678
1679 new_ssid = os_strchr(pin, ' ');
1680 if (new_ssid == NULL)
1681 return -1;
1682 *new_ssid++ = '\0';
1683
1684 new_auth = os_strchr(new_ssid, ' ');
1685 if (new_auth == NULL)
1686 return -1;
1687 *new_auth++ = '\0';
1688
1689 new_encr = os_strchr(new_auth, ' ');
1690 if (new_encr == NULL)
1691 return -1;
1692 *new_encr++ = '\0';
1693
1694 new_key = os_strchr(new_encr, ' ');
1695 if (new_key == NULL)
1696 return -1;
1697 *new_key++ = '\0';
1698
1699 os_memset(&ap, 0, sizeof(ap));
1700 ap.ssid_hex = new_ssid;
1701 ap.auth = new_auth;
1702 ap.encr = new_encr;
1703 ap.key_hex = new_key;
1704 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1705}
Dmitry Shmidt04949592012-07-19 12:16:46 -07001706
1707
1708#ifdef CONFIG_WPS_NFC
1709static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1710 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1711{
1712 int ndef;
1713 struct wpabuf *buf;
1714 int res;
1715 char *uuid;
1716
1717 uuid = os_strchr(cmd, ' ');
1718 if (uuid == NULL)
1719 return -1;
1720 *uuid++ = '\0';
1721
1722 if (os_strcmp(cmd, "WPS") == 0)
1723 ndef = 0;
1724 else if (os_strcmp(cmd, "NDEF") == 0)
1725 ndef = 1;
1726 else
1727 return -1;
1728
1729 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1730 if (buf == NULL)
1731 return -1;
1732
1733 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1734 wpabuf_len(buf));
1735 reply[res++] = '\n';
1736 reply[res] = '\0';
1737
1738 wpabuf_free(buf);
1739
1740 return res;
1741}
1742#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001743#endif /* CONFIG_WPS_ER */
1744
1745#endif /* CONFIG_WPS */
1746
1747
1748#ifdef CONFIG_IBSS_RSN
1749static int wpa_supplicant_ctrl_iface_ibss_rsn(
1750 struct wpa_supplicant *wpa_s, char *addr)
1751{
1752 u8 peer[ETH_ALEN];
1753
1754 if (hwaddr_aton(addr, peer)) {
1755 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1756 "address '%s'", addr);
1757 return -1;
1758 }
1759
1760 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1761 MAC2STR(peer));
1762
1763 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1764}
1765#endif /* CONFIG_IBSS_RSN */
1766
1767
1768static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1769 char *rsp)
1770{
1771#ifdef IEEE8021X_EAPOL
1772 char *pos, *id_pos;
1773 int id;
1774 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001775
1776 pos = os_strchr(rsp, '-');
1777 if (pos == NULL)
1778 return -1;
1779 *pos++ = '\0';
1780 id_pos = pos;
1781 pos = os_strchr(pos, ':');
1782 if (pos == NULL)
1783 return -1;
1784 *pos++ = '\0';
1785 id = atoi(id_pos);
1786 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1787 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1788 (u8 *) pos, os_strlen(pos));
1789
1790 ssid = wpa_config_get_network(wpa_s->conf, id);
1791 if (ssid == NULL) {
1792 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1793 "to update", id);
1794 return -1;
1795 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001796
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001797 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1798 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001799#else /* IEEE8021X_EAPOL */
1800 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1801 return -1;
1802#endif /* IEEE8021X_EAPOL */
1803}
1804
1805
1806static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1807 const char *params,
1808 char *buf, size_t buflen)
1809{
1810 char *pos, *end, tmp[30];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001811 int res, verbose, wps, ret;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001812#ifdef CONFIG_HS20
1813 const u8 *hs20;
1814#endif /* CONFIG_HS20 */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001815 const u8 *sess_id;
1816 size_t sess_id_len;
Dmitry Shmidt44da0252011-08-23 12:30:30 -07001817
Dmitry Shmidt56052862013-10-04 10:23:25 -07001818 if (os_strcmp(params, "-DRIVER") == 0)
1819 return wpa_drv_status(wpa_s, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001820 verbose = os_strcmp(params, "-VERBOSE") == 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001821 wps = os_strcmp(params, "-WPS") == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001822 pos = buf;
1823 end = buf + buflen;
1824 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1825 struct wpa_ssid *ssid = wpa_s->current_ssid;
1826 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1827 MAC2STR(wpa_s->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001828 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001829 return pos - buf;
1830 pos += ret;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001831 ret = os_snprintf(pos, end - pos, "freq=%u\n",
1832 wpa_s->assoc_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001833 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001834 return pos - buf;
1835 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001836 if (ssid) {
1837 u8 *_ssid = ssid->ssid;
1838 size_t ssid_len = ssid->ssid_len;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001839 u8 ssid_buf[SSID_MAX_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001840 if (ssid_len == 0) {
1841 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1842 if (_res < 0)
1843 ssid_len = 0;
1844 else
1845 ssid_len = _res;
1846 _ssid = ssid_buf;
1847 }
1848 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1849 wpa_ssid_txt(_ssid, ssid_len),
1850 ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001851 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001852 return pos - buf;
1853 pos += ret;
1854
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001855 if (wps && ssid->passphrase &&
1856 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1857 (ssid->mode == WPAS_MODE_AP ||
1858 ssid->mode == WPAS_MODE_P2P_GO)) {
1859 ret = os_snprintf(pos, end - pos,
1860 "passphrase=%s\n",
1861 ssid->passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001862 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001863 return pos - buf;
1864 pos += ret;
1865 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001866 if (ssid->id_str) {
1867 ret = os_snprintf(pos, end - pos,
1868 "id_str=%s\n",
1869 ssid->id_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001870 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001871 return pos - buf;
1872 pos += ret;
1873 }
1874
1875 switch (ssid->mode) {
1876 case WPAS_MODE_INFRA:
1877 ret = os_snprintf(pos, end - pos,
1878 "mode=station\n");
1879 break;
1880 case WPAS_MODE_IBSS:
1881 ret = os_snprintf(pos, end - pos,
1882 "mode=IBSS\n");
1883 break;
1884 case WPAS_MODE_AP:
1885 ret = os_snprintf(pos, end - pos,
1886 "mode=AP\n");
1887 break;
1888 case WPAS_MODE_P2P_GO:
1889 ret = os_snprintf(pos, end - pos,
1890 "mode=P2P GO\n");
1891 break;
1892 case WPAS_MODE_P2P_GROUP_FORMATION:
1893 ret = os_snprintf(pos, end - pos,
1894 "mode=P2P GO - group "
1895 "formation\n");
1896 break;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07001897 case WPAS_MODE_MESH:
1898 ret = os_snprintf(pos, end - pos,
1899 "mode=mesh\n");
1900 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901 default:
1902 ret = 0;
1903 break;
1904 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001905 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001906 return pos - buf;
1907 pos += ret;
1908 }
1909
1910#ifdef CONFIG_AP
1911 if (wpa_s->ap_iface) {
1912 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1913 end - pos,
1914 verbose);
1915 } else
1916#endif /* CONFIG_AP */
1917 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1918 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001919#ifdef CONFIG_SAE
1920 if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001921#ifdef CONFIG_AP
1922 !wpa_s->ap_iface &&
1923#endif /* CONFIG_AP */
1924 wpa_s->sme.sae.state == SAE_ACCEPTED) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001925 ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
1926 wpa_s->sme.sae.group);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001927 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001928 return pos - buf;
1929 pos += ret;
1930 }
1931#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001932 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1933 wpa_supplicant_state_txt(wpa_s->wpa_state));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001934 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001935 return pos - buf;
1936 pos += ret;
1937
1938 if (wpa_s->l2 &&
1939 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1940 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001941 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001942 return pos - buf;
1943 pos += ret;
1944 }
1945
1946#ifdef CONFIG_P2P
1947 if (wpa_s->global->p2p) {
1948 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1949 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001950 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001951 return pos - buf;
1952 pos += ret;
1953 }
1954#endif /* CONFIG_P2P */
1955
1956 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1957 MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001958 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001959 return pos - buf;
1960 pos += ret;
1961
Dmitry Shmidt04949592012-07-19 12:16:46 -07001962#ifdef CONFIG_HS20
1963 if (wpa_s->current_bss &&
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001964 (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
1965 HS20_IE_VENDOR_TYPE)) &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001966 wpa_s->wpa_proto == WPA_PROTO_RSN &&
1967 wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001968 int release = 1;
1969 if (hs20[1] >= 5) {
1970 u8 rel_num = (hs20[6] & 0xf0) >> 4;
1971 release = rel_num + 1;
1972 }
1973 ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001974 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07001975 return pos - buf;
1976 pos += ret;
1977 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001978
1979 if (wpa_s->current_ssid) {
1980 struct wpa_cred *cred;
1981 char *type;
1982
1983 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07001984 size_t i;
1985
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001986 if (wpa_s->current_ssid->parent_cred != cred)
1987 continue;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001988
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001989 if (cred->provisioning_sp) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07001990 ret = os_snprintf(pos, end - pos,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001991 "provisioning_sp=%s\n",
1992 cred->provisioning_sp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001993 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt051af732013-10-22 13:52:46 -07001994 return pos - buf;
1995 pos += ret;
1996 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001997
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001998 if (!cred->domain)
1999 goto no_domain;
2000
2001 i = 0;
2002 if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
2003 struct wpabuf *names =
2004 wpa_s->current_bss->anqp->domain_name;
2005 for (i = 0; names && i < cred->num_domain; i++)
2006 {
2007 if (domain_name_list_contains(
2008 names, cred->domain[i], 1))
2009 break;
2010 }
2011 if (i == cred->num_domain)
2012 i = 0; /* show first entry by default */
2013 }
2014 ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
2015 cred->domain[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002016 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002017 return pos - buf;
2018 pos += ret;
2019
2020 no_domain:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002021 if (wpa_s->current_bss == NULL ||
2022 wpa_s->current_bss->anqp == NULL)
2023 res = -1;
2024 else
2025 res = interworking_home_sp_cred(
2026 wpa_s, cred,
2027 wpa_s->current_bss->anqp->domain_name);
2028 if (res > 0)
2029 type = "home";
2030 else if (res == 0)
2031 type = "roaming";
2032 else
2033 type = "unknown";
2034
2035 ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002036 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002037 return pos - buf;
2038 pos += ret;
2039
2040 break;
2041 }
2042 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002043#endif /* CONFIG_HS20 */
2044
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002045 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
2046 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
2047 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
2048 verbose);
2049 if (res >= 0)
2050 pos += res;
2051 }
2052
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002053 sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
2054 if (sess_id) {
2055 char *start = pos;
2056
2057 ret = os_snprintf(pos, end - pos, "eap_session_id=");
2058 if (os_snprintf_error(end - pos, ret))
2059 return start - buf;
2060 pos += ret;
2061 ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
2062 if (ret <= 0)
2063 return start - buf;
2064 pos += ret;
2065 ret = os_snprintf(pos, end - pos, "\n");
2066 if (os_snprintf_error(end - pos, ret))
2067 return start - buf;
2068 pos += ret;
2069 }
2070
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002071 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
2072 if (res >= 0)
2073 pos += res;
2074
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002075#ifdef CONFIG_WPS
2076 {
2077 char uuid_str[100];
2078 uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
2079 ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002080 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002081 return pos - buf;
2082 pos += ret;
2083 }
2084#endif /* CONFIG_WPS */
2085
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08002086#ifdef ANDROID
vandwalleffc70182014-09-11 11:40:14 -07002087 /*
2088 * Allow using the STATUS command with default behavior, say for debug,
2089 * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
2090 * events with STATUS-NO_EVENTS.
2091 */
2092 if (os_strcmp(params, "-NO_EVENTS")) {
2093 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
2094 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
2095 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
2096 wpa_s->wpa_state,
2097 MAC2STR(wpa_s->bssid),
2098 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
2099 wpa_ssid_txt(wpa_s->current_ssid->ssid,
2100 wpa_s->current_ssid->ssid_len) : "");
2101 if (wpa_s->wpa_state == WPA_COMPLETED) {
2102 struct wpa_ssid *ssid = wpa_s->current_ssid;
2103 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
2104 "- connection to " MACSTR
2105 " completed %s [id=%d id_str=%s]",
2106 MAC2STR(wpa_s->bssid), "(auth)",
2107 ssid ? ssid->id : -1,
2108 ssid && ssid->id_str ? ssid->id_str : "");
2109 }
Irfan Sheriffbf5edf42012-01-11 16:54:57 -08002110 }
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08002111#endif /* ANDROID */
2112
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002113 return pos - buf;
2114}
2115
2116
2117static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
2118 char *cmd)
2119{
2120 char *pos;
2121 int id;
2122 struct wpa_ssid *ssid;
2123 u8 bssid[ETH_ALEN];
2124
2125 /* cmd: "<network id> <BSSID>" */
2126 pos = os_strchr(cmd, ' ');
2127 if (pos == NULL)
2128 return -1;
2129 *pos++ = '\0';
2130 id = atoi(cmd);
2131 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
2132 if (hwaddr_aton(pos, bssid)) {
2133 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
2134 return -1;
2135 }
2136
2137 ssid = wpa_config_get_network(wpa_s->conf, id);
2138 if (ssid == NULL) {
2139 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2140 "to update", id);
2141 return -1;
2142 }
2143
2144 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
2145 ssid->bssid_set = !is_zero_ether_addr(bssid);
2146
2147 return 0;
2148}
2149
2150
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002151static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002152 char *cmd, char *buf,
2153 size_t buflen)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002154{
2155 u8 bssid[ETH_ALEN];
2156 struct wpa_blacklist *e;
2157 char *pos, *end;
2158 int ret;
2159
2160 /* cmd: "BLACKLIST [<BSSID>]" */
2161 if (*cmd == '\0') {
2162 pos = buf;
2163 end = buf + buflen;
2164 e = wpa_s->blacklist;
2165 while (e) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002166 ret = os_snprintf(pos, end - pos, MACSTR "\n",
2167 MAC2STR(e->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002168 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002169 return pos - buf;
2170 pos += ret;
2171 e = e->next;
2172 }
2173 return pos - buf;
2174 }
2175
2176 cmd++;
2177 if (os_strncmp(cmd, "clear", 5) == 0) {
2178 wpa_blacklist_clear(wpa_s);
2179 os_memcpy(buf, "OK\n", 3);
2180 return 3;
2181 }
2182
2183 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
2184 if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002185 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002186 return -1;
2187 }
2188
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002189 /*
2190 * Add the BSSID twice, so its count will be 2, causing it to be
2191 * skipped when processing scan results.
2192 */
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002193 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002194 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002195 return -1;
2196 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002197 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002198 return -1;
2199 os_memcpy(buf, "OK\n", 3);
2200 return 3;
2201}
2202
2203
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002204static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
2205 char *cmd, char *buf,
2206 size_t buflen)
2207{
2208 char *pos, *end, *stamp;
2209 int ret;
2210
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002211 /* cmd: "LOG_LEVEL [<level>]" */
2212 if (*cmd == '\0') {
2213 pos = buf;
2214 end = buf + buflen;
2215 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2216 "Timestamp: %d\n",
2217 debug_level_str(wpa_debug_level),
2218 wpa_debug_timestamp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002219 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002220 ret = 0;
2221
2222 return ret;
2223 }
2224
2225 while (*cmd == ' ')
2226 cmd++;
2227
2228 stamp = os_strchr(cmd, ' ');
2229 if (stamp) {
2230 *stamp++ = '\0';
2231 while (*stamp == ' ') {
2232 stamp++;
2233 }
2234 }
2235
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002236 if (os_strlen(cmd)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002237 int level = str_to_debug_level(cmd);
2238 if (level < 0)
2239 return -1;
2240 wpa_debug_level = level;
2241 }
2242
2243 if (stamp && os_strlen(stamp))
2244 wpa_debug_timestamp = atoi(stamp);
2245
2246 os_memcpy(buf, "OK\n", 3);
2247 return 3;
2248}
2249
2250
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002251static int wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002252 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002253{
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002254 char *pos, *end, *prev;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002255 struct wpa_ssid *ssid;
2256 int ret;
2257
2258 pos = buf;
2259 end = buf + buflen;
2260 ret = os_snprintf(pos, end - pos,
2261 "network id / ssid / bssid / flags\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002262 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002263 return pos - buf;
2264 pos += ret;
2265
2266 ssid = wpa_s->conf->ssid;
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002267
2268 /* skip over ssids until we find next one */
2269 if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
2270 int last_id = atoi(cmd + 8);
2271 if (last_id != -1) {
2272 while (ssid != NULL && ssid->id <= last_id) {
2273 ssid = ssid->next;
2274 }
2275 }
2276 }
2277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002278 while (ssid) {
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002279 prev = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002280 ret = os_snprintf(pos, end - pos, "%d\t%s",
2281 ssid->id,
2282 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002283 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002284 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002285 pos += ret;
2286 if (ssid->bssid_set) {
2287 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
2288 MAC2STR(ssid->bssid));
2289 } else {
2290 ret = os_snprintf(pos, end - pos, "\tany");
2291 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002292 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002293 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294 pos += ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002295 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002296 ssid == wpa_s->current_ssid ?
2297 "[CURRENT]" : "",
2298 ssid->disabled ? "[DISABLED]" : "",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002299 ssid->disabled_until.sec ?
2300 "[TEMP-DISABLED]" : "",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002301 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
2302 "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002303 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002304 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002305 pos += ret;
2306 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002307 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002308 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002309 pos += ret;
2310
2311 ssid = ssid->next;
2312 }
2313
2314 return pos - buf;
2315}
2316
2317
2318static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
2319{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002320 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002321 ret = os_snprintf(pos, end - pos, "-");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002322 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002323 return pos;
2324 pos += ret;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002325 ret = wpa_write_ciphers(pos, end, cipher, "+");
2326 if (ret < 0)
2327 return pos;
2328 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002329 return pos;
2330}
2331
2332
2333static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
2334 const u8 *ie, size_t ie_len)
2335{
2336 struct wpa_ie_data data;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002337 char *start;
2338 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002339
2340 ret = os_snprintf(pos, end - pos, "[%s-", proto);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002341 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002342 return pos;
2343 pos += ret;
2344
2345 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
2346 ret = os_snprintf(pos, end - pos, "?]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002347 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002348 return pos;
2349 pos += ret;
2350 return pos;
2351 }
2352
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002353 start = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002354 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002355 ret = os_snprintf(pos, end - pos, "%sEAP",
2356 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002357 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002358 return pos;
2359 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002360 }
2361 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002362 ret = os_snprintf(pos, end - pos, "%sPSK",
2363 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002364 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002365 return pos;
2366 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002367 }
2368 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002369 ret = os_snprintf(pos, end - pos, "%sNone",
2370 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002371 if (os_snprintf_error(end - pos, ret))
2372 return pos;
2373 pos += ret;
2374 }
2375 if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
2376 ret = os_snprintf(pos, end - pos, "%sSAE",
2377 pos == start ? "" : "+");
2378 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002379 return pos;
2380 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002381 }
2382#ifdef CONFIG_IEEE80211R
2383 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
2384 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002385 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002386 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002387 return pos;
2388 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002389 }
2390 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
2391 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002392 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002393 if (os_snprintf_error(end - pos, ret))
2394 return pos;
2395 pos += ret;
2396 }
2397 if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
2398 ret = os_snprintf(pos, end - pos, "%sFT/SAE",
2399 pos == start ? "" : "+");
2400 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002401 return pos;
2402 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002403 }
2404#endif /* CONFIG_IEEE80211R */
2405#ifdef CONFIG_IEEE80211W
2406 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2407 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002408 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002409 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002410 return pos;
2411 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002412 }
2413 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
2414 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002415 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002416 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002417 return pos;
2418 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002419 }
2420#endif /* CONFIG_IEEE80211W */
2421
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002422#ifdef CONFIG_SUITEB
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002423 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2424 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
2425 pos == start ? "" : "+");
2426 if (os_snprintf_error(end - pos, ret))
2427 return pos;
2428 pos += ret;
2429 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002430#endif /* CONFIG_SUITEB */
2431
2432#ifdef CONFIG_SUITEB192
2433 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2434 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
2435 pos == start ? "" : "+");
2436 if (os_snprintf_error(end - pos, ret))
2437 return pos;
2438 pos += ret;
2439 }
2440#endif /* CONFIG_SUITEB192 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002441
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002442#ifdef CONFIG_FILS
2443 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
2444 ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
2445 pos == start ? "" : "+");
2446 if (os_snprintf_error(end - pos, ret))
2447 return pos;
2448 pos += ret;
2449 }
2450 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
2451 ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
2452 pos == start ? "" : "+");
2453 if (os_snprintf_error(end - pos, ret))
2454 return pos;
2455 pos += ret;
2456 }
2457#ifdef CONFIG_IEEE80211R
2458 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
2459 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
2460 pos == start ? "" : "+");
2461 if (os_snprintf_error(end - pos, ret))
2462 return pos;
2463 pos += ret;
2464 }
2465 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
2466 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
2467 pos == start ? "" : "+");
2468 if (os_snprintf_error(end - pos, ret))
2469 return pos;
2470 pos += ret;
2471 }
2472#endif /* CONFIG_IEEE80211R */
2473#endif /* CONFIG_FILS */
2474
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002475 if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
2476 ret = os_snprintf(pos, end - pos, "%sOSEN",
2477 pos == start ? "" : "+");
2478 if (os_snprintf_error(end - pos, ret))
2479 return pos;
2480 pos += ret;
2481 }
2482
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002483 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
2484
2485 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
2486 ret = os_snprintf(pos, end - pos, "-preauth");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002487 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002488 return pos;
2489 pos += ret;
2490 }
2491
2492 ret = os_snprintf(pos, end - pos, "]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002493 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002494 return pos;
2495 pos += ret;
2496
2497 return pos;
2498}
2499
2500
2501#ifdef CONFIG_WPS
2502static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
2503 char *pos, char *end,
2504 struct wpabuf *wps_ie)
2505{
2506 int ret;
2507 const char *txt;
2508
2509 if (wps_ie == NULL)
2510 return pos;
2511 if (wps_is_selected_pbc_registrar(wps_ie))
2512 txt = "[WPS-PBC]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002513 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
2514 txt = "[WPS-AUTH]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002515 else if (wps_is_selected_pin_registrar(wps_ie))
2516 txt = "[WPS-PIN]";
2517 else
2518 txt = "[WPS]";
2519
2520 ret = os_snprintf(pos, end - pos, "%s", txt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002521 if (!os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002522 pos += ret;
2523 wpabuf_free(wps_ie);
2524 return pos;
2525}
2526#endif /* CONFIG_WPS */
2527
2528
2529static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
2530 char *pos, char *end,
2531 const struct wpa_bss *bss)
2532{
2533#ifdef CONFIG_WPS
2534 struct wpabuf *wps_ie;
2535 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
2536 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
2537#else /* CONFIG_WPS */
2538 return pos;
2539#endif /* CONFIG_WPS */
2540}
2541
2542
2543/* Format one result on one text line into a buffer. */
2544static int wpa_supplicant_ctrl_iface_scan_result(
2545 struct wpa_supplicant *wpa_s,
2546 const struct wpa_bss *bss, char *buf, size_t buflen)
2547{
2548 char *pos, *end;
2549 int ret;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002550 const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002551
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002552 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002553 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt96571392013-10-14 12:54:46 -07002554 if (!p2p)
2555 p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002556 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
2557 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
2558 0)
2559 return 0; /* Do not show P2P listen discovery results here */
2560
2561 pos = buf;
2562 end = buf + buflen;
2563
2564 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
2565 MAC2STR(bss->bssid), bss->freq, bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002566 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002567 return -1;
2568 pos += ret;
2569 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2570 if (ie)
2571 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
2572 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002573 if (ie2) {
2574 pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
2575 ie2, 2 + ie2[1]);
2576 }
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002577 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
2578 if (osen_ie)
2579 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
2580 osen_ie, 2 + osen_ie[1]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002581 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002582 if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002583 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002584 if (os_snprintf_error(end - pos, ret))
2585 return -1;
2586 pos += ret;
2587 }
2588 if (mesh) {
2589 ret = os_snprintf(pos, end - pos, "[MESH]");
2590 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002591 return -1;
2592 pos += ret;
2593 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002594 if (bss_is_dmg(bss)) {
2595 const char *s;
2596 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002597 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002598 return -1;
2599 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002600 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
2601 case IEEE80211_CAP_DMG_IBSS:
2602 s = "[IBSS]";
2603 break;
2604 case IEEE80211_CAP_DMG_AP:
2605 s = "[ESS]";
2606 break;
2607 case IEEE80211_CAP_DMG_PBSS:
2608 s = "[PBSS]";
2609 break;
2610 default:
2611 s = "";
2612 break;
2613 }
2614 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002615 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002616 return -1;
2617 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002618 } else {
2619 if (bss->caps & IEEE80211_CAP_IBSS) {
2620 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002621 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002622 return -1;
2623 pos += ret;
2624 }
2625 if (bss->caps & IEEE80211_CAP_ESS) {
2626 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002627 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002628 return -1;
2629 pos += ret;
2630 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002631 }
2632 if (p2p) {
2633 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002634 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002635 return -1;
2636 pos += ret;
2637 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002638#ifdef CONFIG_HS20
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002639 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002640 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002641 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07002642 return -1;
2643 pos += ret;
2644 }
2645#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002646#ifdef CONFIG_FILS
2647 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
2648 ret = os_snprintf(pos, end - pos, "[FILS]");
2649 if (os_snprintf_error(end - pos, ret))
2650 return -1;
2651 pos += ret;
2652 }
2653#endif /* CONFIG_FILS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002654#ifdef CONFIG_FST
2655 if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
2656 ret = os_snprintf(pos, end - pos, "[FST]");
2657 if (os_snprintf_error(end - pos, ret))
2658 return -1;
2659 pos += ret;
2660 }
2661#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002662
2663 ret = os_snprintf(pos, end - pos, "\t%s",
2664 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002665 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002666 return -1;
2667 pos += ret;
2668
2669 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002670 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002671 return -1;
2672 pos += ret;
2673
2674 return pos - buf;
2675}
2676
2677
2678static int wpa_supplicant_ctrl_iface_scan_results(
2679 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2680{
2681 char *pos, *end;
2682 struct wpa_bss *bss;
2683 int ret;
2684
2685 pos = buf;
2686 end = buf + buflen;
2687 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
2688 "flags / ssid\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002689 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002690 return pos - buf;
2691 pos += ret;
2692
2693 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2694 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
2695 end - pos);
2696 if (ret < 0 || ret >= end - pos)
2697 return pos - buf;
2698 pos += ret;
2699 }
2700
2701 return pos - buf;
2702}
2703
2704
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002705#ifdef CONFIG_MESH
2706
2707static int wpa_supplicant_ctrl_iface_mesh_interface_add(
2708 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
2709{
2710 char *pos, ifname[IFNAMSIZ + 1];
2711
2712 ifname[0] = '\0';
2713
2714 pos = os_strstr(cmd, "ifname=");
2715 if (pos) {
2716 pos += 7;
2717 os_strlcpy(ifname, pos, sizeof(ifname));
2718 }
2719
2720 if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
2721 return -1;
2722
2723 os_strlcpy(reply, ifname, max_len);
2724 return os_strlen(ifname);
2725}
2726
2727
2728static int wpa_supplicant_ctrl_iface_mesh_group_add(
2729 struct wpa_supplicant *wpa_s, char *cmd)
2730{
2731 int id;
2732 struct wpa_ssid *ssid;
2733
2734 id = atoi(cmd);
2735 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
2736
2737 ssid = wpa_config_get_network(wpa_s->conf, id);
2738 if (ssid == NULL) {
2739 wpa_printf(MSG_DEBUG,
2740 "CTRL_IFACE: Could not find network id=%d", id);
2741 return -1;
2742 }
2743 if (ssid->mode != WPAS_MODE_MESH) {
2744 wpa_printf(MSG_DEBUG,
2745 "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
2746 return -1;
2747 }
2748 if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
2749 ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
2750 wpa_printf(MSG_ERROR,
2751 "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
2752 return -1;
2753 }
2754
2755 /*
2756 * TODO: If necessary write our own group_add function,
2757 * for now we can reuse select_network
2758 */
2759 wpa_supplicant_select_network(wpa_s, ssid);
2760
2761 return 0;
2762}
2763
2764
2765static int wpa_supplicant_ctrl_iface_mesh_group_remove(
2766 struct wpa_supplicant *wpa_s, char *cmd)
2767{
2768 struct wpa_supplicant *orig;
2769 struct wpa_global *global;
2770 int found = 0;
2771
2772 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
2773
2774 global = wpa_s->global;
2775 orig = wpa_s;
2776
2777 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2778 if (os_strcmp(wpa_s->ifname, cmd) == 0) {
2779 found = 1;
2780 break;
2781 }
2782 }
2783 if (!found) {
2784 wpa_printf(MSG_ERROR,
2785 "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
2786 cmd);
2787 return -1;
2788 }
2789 if (wpa_s->mesh_if_created && wpa_s == orig) {
2790 wpa_printf(MSG_ERROR,
2791 "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
2792 return -1;
2793 }
2794
2795 wpa_s->reassociate = 0;
2796 wpa_s->disconnected = 1;
2797 wpa_supplicant_cancel_sched_scan(wpa_s);
2798 wpa_supplicant_cancel_scan(wpa_s);
2799
2800 /*
2801 * TODO: If necessary write our own group_remove function,
2802 * for now we can reuse deauthenticate
2803 */
2804 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2805
2806 if (wpa_s->mesh_if_created)
2807 wpa_supplicant_remove_iface(global, wpa_s, 0);
2808
2809 return 0;
2810}
2811
Dmitry Shmidte4663042016-04-04 10:07:49 -07002812
2813static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
2814 struct wpa_supplicant *wpa_s, char *cmd)
2815{
2816 u8 addr[ETH_ALEN];
2817
2818 if (hwaddr_aton(cmd, addr) < 0)
2819 return -1;
2820
2821 return wpas_mesh_peer_remove(wpa_s, addr);
2822}
2823
2824
2825static int wpa_supplicant_ctrl_iface_mesh_peer_add(
2826 struct wpa_supplicant *wpa_s, char *cmd)
2827{
2828 u8 addr[ETH_ALEN];
2829 int duration;
2830 char *pos;
2831
2832 pos = os_strstr(cmd, " duration=");
2833 if (pos) {
2834 *pos = '\0';
2835 duration = atoi(pos + 10);
2836 } else {
2837 duration = -1;
2838 }
2839
2840 if (hwaddr_aton(cmd, addr))
2841 return -1;
2842
2843 return wpas_mesh_peer_add(wpa_s, addr, duration);
2844}
2845
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002846#endif /* CONFIG_MESH */
2847
2848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002849static int wpa_supplicant_ctrl_iface_select_network(
2850 struct wpa_supplicant *wpa_s, char *cmd)
2851{
2852 int id;
2853 struct wpa_ssid *ssid;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002854 char *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002855
2856 /* cmd: "<network id>" or "any" */
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002857 if (os_strncmp(cmd, "any", 3) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002858 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
2859 ssid = NULL;
2860 } else {
2861 id = atoi(cmd);
2862 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
2863
2864 ssid = wpa_config_get_network(wpa_s->conf, id);
2865 if (ssid == NULL) {
2866 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2867 "network id=%d", id);
2868 return -1;
2869 }
2870 if (ssid->disabled == 2) {
2871 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2872 "SELECT_NETWORK with persistent P2P group");
2873 return -1;
2874 }
2875 }
2876
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002877 pos = os_strstr(cmd, " freq=");
2878 if (pos) {
2879 int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
2880 if (freqs) {
2881 wpa_s->scan_req = MANUAL_SCAN_REQ;
2882 os_free(wpa_s->manual_scan_freqs);
2883 wpa_s->manual_scan_freqs = freqs;
2884 }
2885 }
2886
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002887 wpa_s->scan_min_time.sec = 0;
2888 wpa_s->scan_min_time.usec = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002889 wpa_supplicant_select_network(wpa_s, ssid);
2890
2891 return 0;
2892}
2893
2894
2895static int wpa_supplicant_ctrl_iface_enable_network(
2896 struct wpa_supplicant *wpa_s, char *cmd)
2897{
2898 int id;
2899 struct wpa_ssid *ssid;
2900
2901 /* cmd: "<network id>" or "all" */
2902 if (os_strcmp(cmd, "all") == 0) {
2903 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
2904 ssid = NULL;
2905 } else {
2906 id = atoi(cmd);
2907 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
2908
2909 ssid = wpa_config_get_network(wpa_s->conf, id);
2910 if (ssid == NULL) {
2911 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2912 "network id=%d", id);
2913 return -1;
2914 }
2915 if (ssid->disabled == 2) {
2916 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2917 "ENABLE_NETWORK with persistent P2P group");
2918 return -1;
2919 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002920
2921 if (os_strstr(cmd, " no-connect")) {
2922 ssid->disabled = 0;
2923 return 0;
2924 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002925 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002926 wpa_s->scan_min_time.sec = 0;
2927 wpa_s->scan_min_time.usec = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002928 wpa_supplicant_enable_network(wpa_s, ssid);
2929
2930 return 0;
2931}
2932
2933
2934static int wpa_supplicant_ctrl_iface_disable_network(
2935 struct wpa_supplicant *wpa_s, char *cmd)
2936{
2937 int id;
2938 struct wpa_ssid *ssid;
2939
2940 /* cmd: "<network id>" or "all" */
2941 if (os_strcmp(cmd, "all") == 0) {
2942 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
2943 ssid = NULL;
2944 } else {
2945 id = atoi(cmd);
2946 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
2947
2948 ssid = wpa_config_get_network(wpa_s->conf, id);
2949 if (ssid == NULL) {
2950 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2951 "network id=%d", id);
2952 return -1;
2953 }
2954 if (ssid->disabled == 2) {
2955 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2956 "DISABLE_NETWORK with persistent P2P "
2957 "group");
2958 return -1;
2959 }
2960 }
2961 wpa_supplicant_disable_network(wpa_s, ssid);
2962
2963 return 0;
2964}
2965
2966
2967static int wpa_supplicant_ctrl_iface_add_network(
2968 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2969{
2970 struct wpa_ssid *ssid;
2971 int ret;
2972
2973 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
2974
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07002975 ssid = wpa_supplicant_add_network(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002976 if (ssid == NULL)
2977 return -1;
2978
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002979 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002980 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002981 return -1;
2982 return ret;
2983}
2984
2985
2986static int wpa_supplicant_ctrl_iface_remove_network(
2987 struct wpa_supplicant *wpa_s, char *cmd)
2988{
2989 int id;
2990 struct wpa_ssid *ssid;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07002991 int result;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002992
2993 /* cmd: "<network id>" or "all" */
2994 if (os_strcmp(cmd, "all") == 0) {
2995 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002996 if (wpa_s->sched_scanning)
2997 wpa_supplicant_cancel_sched_scan(wpa_s);
2998
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002999 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003000 if (wpa_s->current_ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07003001#ifdef CONFIG_SME
3002 wpa_s->sme.prev_bssid_set = 0;
3003#endif /* CONFIG_SME */
Jouni Malinen75ecf522011-06-27 15:19:46 -07003004 wpa_sm_set_config(wpa_s->wpa, NULL);
3005 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07003006 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3007 wpa_s->own_disconnect_req = 1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003008 wpa_supplicant_deauthenticate(
3009 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003010 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003011 ssid = wpa_s->conf->ssid;
3012 while (ssid) {
3013 struct wpa_ssid *remove_ssid = ssid;
3014 id = ssid->id;
3015 ssid = ssid->next;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003016 if (wpa_s->last_ssid == remove_ssid)
3017 wpa_s->last_ssid = NULL;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003018 wpas_notify_network_removed(wpa_s, remove_ssid);
3019 wpa_config_remove_network(wpa_s->conf, id);
3020 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003021 return 0;
3022 }
3023
3024 id = atoi(cmd);
3025 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
3026
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003027 result = wpa_supplicant_remove_network(wpa_s, id);
3028 if (result == -1) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003029 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3030 "id=%d", id);
3031 return -1;
3032 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07003033 if (result == -2) {
Deepthi Gowria831d782012-09-03 11:55:38 +03003034 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
3035 "network id=%d", id);
3036 return -1;
3037 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003038 return 0;
3039}
3040
3041
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003042static int wpa_supplicant_ctrl_iface_update_network(
3043 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
3044 char *name, char *value)
3045{
Dmitry Shmidte4663042016-04-04 10:07:49 -07003046 int ret;
3047
3048 ret = wpa_config_set(ssid, name, value, 0);
3049 if (ret < 0) {
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003050 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
3051 "variable '%s'", name);
3052 return -1;
3053 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07003054 if (ret == 1)
3055 return 0; /* No change to the previously configured value */
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003056
3057 if (os_strcmp(name, "bssid") != 0 &&
Dmitry Shmidte4663042016-04-04 10:07:49 -07003058 os_strcmp(name, "priority") != 0) {
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003059 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
3060
Dmitry Shmidte4663042016-04-04 10:07:49 -07003061 if (wpa_s->current_ssid == ssid ||
3062 wpa_s->current_ssid == NULL) {
3063 /*
3064 * Invalidate the EAP session cache if anything in the
3065 * current or previously used configuration changes.
3066 */
3067 eapol_sm_invalidate_cached_session(wpa_s->eapol);
3068 }
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003069 }
3070
3071 if ((os_strcmp(name, "psk") == 0 &&
3072 value[0] == '"' && ssid->ssid_len) ||
3073 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
3074 wpa_config_update_psk(ssid);
3075 else if (os_strcmp(name, "priority") == 0)
3076 wpa_config_update_prio_list(wpa_s->conf);
3077
3078 return 0;
3079}
3080
3081
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003082static int wpa_supplicant_ctrl_iface_set_network(
3083 struct wpa_supplicant *wpa_s, char *cmd)
3084{
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003085 int id, ret, prev_bssid_set, prev_disabled;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003086 struct wpa_ssid *ssid;
3087 char *name, *value;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003088 u8 prev_bssid[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003089
3090 /* cmd: "<network id> <variable name> <value>" */
3091 name = os_strchr(cmd, ' ');
3092 if (name == NULL)
3093 return -1;
3094 *name++ = '\0';
3095
3096 value = os_strchr(name, ' ');
3097 if (value == NULL)
3098 return -1;
3099 *value++ = '\0';
3100
3101 id = atoi(cmd);
3102 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
3103 id, name);
3104 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3105 (u8 *) value, os_strlen(value));
3106
3107 ssid = wpa_config_get_network(wpa_s->conf, id);
3108 if (ssid == NULL) {
3109 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3110 "id=%d", id);
3111 return -1;
3112 }
3113
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003114 prev_bssid_set = ssid->bssid_set;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003115 prev_disabled = ssid->disabled;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003116 os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
3117 ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
3118 value);
3119 if (ret == 0 &&
3120 (ssid->bssid_set != prev_bssid_set ||
3121 os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
3122 wpas_notify_network_bssid_set_changed(wpa_s, ssid);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003123
3124 if (prev_disabled != ssid->disabled &&
3125 (prev_disabled == 2 || ssid->disabled == 2))
3126 wpas_notify_network_type_changed(wpa_s, ssid);
3127
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003128 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003129}
3130
3131
3132static int wpa_supplicant_ctrl_iface_get_network(
3133 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
3134{
3135 int id;
3136 size_t res;
3137 struct wpa_ssid *ssid;
3138 char *name, *value;
3139
3140 /* cmd: "<network id> <variable name>" */
3141 name = os_strchr(cmd, ' ');
3142 if (name == NULL || buflen == 0)
3143 return -1;
3144 *name++ = '\0';
3145
3146 id = atoi(cmd);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003147 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003148 id, name);
3149
3150 ssid = wpa_config_get_network(wpa_s->conf, id);
3151 if (ssid == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003152 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003153 "id=%d", id);
3154 return -1;
3155 }
3156
3157 value = wpa_config_get_no_key(ssid, name);
3158 if (value == NULL) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003159 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003160 "variable '%s'", name);
3161 return -1;
3162 }
3163
3164 res = os_strlcpy(buf, value, buflen);
3165 if (res >= buflen) {
3166 os_free(value);
3167 return -1;
3168 }
3169
3170 os_free(value);
3171
3172 return res;
3173}
3174
3175
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003176static int wpa_supplicant_ctrl_iface_dup_network(
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003177 struct wpa_supplicant *wpa_s, char *cmd,
3178 struct wpa_supplicant *dst_wpa_s)
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003179{
3180 struct wpa_ssid *ssid_s, *ssid_d;
3181 char *name, *id, *value;
3182 int id_s, id_d, ret;
3183
3184 /* cmd: "<src network id> <dst network id> <variable name>" */
3185 id = os_strchr(cmd, ' ');
3186 if (id == NULL)
3187 return -1;
3188 *id++ = '\0';
3189
3190 name = os_strchr(id, ' ');
3191 if (name == NULL)
3192 return -1;
3193 *name++ = '\0';
3194
3195 id_s = atoi(cmd);
3196 id_d = atoi(id);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003197
3198 wpa_printf(MSG_DEBUG,
3199 "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'",
3200 wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003201
3202 ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
3203 if (ssid_s == NULL) {
3204 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3205 "network id=%d", id_s);
3206 return -1;
3207 }
3208
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003209 ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003210 if (ssid_d == NULL) {
3211 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003212 "network id=%d", id_d);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003213 return -1;
3214 }
3215
3216 value = wpa_config_get(ssid_s, name);
3217 if (value == NULL) {
3218 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
3219 "variable '%s'", name);
3220 return -1;
3221 }
3222
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003223 ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003224 value);
3225
3226 os_free(value);
3227
3228 return ret;
3229}
3230
3231
Dmitry Shmidt04949592012-07-19 12:16:46 -07003232static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
3233 char *buf, size_t buflen)
3234{
3235 char *pos, *end;
3236 struct wpa_cred *cred;
3237 int ret;
3238
3239 pos = buf;
3240 end = buf + buflen;
3241 ret = os_snprintf(pos, end - pos,
3242 "cred id / realm / username / domain / imsi\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003243 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003244 return pos - buf;
3245 pos += ret;
3246
3247 cred = wpa_s->conf->cred;
3248 while (cred) {
3249 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
3250 cred->id, cred->realm ? cred->realm : "",
3251 cred->username ? cred->username : "",
Dmitry Shmidt051af732013-10-22 13:52:46 -07003252 cred->domain ? cred->domain[0] : "",
Dmitry Shmidt04949592012-07-19 12:16:46 -07003253 cred->imsi ? cred->imsi : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003254 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003255 return pos - buf;
3256 pos += ret;
3257
3258 cred = cred->next;
3259 }
3260
3261 return pos - buf;
3262}
3263
3264
3265static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
3266 char *buf, size_t buflen)
3267{
3268 struct wpa_cred *cred;
3269 int ret;
3270
3271 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
3272
3273 cred = wpa_config_add_cred(wpa_s->conf);
3274 if (cred == NULL)
3275 return -1;
3276
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003277 wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
3278
Dmitry Shmidt04949592012-07-19 12:16:46 -07003279 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003280 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003281 return -1;
3282 return ret;
3283}
3284
3285
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003286static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
3287 struct wpa_cred *cred)
3288{
3289 struct wpa_ssid *ssid;
3290 char str[20];
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003291 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003292
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003293 if (cred == NULL) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003294 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3295 return -1;
3296 }
3297
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003298 id = cred->id;
3299 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
3300 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3301 return -1;
3302 }
3303
3304 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
3305
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003306 /* Remove any network entry created based on the removed credential */
3307 ssid = wpa_s->conf->ssid;
3308 while (ssid) {
3309 if (ssid->parent_cred == cred) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003310 int res;
3311
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003312 wpa_printf(MSG_DEBUG, "Remove network id %d since it "
3313 "used the removed credential", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003314 res = os_snprintf(str, sizeof(str), "%d", ssid->id);
3315 if (os_snprintf_error(sizeof(str), res))
3316 str[sizeof(str) - 1] = '\0';
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003317 ssid = ssid->next;
3318 wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
3319 } else
3320 ssid = ssid->next;
3321 }
3322
3323 return 0;
3324}
3325
3326
Dmitry Shmidt04949592012-07-19 12:16:46 -07003327static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
3328 char *cmd)
3329{
3330 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003331 struct wpa_cred *cred, *prev;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003332
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003333 /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
3334 * "provisioning_sp=<FQDN> */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003335 if (os_strcmp(cmd, "all") == 0) {
3336 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
3337 cred = wpa_s->conf->cred;
3338 while (cred) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003339 prev = cred;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003340 cred = cred->next;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003341 wpas_ctrl_remove_cred(wpa_s, prev);
3342 }
3343 return 0;
3344 }
3345
3346 if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
3347 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
3348 cmd + 8);
3349 cred = wpa_s->conf->cred;
3350 while (cred) {
3351 prev = cred;
3352 cred = cred->next;
Dmitry Shmidt051af732013-10-22 13:52:46 -07003353 if (prev->domain) {
3354 size_t i;
3355 for (i = 0; i < prev->num_domain; i++) {
3356 if (os_strcmp(prev->domain[i], cmd + 8)
3357 != 0)
3358 continue;
3359 wpas_ctrl_remove_cred(wpa_s, prev);
3360 break;
3361 }
3362 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003363 }
3364 return 0;
3365 }
3366
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003367 if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
3368 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
3369 cmd + 16);
3370 cred = wpa_s->conf->cred;
3371 while (cred) {
3372 prev = cred;
3373 cred = cred->next;
3374 if (prev->provisioning_sp &&
3375 os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
3376 wpas_ctrl_remove_cred(wpa_s, prev);
3377 }
3378 return 0;
3379 }
3380
Dmitry Shmidt04949592012-07-19 12:16:46 -07003381 id = atoi(cmd);
3382 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
3383
3384 cred = wpa_config_get_cred(wpa_s->conf, id);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003385 return wpas_ctrl_remove_cred(wpa_s, cred);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003386}
3387
3388
3389static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
3390 char *cmd)
3391{
3392 int id;
3393 struct wpa_cred *cred;
3394 char *name, *value;
3395
3396 /* cmd: "<cred id> <variable name> <value>" */
3397 name = os_strchr(cmd, ' ');
3398 if (name == NULL)
3399 return -1;
3400 *name++ = '\0';
3401
3402 value = os_strchr(name, ' ');
3403 if (value == NULL)
3404 return -1;
3405 *value++ = '\0';
3406
3407 id = atoi(cmd);
3408 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
3409 id, name);
3410 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3411 (u8 *) value, os_strlen(value));
3412
3413 cred = wpa_config_get_cred(wpa_s->conf, id);
3414 if (cred == NULL) {
3415 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3416 id);
3417 return -1;
3418 }
3419
3420 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
3421 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
3422 "variable '%s'", name);
3423 return -1;
3424 }
3425
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003426 wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
3427
Dmitry Shmidt04949592012-07-19 12:16:46 -07003428 return 0;
3429}
3430
3431
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003432static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
3433 char *cmd, char *buf,
3434 size_t buflen)
3435{
3436 int id;
3437 size_t res;
3438 struct wpa_cred *cred;
3439 char *name, *value;
3440
3441 /* cmd: "<cred id> <variable name>" */
3442 name = os_strchr(cmd, ' ');
3443 if (name == NULL)
3444 return -1;
3445 *name++ = '\0';
3446
3447 id = atoi(cmd);
3448 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
3449 id, name);
3450
3451 cred = wpa_config_get_cred(wpa_s->conf, id);
3452 if (cred == NULL) {
3453 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3454 id);
3455 return -1;
3456 }
3457
3458 value = wpa_config_get_cred_no_key(cred, name);
3459 if (value == NULL) {
3460 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
3461 name);
3462 return -1;
3463 }
3464
3465 res = os_strlcpy(buf, value, buflen);
3466 if (res >= buflen) {
3467 os_free(value);
3468 return -1;
3469 }
3470
3471 os_free(value);
3472
3473 return res;
3474}
3475
3476
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003477#ifndef CONFIG_NO_CONFIG_WRITE
3478static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
3479{
3480 int ret;
3481
3482 if (!wpa_s->conf->update_config) {
3483 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
3484 "to update configuration (update_config=0)");
3485 return -1;
3486 }
3487
3488 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3489 if (ret) {
3490 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
3491 "update configuration");
3492 } else {
3493 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
3494 " updated");
3495 }
3496
3497 return ret;
3498}
3499#endif /* CONFIG_NO_CONFIG_WRITE */
3500
3501
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003502struct cipher_info {
3503 unsigned int capa;
3504 const char *name;
3505 int group_only;
3506};
3507
3508static const struct cipher_info ciphers[] = {
3509 { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
3510 { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
3511 { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
3512 { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
3513 { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
3514 { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
3515 { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
3516 { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
3517};
3518
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003519static const struct cipher_info ciphers_group_mgmt[] = {
3520 { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
3521 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
3522 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
3523 { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
3524};
3525
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003526
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003527static int ctrl_iface_get_capability_pairwise(int res, char *strict,
3528 struct wpa_driver_capa *capa,
3529 char *buf, size_t buflen)
3530{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003531 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003532 char *pos, *end;
3533 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003534 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003535
3536 pos = buf;
3537 end = pos + buflen;
3538
3539 if (res < 0) {
3540 if (strict)
3541 return 0;
3542 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
3543 if (len >= buflen)
3544 return -1;
3545 return len;
3546 }
3547
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003548 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3549 if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
3550 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003551 pos == buf ? "" : " ",
3552 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003553 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003554 return pos - buf;
3555 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003556 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557 }
3558
3559 return pos - buf;
3560}
3561
3562
3563static int ctrl_iface_get_capability_group(int res, char *strict,
3564 struct wpa_driver_capa *capa,
3565 char *buf, size_t buflen)
3566{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003567 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003568 char *pos, *end;
3569 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003570 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003571
3572 pos = buf;
3573 end = pos + buflen;
3574
3575 if (res < 0) {
3576 if (strict)
3577 return 0;
3578 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
3579 if (len >= buflen)
3580 return -1;
3581 return len;
3582 }
3583
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003584 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3585 if (capa->enc & ciphers[i].capa) {
3586 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003587 pos == buf ? "" : " ",
3588 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003589 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003590 return pos - buf;
3591 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003592 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003593 }
3594
3595 return pos - buf;
3596}
3597
3598
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003599static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
3600 struct wpa_driver_capa *capa,
3601 char *buf, size_t buflen)
3602{
3603 int ret;
3604 char *pos, *end;
3605 unsigned int i;
3606
3607 pos = buf;
3608 end = pos + buflen;
3609
3610 if (res < 0)
3611 return 0;
3612
3613 for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
3614 if (capa->enc & ciphers_group_mgmt[i].capa) {
3615 ret = os_snprintf(pos, end - pos, "%s%s",
3616 pos == buf ? "" : " ",
3617 ciphers_group_mgmt[i].name);
3618 if (os_snprintf_error(end - pos, ret))
3619 return pos - buf;
3620 pos += ret;
3621 }
3622 }
3623
3624 return pos - buf;
3625}
3626
3627
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003628static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
3629 struct wpa_driver_capa *capa,
3630 char *buf, size_t buflen)
3631{
3632 int ret;
3633 char *pos, *end;
3634 size_t len;
3635
3636 pos = buf;
3637 end = pos + buflen;
3638
3639 if (res < 0) {
3640 if (strict)
3641 return 0;
3642 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
3643 "NONE", buflen);
3644 if (len >= buflen)
3645 return -1;
3646 return len;
3647 }
3648
3649 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003650 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003651 return pos - buf;
3652 pos += ret;
3653
3654 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3655 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3656 ret = os_snprintf(pos, end - pos, " WPA-EAP");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003657 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003658 return pos - buf;
3659 pos += ret;
3660 }
3661
3662 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3663 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3664 ret = os_snprintf(pos, end - pos, " WPA-PSK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003665 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003666 return pos - buf;
3667 pos += ret;
3668 }
3669
3670 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
3671 ret = os_snprintf(pos, end - pos, " WPA-NONE");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003672 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003673 return pos - buf;
3674 pos += ret;
3675 }
3676
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003677#ifdef CONFIG_SUITEB
3678 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
3679 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
3680 if (os_snprintf_error(end - pos, ret))
3681 return pos - buf;
3682 pos += ret;
3683 }
3684#endif /* CONFIG_SUITEB */
3685#ifdef CONFIG_SUITEB192
3686 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
3687 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
3688 if (os_snprintf_error(end - pos, ret))
3689 return pos - buf;
3690 pos += ret;
3691 }
3692#endif /* CONFIG_SUITEB192 */
3693
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003694 return pos - buf;
3695}
3696
3697
3698static int ctrl_iface_get_capability_proto(int res, char *strict,
3699 struct wpa_driver_capa *capa,
3700 char *buf, size_t buflen)
3701{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003702 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003703 char *pos, *end;
3704 size_t len;
3705
3706 pos = buf;
3707 end = pos + buflen;
3708
3709 if (res < 0) {
3710 if (strict)
3711 return 0;
3712 len = os_strlcpy(buf, "RSN WPA", buflen);
3713 if (len >= buflen)
3714 return -1;
3715 return len;
3716 }
3717
3718 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3719 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003720 ret = os_snprintf(pos, end - pos, "%sRSN",
3721 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003722 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003723 return pos - buf;
3724 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003725 }
3726
3727 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3728 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003729 ret = os_snprintf(pos, end - pos, "%sWPA",
3730 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003731 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003732 return pos - buf;
3733 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003734 }
3735
3736 return pos - buf;
3737}
3738
3739
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003740static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
3741 int res, char *strict,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003742 struct wpa_driver_capa *capa,
3743 char *buf, size_t buflen)
3744{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003745 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003746 char *pos, *end;
3747 size_t len;
3748
3749 pos = buf;
3750 end = pos + buflen;
3751
3752 if (res < 0) {
3753 if (strict)
3754 return 0;
3755 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
3756 if (len >= buflen)
3757 return -1;
3758 return len;
3759 }
3760
3761 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003762 ret = os_snprintf(pos, end - pos, "%sOPEN",
3763 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003764 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003765 return pos - buf;
3766 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003767 }
3768
3769 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
3770 ret = os_snprintf(pos, end - pos, "%sSHARED",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003771 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003772 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003773 return pos - buf;
3774 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003775 }
3776
3777 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003778 ret = os_snprintf(pos, end - pos, "%sLEAP",
3779 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003780 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003781 return pos - buf;
3782 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003783 }
3784
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003785#ifdef CONFIG_SAE
3786 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
3787 ret = os_snprintf(pos, end - pos, "%sSAE",
3788 pos == buf ? "" : " ");
3789 if (os_snprintf_error(end - pos, ret))
3790 return pos - buf;
3791 pos += ret;
3792 }
3793#endif /* CONFIG_SAE */
3794
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003795 return pos - buf;
3796}
3797
3798
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003799static int ctrl_iface_get_capability_modes(int res, char *strict,
3800 struct wpa_driver_capa *capa,
3801 char *buf, size_t buflen)
3802{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003803 int ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003804 char *pos, *end;
3805 size_t len;
3806
3807 pos = buf;
3808 end = pos + buflen;
3809
3810 if (res < 0) {
3811 if (strict)
3812 return 0;
3813 len = os_strlcpy(buf, "IBSS AP", buflen);
3814 if (len >= buflen)
3815 return -1;
3816 return len;
3817 }
3818
3819 if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003820 ret = os_snprintf(pos, end - pos, "%sIBSS",
3821 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003822 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003823 return pos - buf;
3824 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003825 }
3826
3827 if (capa->flags & WPA_DRIVER_FLAGS_AP) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003828 ret = os_snprintf(pos, end - pos, "%sAP",
3829 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003830 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003831 return pos - buf;
3832 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003833 }
3834
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003835#ifdef CONFIG_MESH
3836 if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
3837 ret = os_snprintf(pos, end - pos, "%sMESH",
3838 pos == buf ? "" : " ");
3839 if (os_snprintf_error(end - pos, ret))
3840 return pos - buf;
3841 pos += ret;
3842 }
3843#endif /* CONFIG_MESH */
3844
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003845 return pos - buf;
3846}
3847
3848
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003849static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
3850 char *buf, size_t buflen)
3851{
3852 struct hostapd_channel_data *chnl;
3853 int ret, i, j;
3854 char *pos, *end, *hmode;
3855
3856 pos = buf;
3857 end = pos + buflen;
3858
3859 for (j = 0; j < wpa_s->hw.num_modes; j++) {
3860 switch (wpa_s->hw.modes[j].mode) {
3861 case HOSTAPD_MODE_IEEE80211B:
3862 hmode = "B";
3863 break;
3864 case HOSTAPD_MODE_IEEE80211G:
3865 hmode = "G";
3866 break;
3867 case HOSTAPD_MODE_IEEE80211A:
3868 hmode = "A";
3869 break;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003870 case HOSTAPD_MODE_IEEE80211AD:
3871 hmode = "AD";
3872 break;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003873 default:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003874 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003875 }
3876 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003877 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003878 return pos - buf;
3879 pos += ret;
3880 chnl = wpa_s->hw.modes[j].channels;
3881 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003882 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3883 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003884 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003885 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003886 return pos - buf;
3887 pos += ret;
3888 }
3889 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003890 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003891 return pos - buf;
3892 pos += ret;
3893 }
3894
3895 return pos - buf;
3896}
3897
3898
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003899static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
3900 char *buf, size_t buflen)
3901{
3902 struct hostapd_channel_data *chnl;
3903 int ret, i, j;
3904 char *pos, *end, *hmode;
3905
3906 pos = buf;
3907 end = pos + buflen;
3908
3909 for (j = 0; j < wpa_s->hw.num_modes; j++) {
3910 switch (wpa_s->hw.modes[j].mode) {
3911 case HOSTAPD_MODE_IEEE80211B:
3912 hmode = "B";
3913 break;
3914 case HOSTAPD_MODE_IEEE80211G:
3915 hmode = "G";
3916 break;
3917 case HOSTAPD_MODE_IEEE80211A:
3918 hmode = "A";
3919 break;
3920 case HOSTAPD_MODE_IEEE80211AD:
3921 hmode = "AD";
3922 break;
3923 default:
3924 continue;
3925 }
3926 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
3927 hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003928 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003929 return pos - buf;
3930 pos += ret;
3931 chnl = wpa_s->hw.modes[j].channels;
3932 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
3933 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3934 continue;
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08003935 ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003936 chnl[i].chan, chnl[i].freq,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003937 chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
3938 " (NO_IR)" : "",
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08003939 chnl[i].flag & HOSTAPD_CHAN_RADAR ?
3940 " (DFS)" : "");
3941
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003942 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003943 return pos - buf;
3944 pos += ret;
3945 }
3946 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003947 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003948 return pos - buf;
3949 pos += ret;
3950 }
3951
3952 return pos - buf;
3953}
3954
3955
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003956static int wpa_supplicant_ctrl_iface_get_capability(
3957 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
3958 size_t buflen)
3959{
3960 struct wpa_driver_capa capa;
3961 int res;
3962 char *strict;
3963 char field[30];
3964 size_t len;
3965
3966 /* Determine whether or not strict checking was requested */
3967 len = os_strlcpy(field, _field, sizeof(field));
3968 if (len >= sizeof(field))
3969 return -1;
3970 strict = os_strchr(field, ' ');
3971 if (strict != NULL) {
3972 *strict++ = '\0';
3973 if (os_strcmp(strict, "strict") != 0)
3974 return -1;
3975 }
3976
3977 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
3978 field, strict ? strict : "");
3979
3980 if (os_strcmp(field, "eap") == 0) {
3981 return eap_get_names(buf, buflen);
3982 }
3983
3984 res = wpa_drv_get_capa(wpa_s, &capa);
3985
3986 if (os_strcmp(field, "pairwise") == 0)
3987 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
3988 buf, buflen);
3989
3990 if (os_strcmp(field, "group") == 0)
3991 return ctrl_iface_get_capability_group(res, strict, &capa,
3992 buf, buflen);
3993
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003994 if (os_strcmp(field, "group_mgmt") == 0)
3995 return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
3996 buf, buflen);
3997
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003998 if (os_strcmp(field, "key_mgmt") == 0)
3999 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
4000 buf, buflen);
4001
4002 if (os_strcmp(field, "proto") == 0)
4003 return ctrl_iface_get_capability_proto(res, strict, &capa,
4004 buf, buflen);
4005
4006 if (os_strcmp(field, "auth_alg") == 0)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004007 return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
4008 &capa, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004009
Dmitry Shmidt700a1372013-03-15 14:14:44 -07004010 if (os_strcmp(field, "modes") == 0)
4011 return ctrl_iface_get_capability_modes(res, strict, &capa,
4012 buf, buflen);
4013
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07004014 if (os_strcmp(field, "channels") == 0)
4015 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
4016
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004017 if (os_strcmp(field, "freq") == 0)
4018 return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
4019
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004020#ifdef CONFIG_TDLS
4021 if (os_strcmp(field, "tdls") == 0)
4022 return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
4023#endif /* CONFIG_TDLS */
4024
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004025#ifdef CONFIG_ERP
4026 if (os_strcmp(field, "erp") == 0) {
4027 res = os_snprintf(buf, buflen, "ERP");
4028 if (os_snprintf_error(buflen, res))
4029 return -1;
4030 return res;
4031 }
4032#endif /* CONFIG_EPR */
4033
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004034#ifdef CONFIG_FIPS
4035 if (os_strcmp(field, "fips") == 0) {
4036 res = os_snprintf(buf, buflen, "FIPS");
4037 if (os_snprintf_error(buflen, res))
4038 return -1;
4039 return res;
4040 }
4041#endif /* CONFIG_FIPS */
4042
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08004043#ifdef CONFIG_ACS
4044 if (os_strcmp(field, "acs") == 0) {
4045 res = os_snprintf(buf, buflen, "ACS");
4046 if (os_snprintf_error(buflen, res))
4047 return -1;
4048 return res;
4049 }
4050#endif /* CONFIG_ACS */
4051
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004052#ifdef CONFIG_FILS
4053 if (os_strcmp(field, "fils") == 0 &&
4054 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) {
4055 res = os_snprintf(buf, buflen, "FILS");
4056 if (os_snprintf_error(buflen, res))
4057 return -1;
4058 return res;
4059 }
4060#endif /* CONFIG_FILS */
4061
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004062 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
4063 field);
4064
4065 return -1;
4066}
4067
4068
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004069#ifdef CONFIG_INTERWORKING
4070static char * anqp_add_hex(char *pos, char *end, const char *title,
4071 struct wpabuf *data)
4072{
4073 char *start = pos;
4074 size_t i;
4075 int ret;
4076 const u8 *d;
4077
4078 if (data == NULL)
4079 return start;
4080
4081 ret = os_snprintf(pos, end - pos, "%s=", title);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004082 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004083 return start;
4084 pos += ret;
4085
4086 d = wpabuf_head_u8(data);
4087 for (i = 0; i < wpabuf_len(data); i++) {
4088 ret = os_snprintf(pos, end - pos, "%02x", *d++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004089 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004090 return start;
4091 pos += ret;
4092 }
4093
4094 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004095 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004096 return start;
4097 pos += ret;
4098
4099 return pos;
4100}
4101#endif /* CONFIG_INTERWORKING */
4102
4103
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004104static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
4105 unsigned long mask, char *buf, size_t buflen)
4106{
4107 size_t i;
4108 int ret;
4109 char *pos, *end;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07004110 const u8 *ie, *ie2, *osen_ie;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004111
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004112 pos = buf;
4113 end = buf + buflen;
4114
4115 if (mask & WPA_BSS_MASK_ID) {
4116 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004117 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004118 return 0;
4119 pos += ret;
4120 }
4121
4122 if (mask & WPA_BSS_MASK_BSSID) {
4123 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
4124 MAC2STR(bss->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004125 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004126 return 0;
4127 pos += ret;
4128 }
4129
4130 if (mask & WPA_BSS_MASK_FREQ) {
4131 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004132 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004133 return 0;
4134 pos += ret;
4135 }
4136
4137 if (mask & WPA_BSS_MASK_BEACON_INT) {
4138 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
4139 bss->beacon_int);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004140 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004141 return 0;
4142 pos += ret;
4143 }
4144
4145 if (mask & WPA_BSS_MASK_CAPABILITIES) {
4146 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
4147 bss->caps);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004148 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004149 return 0;
4150 pos += ret;
4151 }
4152
4153 if (mask & WPA_BSS_MASK_QUAL) {
4154 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004155 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004156 return 0;
4157 pos += ret;
4158 }
4159
4160 if (mask & WPA_BSS_MASK_NOISE) {
4161 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004162 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004163 return 0;
4164 pos += ret;
4165 }
4166
4167 if (mask & WPA_BSS_MASK_LEVEL) {
4168 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004169 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004170 return 0;
4171 pos += ret;
4172 }
4173
4174 if (mask & WPA_BSS_MASK_TSF) {
4175 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
4176 (unsigned long long) bss->tsf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004177 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004178 return 0;
4179 pos += ret;
4180 }
4181
4182 if (mask & WPA_BSS_MASK_AGE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004183 struct os_reltime now;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004184
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004185 os_get_reltime(&now);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004186 ret = os_snprintf(pos, end - pos, "age=%d\n",
4187 (int) (now.sec - bss->last_update.sec));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004188 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004189 return 0;
4190 pos += ret;
4191 }
4192
4193 if (mask & WPA_BSS_MASK_IE) {
4194 ret = os_snprintf(pos, end - pos, "ie=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004195 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004196 return 0;
4197 pos += ret;
4198
4199 ie = (const u8 *) (bss + 1);
4200 for (i = 0; i < bss->ie_len; i++) {
4201 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004202 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004203 return 0;
4204 pos += ret;
4205 }
4206
4207 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004208 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004209 return 0;
4210 pos += ret;
4211 }
4212
4213 if (mask & WPA_BSS_MASK_FLAGS) {
4214 ret = os_snprintf(pos, end - pos, "flags=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004215 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004216 return 0;
4217 pos += ret;
4218
4219 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
4220 if (ie)
4221 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
4222 2 + ie[1]);
4223 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
4224 if (ie2)
4225 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
4226 2 + ie2[1]);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07004227 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
4228 if (osen_ie)
4229 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
4230 osen_ie, 2 + osen_ie[1]);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004231 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07004232 if (!ie && !ie2 && !osen_ie &&
4233 (bss->caps & IEEE80211_CAP_PRIVACY)) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004234 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004235 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004236 return 0;
4237 pos += ret;
4238 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004239 if (bss_is_dmg(bss)) {
4240 const char *s;
4241 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004242 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004243 return 0;
4244 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004245 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
4246 case IEEE80211_CAP_DMG_IBSS:
4247 s = "[IBSS]";
4248 break;
4249 case IEEE80211_CAP_DMG_AP:
4250 s = "[ESS]";
4251 break;
4252 case IEEE80211_CAP_DMG_PBSS:
4253 s = "[PBSS]";
4254 break;
4255 default:
4256 s = "";
4257 break;
4258 }
4259 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004260 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004261 return 0;
4262 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004263 } else {
4264 if (bss->caps & IEEE80211_CAP_IBSS) {
4265 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004266 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004267 return 0;
4268 pos += ret;
4269 }
4270 if (bss->caps & IEEE80211_CAP_ESS) {
4271 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004272 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07004273 return 0;
4274 pos += ret;
4275 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004276 }
Dmitry Shmidt96571392013-10-14 12:54:46 -07004277 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
4278 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004279 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004280 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004281 return 0;
4282 pos += ret;
4283 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004284#ifdef CONFIG_HS20
4285 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
4286 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004287 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004288 return 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004289 pos += ret;
4290 }
4291#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004292#ifdef CONFIG_FILS
4293 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
4294 ret = os_snprintf(pos, end - pos, "[FILS]");
4295 if (os_snprintf_error(end - pos, ret))
4296 return 0;
4297 pos += ret;
4298 }
4299#endif /* CONFIG_FILS */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004300
4301 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004302 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004303 return 0;
4304 pos += ret;
4305 }
4306
4307 if (mask & WPA_BSS_MASK_SSID) {
4308 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
4309 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004310 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004311 return 0;
4312 pos += ret;
4313 }
4314
4315#ifdef CONFIG_WPS
4316 if (mask & WPA_BSS_MASK_WPS_SCAN) {
4317 ie = (const u8 *) (bss + 1);
4318 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004319 if (ret >= end - pos)
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004320 return 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004321 if (ret > 0)
4322 pos += ret;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004323 }
4324#endif /* CONFIG_WPS */
4325
4326#ifdef CONFIG_P2P
4327 if (mask & WPA_BSS_MASK_P2P_SCAN) {
4328 ie = (const u8 *) (bss + 1);
4329 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004330 if (ret >= end - pos)
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004331 return 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004332 if (ret > 0)
4333 pos += ret;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004334 }
4335#endif /* CONFIG_P2P */
4336
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004337#ifdef CONFIG_WIFI_DISPLAY
4338 if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
4339 struct wpabuf *wfd;
4340 ie = (const u8 *) (bss + 1);
4341 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
4342 WFD_IE_VENDOR_TYPE);
4343 if (wfd) {
4344 ret = os_snprintf(pos, end - pos, "wfd_subelems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004345 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004346 wpabuf_free(wfd);
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004347 return 0;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004348 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004349 pos += ret;
4350
4351 pos += wpa_snprintf_hex(pos, end - pos,
4352 wpabuf_head(wfd),
4353 wpabuf_len(wfd));
4354 wpabuf_free(wfd);
4355
4356 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004357 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004358 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004359 pos += ret;
4360 }
4361 }
4362#endif /* CONFIG_WIFI_DISPLAY */
4363
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004364#ifdef CONFIG_INTERWORKING
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004365 if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
4366 struct wpa_bss_anqp *anqp = bss->anqp;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004367 struct wpa_bss_anqp_elem *elem;
4368
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004369 pos = anqp_add_hex(pos, end, "anqp_capability_list",
4370 anqp->capability_list);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004371 pos = anqp_add_hex(pos, end, "anqp_venue_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004372 anqp->venue_name);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004373 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004374 anqp->network_auth_type);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004375 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004376 anqp->roaming_consortium);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004377 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004378 anqp->ip_addr_type_availability);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004379 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004380 anqp->nai_realm);
4381 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004382 pos = anqp_add_hex(pos, end, "anqp_domain_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004383 anqp->domain_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004384#ifdef CONFIG_HS20
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004385 pos = anqp_add_hex(pos, end, "hs20_capability_list",
4386 anqp->hs20_capability_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004387 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004388 anqp->hs20_operator_friendly_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004389 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004390 anqp->hs20_wan_metrics);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004391 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004392 anqp->hs20_connection_capability);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004393 pos = anqp_add_hex(pos, end, "hs20_operating_class",
4394 anqp->hs20_operating_class);
4395 pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
4396 anqp->hs20_osu_providers_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004397#endif /* CONFIG_HS20 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004398
4399 dl_list_for_each(elem, &anqp->anqp_elems,
4400 struct wpa_bss_anqp_elem, list) {
4401 char title[20];
4402
4403 os_snprintf(title, sizeof(title), "anqp[%u]",
4404 elem->infoid);
4405 pos = anqp_add_hex(pos, end, title, elem->payload);
4406 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004407 }
4408#endif /* CONFIG_INTERWORKING */
4409
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004410#ifdef CONFIG_MESH
4411 if (mask & WPA_BSS_MASK_MESH_SCAN) {
4412 ie = (const u8 *) (bss + 1);
4413 ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004414 if (ret >= end - pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004415 return 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07004416 if (ret > 0)
4417 pos += ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004418 }
4419#endif /* CONFIG_MESH */
4420
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004421 if (mask & WPA_BSS_MASK_SNR) {
4422 ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
4423 if (os_snprintf_error(end - pos, ret))
4424 return 0;
4425 pos += ret;
4426 }
4427
4428 if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
4429 ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
4430 bss->est_throughput);
4431 if (os_snprintf_error(end - pos, ret))
4432 return 0;
4433 pos += ret;
4434 }
4435
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004436#ifdef CONFIG_FST
4437 if (mask & WPA_BSS_MASK_FST) {
4438 ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos);
4439 if (ret < 0 || ret >= end - pos)
4440 return 0;
4441 pos += ret;
4442 }
4443#endif /* CONFIG_FST */
4444
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004445 if (mask & WPA_BSS_MASK_DELIM) {
4446 ret = os_snprintf(pos, end - pos, "====\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004447 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004448 return 0;
4449 pos += ret;
4450 }
Irfan Sheriffe2ea0082012-08-13 10:56:16 -07004451
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004452 return pos - buf;
4453}
4454
Dmitry Shmidt04949592012-07-19 12:16:46 -07004455
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004456static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
4457 const char *cmd, char *buf,
4458 size_t buflen)
4459{
4460 u8 bssid[ETH_ALEN];
4461 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004462 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004463 struct wpa_bss *bsslast = NULL;
4464 struct dl_list *next;
4465 int ret = 0;
4466 int len;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004467 char *ctmp, *end = buf + buflen;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004468 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004469
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004470 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
4471 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
4472 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004473 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004474 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
4475 list_id);
4476 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004477 unsigned int id1, id2;
4478
4479 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
4480 wpa_printf(MSG_INFO, "Wrong BSS range "
4481 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004482 return 0;
4483 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004484
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004485 if (*(cmd + 6) == '-')
4486 id1 = 0;
4487 else
4488 id1 = atoi(cmd + 6);
4489 ctmp++;
4490 if (*ctmp >= '0' && *ctmp <= '9')
4491 id2 = atoi(ctmp);
4492 else
4493 id2 = (unsigned int) -1;
4494 bss = wpa_bss_get_id_range(wpa_s, id1, id2);
4495 if (id2 == (unsigned int) -1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004496 bsslast = dl_list_last(&wpa_s->bss_id,
4497 struct wpa_bss,
4498 list_id);
4499 else {
4500 bsslast = wpa_bss_get_id(wpa_s, id2);
4501 if (bsslast == NULL && bss && id2 > id1) {
4502 struct wpa_bss *tmp = bss;
4503 for (;;) {
4504 next = tmp->list_id.next;
4505 if (next == &wpa_s->bss_id)
4506 break;
4507 tmp = dl_list_entry(
4508 next, struct wpa_bss,
4509 list_id);
4510 if (tmp->id > id2)
4511 break;
4512 bsslast = tmp;
4513 }
4514 }
4515 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004516 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004517 } else if (os_strncmp(cmd, "FIRST", 5) == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004518 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004519 else if (os_strncmp(cmd, "LAST", 4) == 0)
4520 bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004521 else if (os_strncmp(cmd, "ID-", 3) == 0) {
4522 i = atoi(cmd + 3);
4523 bss = wpa_bss_get_id(wpa_s, i);
4524 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4525 i = atoi(cmd + 5);
4526 bss = wpa_bss_get_id(wpa_s, i);
4527 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004528 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004529 if (next == &wpa_s->bss_id)
4530 bss = NULL;
4531 else
4532 bss = dl_list_entry(next, struct wpa_bss,
4533 list_id);
4534 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004535#ifdef CONFIG_P2P
4536 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
4537 if (hwaddr_aton(cmd + 13, bssid) == 0)
4538 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
4539 else
4540 bss = NULL;
4541#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004542 } else if (hwaddr_aton(cmd, bssid) == 0)
4543 bss = wpa_bss_get_bssid(wpa_s, bssid);
4544 else {
4545 struct wpa_bss *tmp;
4546 i = atoi(cmd);
4547 bss = NULL;
4548 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
4549 {
4550 if (i-- == 0) {
4551 bss = tmp;
4552 break;
4553 }
4554 }
4555 }
4556
Dmitry Shmidt04949592012-07-19 12:16:46 -07004557 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
4558 mask = strtoul(ctmp + 5, NULL, 0x10);
4559 if (mask == 0)
4560 mask = WPA_BSS_MASK_ALL;
4561 }
4562
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004563 if (bss == NULL)
4564 return 0;
4565
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004566 if (bsslast == NULL)
4567 bsslast = bss;
4568 do {
4569 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
4570 ret += len;
4571 buf += len;
4572 buflen -= len;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004573 if (bss == bsslast) {
4574 if ((mask & WPA_BSS_MASK_DELIM) && len &&
4575 (bss == dl_list_last(&wpa_s->bss_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004576 struct wpa_bss, list_id))) {
4577 int res;
4578
4579 res = os_snprintf(buf - 5, end - buf + 5,
4580 "####\n");
4581 if (os_snprintf_error(end - buf + 5, res)) {
4582 wpa_printf(MSG_DEBUG,
4583 "Could not add end delim");
4584 }
4585 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004586 break;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004587 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004588 next = bss->list_id.next;
4589 if (next == &wpa_s->bss_id)
4590 break;
4591 bss = dl_list_entry(next, struct wpa_bss, list_id);
4592 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004593
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004594 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004595}
4596
4597
4598static int wpa_supplicant_ctrl_iface_ap_scan(
4599 struct wpa_supplicant *wpa_s, char *cmd)
4600{
4601 int ap_scan = atoi(cmd);
4602 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
4603}
4604
4605
4606static int wpa_supplicant_ctrl_iface_scan_interval(
4607 struct wpa_supplicant *wpa_s, char *cmd)
4608{
4609 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004610 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004611}
4612
4613
4614static int wpa_supplicant_ctrl_iface_bss_expire_age(
4615 struct wpa_supplicant *wpa_s, char *cmd)
4616{
4617 int expire_age = atoi(cmd);
4618 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
4619}
4620
4621
4622static int wpa_supplicant_ctrl_iface_bss_expire_count(
4623 struct wpa_supplicant *wpa_s, char *cmd)
4624{
4625 int expire_count = atoi(cmd);
4626 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
4627}
4628
4629
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004630static void wpa_supplicant_ctrl_iface_bss_flush(
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07004631 struct wpa_supplicant *wpa_s, char *cmd)
4632{
4633 int flush_age = atoi(cmd);
4634
4635 if (flush_age == 0)
4636 wpa_bss_flush(wpa_s);
4637 else
4638 wpa_bss_flush_by_age(wpa_s, flush_age);
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07004639}
4640
4641
Dmitry Shmidt21de2142014-04-08 10:50:52 -07004642#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004643static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
4644{
4645 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
4646 /* MLME-DELETEKEYS.request */
4647 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
4648 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
4649 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
4650 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
4651#ifdef CONFIG_IEEE80211W
4652 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
4653 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
4654#endif /* CONFIG_IEEE80211W */
4655
4656 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
4657 0);
4658 /* MLME-SETPROTECTION.request(None) */
4659 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
4660 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
4661 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
4662 wpa_sm_drop_sa(wpa_s->wpa);
4663}
Dmitry Shmidt21de2142014-04-08 10:50:52 -07004664#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004665
4666
4667static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
4668 char *addr)
4669{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004670#ifdef CONFIG_NO_SCAN_PROCESSING
4671 return -1;
4672#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004673 u8 bssid[ETH_ALEN];
4674 struct wpa_bss *bss;
4675 struct wpa_ssid *ssid = wpa_s->current_ssid;
4676
4677 if (hwaddr_aton(addr, bssid)) {
4678 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
4679 "address '%s'", addr);
4680 return -1;
4681 }
4682
4683 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
4684
Dmitry Shmidt444d5672013-04-01 13:08:44 -07004685 if (!ssid) {
4686 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
4687 "configuration known for the target AP");
4688 return -1;
4689 }
4690
4691 bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004692 if (!bss) {
4693 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
4694 "from BSS table");
4695 return -1;
4696 }
4697
4698 /*
4699 * TODO: Find best network configuration block from configuration to
4700 * allow roaming to other networks
4701 */
4702
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004703 wpa_s->reassociate = 1;
4704 wpa_supplicant_connect(wpa_s, bss, ssid);
4705
4706 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004707#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004708}
4709
4710
4711#ifdef CONFIG_P2P
4712static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
4713{
4714 unsigned int timeout = atoi(cmd);
4715 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004716 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004717 u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004718 char *pos;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004719 unsigned int search_delay;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08004720 const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004721 u8 seek_count = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08004722 int freq = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004723
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07004724 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
4725 wpa_dbg(wpa_s, MSG_INFO,
4726 "Reject P2P_FIND since interface is disabled");
4727 return -1;
4728 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004729 if (os_strstr(cmd, "type=social"))
4730 type = P2P_FIND_ONLY_SOCIAL;
4731 else if (os_strstr(cmd, "type=progressive"))
4732 type = P2P_FIND_PROGRESSIVE;
4733
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004734 pos = os_strstr(cmd, "dev_id=");
4735 if (pos) {
4736 pos += 7;
4737 if (hwaddr_aton(pos, dev_id))
4738 return -1;
4739 _dev_id = dev_id;
4740 }
4741
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004742 pos = os_strstr(cmd, "dev_type=");
4743 if (pos) {
4744 pos += 9;
4745 if (wps_dev_type_str2bin(pos, dev_type) < 0)
4746 return -1;
4747 _dev_type = dev_type;
4748 }
4749
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004750 pos = os_strstr(cmd, "delay=");
4751 if (pos) {
4752 pos += 6;
4753 search_delay = atoi(pos);
4754 } else
4755 search_delay = wpas_p2p_search_delay(wpa_s);
4756
Dmitry Shmidt41712582015-06-29 11:02:15 -07004757 pos = os_strstr(cmd, "freq=");
4758 if (pos) {
4759 pos += 5;
4760 freq = atoi(pos);
4761 if (freq <= 0)
4762 return -1;
4763 }
4764
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004765 /* Must be searched for last, because it adds nul termination */
4766 pos = os_strstr(cmd, " seek=");
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07004767 if (pos)
4768 pos += 6;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004769 while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
4770 char *term;
4771
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07004772 _seek[seek_count++] = pos;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08004773 seek = _seek;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07004774 term = os_strchr(pos, ' ');
4775 if (!term)
4776 break;
4777 *term = '\0';
4778 pos = os_strstr(term + 1, "seek=");
4779 if (pos)
4780 pos += 5;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004781 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004782 if (seek_count > P2P_MAX_QUERY_HASH) {
4783 seek[0] = NULL;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08004784 seek_count = 1;
4785 }
4786
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004787 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08004788 _dev_id, search_delay, seek_count, seek, freq);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004789}
4790
4791
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004792static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
4793{
4794 const char *last = NULL;
4795 const char *token;
4796 long int token_len;
4797 unsigned int i;
4798
4799 /* Expected predefined CPT names delimited by ':' */
4800 for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) {
4801 if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
4802 wpa_printf(MSG_ERROR,
4803 "P2PS: CPT name list is too long, expected up to %d names",
4804 P2PS_FEATURE_CAPAB_CPT_MAX);
4805 cpt[0] = 0;
4806 return -1;
4807 }
4808
4809 token_len = last - token;
4810
4811 if (token_len == 3 &&
4812 os_memcmp(token, "UDP", token_len) == 0) {
4813 cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
4814 } else if (token_len == 3 &&
4815 os_memcmp(token, "MAC", token_len) == 0) {
4816 cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
4817 } else {
4818 wpa_printf(MSG_ERROR,
4819 "P2PS: Unsupported CPT name '%s'", token);
4820 cpt[0] = 0;
4821 return -1;
4822 }
4823
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004824 if (isblank((unsigned char) *last)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004825 i++;
4826 break;
4827 }
4828 }
4829 cpt[i] = 0;
4830 return 0;
4831}
4832
4833
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004834static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
4835{
4836 struct p2ps_provision *p2ps_prov;
4837 char *pos;
4838 size_t info_len = 0;
4839 char *info = NULL;
4840 u8 role = P2PS_SETUP_NONE;
4841 long long unsigned val;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004842 int i;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004843
4844 pos = os_strstr(cmd, "info=");
4845 if (pos) {
4846 pos += 5;
4847 info_len = os_strlen(pos);
4848
4849 if (info_len) {
4850 info = os_malloc(info_len + 1);
4851 if (info) {
4852 info_len = utf8_unescape(pos, info_len,
4853 info, info_len + 1);
4854 } else
4855 info_len = 0;
4856 }
4857 }
4858
4859 p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
4860 if (p2ps_prov == NULL) {
4861 os_free(info);
4862 return NULL;
4863 }
4864
4865 if (info) {
4866 os_memcpy(p2ps_prov->info, info, info_len);
4867 p2ps_prov->info[info_len] = '\0';
4868 os_free(info);
4869 }
4870
4871 pos = os_strstr(cmd, "status=");
4872 if (pos)
4873 p2ps_prov->status = atoi(pos + 7);
4874 else
4875 p2ps_prov->status = -1;
4876
4877 pos = os_strstr(cmd, "adv_id=");
4878 if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
4879 goto invalid_args;
4880 p2ps_prov->adv_id = val;
4881
4882 pos = os_strstr(cmd, "method=");
4883 if (pos)
4884 p2ps_prov->method = strtol(pos + 7, NULL, 16);
4885 else
4886 p2ps_prov->method = 0;
4887
4888 pos = os_strstr(cmd, "session=");
4889 if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
4890 goto invalid_args;
4891 p2ps_prov->session_id = val;
4892
4893 pos = os_strstr(cmd, "adv_mac=");
4894 if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
4895 goto invalid_args;
4896
4897 pos = os_strstr(cmd, "session_mac=");
4898 if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
4899 goto invalid_args;
4900
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004901 pos = os_strstr(cmd, "cpt=");
4902 if (pos) {
4903 if (p2ps_ctrl_parse_cpt_priority(pos + 4,
4904 p2ps_prov->cpt_priority))
4905 goto invalid_args;
4906 } else {
4907 p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
4908 }
4909
4910 for (i = 0; p2ps_prov->cpt_priority[i]; i++)
4911 p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
4912
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004913 /* force conncap with tstCap (no sanity checks) */
4914 pos = os_strstr(cmd, "tstCap=");
4915 if (pos) {
4916 role = strtol(pos + 7, NULL, 16);
4917 } else {
4918 pos = os_strstr(cmd, "role=");
4919 if (pos) {
4920 role = strtol(pos + 5, NULL, 16);
4921 if (role != P2PS_SETUP_CLIENT &&
4922 role != P2PS_SETUP_GROUP_OWNER)
4923 role = P2PS_SETUP_NONE;
4924 }
4925 }
4926 p2ps_prov->role = role;
4927
4928 return p2ps_prov;
4929
4930invalid_args:
4931 os_free(p2ps_prov);
4932 return NULL;
4933}
4934
4935
4936static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
4937{
4938 u8 addr[ETH_ALEN];
4939 struct p2ps_provision *p2ps_prov;
4940 char *pos;
4941
4942 /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
4943
4944 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
4945
4946 if (hwaddr_aton(cmd, addr))
4947 return -1;
4948
4949 pos = cmd + 17;
4950 if (*pos != ' ')
4951 return -1;
4952
4953 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
4954 if (!p2ps_prov)
4955 return -1;
4956
4957 if (p2ps_prov->status < 0) {
4958 os_free(p2ps_prov);
4959 return -1;
4960 }
4961
4962 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
4963 p2ps_prov);
4964}
4965
4966
4967static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
4968{
4969 u8 addr[ETH_ALEN];
4970 struct p2ps_provision *p2ps_prov;
4971 char *pos;
4972
4973 /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
4974 * session=<ses_id> mac=<ses_mac> [info=<infodata>]
4975 */
4976
4977 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
4978 if (hwaddr_aton(cmd, addr))
4979 return -1;
4980
4981 pos = cmd + 17;
4982 if (*pos != ' ')
4983 return -1;
4984
4985 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
4986 if (!p2ps_prov)
4987 return -1;
4988
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004989 p2ps_prov->pd_seeker = 1;
4990
Dmitry Shmidt216983b2015-02-06 10:50:36 -08004991 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
4992 p2ps_prov);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004993}
4994
4995
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08004996static int parse_freq(int chwidth, int freq2)
4997{
4998 if (freq2 < 0)
4999 return -1;
5000 if (freq2)
5001 return VHT_CHANWIDTH_80P80MHZ;
5002
5003 switch (chwidth) {
5004 case 0:
5005 case 20:
5006 case 40:
5007 return VHT_CHANWIDTH_USE_HT;
5008 case 80:
5009 return VHT_CHANWIDTH_80MHZ;
5010 case 160:
5011 return VHT_CHANWIDTH_160MHZ;
5012 default:
5013 wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
5014 chwidth);
5015 return -1;
5016 }
5017}
5018
5019
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005020static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
5021 char *buf, size_t buflen)
5022{
5023 u8 addr[ETH_ALEN];
5024 char *pos, *pos2;
5025 char *pin = NULL;
5026 enum p2p_wps_method wps_method;
5027 int new_pin;
5028 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005029 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005030 int join;
5031 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005032 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005033 int go_intent = -1;
5034 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005035 int pd;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005036 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005037 u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
5038 size_t group_ssid_len = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005039
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005040 if (!wpa_s->global->p2p_init_wpa_s)
5041 return -1;
5042 if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
5043 wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
5044 wpa_s->global->p2p_init_wpa_s->ifname);
5045 wpa_s = wpa_s->global->p2p_init_wpa_s;
5046 }
5047
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005048 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
Dmitry Shmidt04949592012-07-19 12:16:46 -07005049 * [persistent|persistent=<network id>]
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005050 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005051 * [ht40] [vht] [auto] [ssid=<hexdump>] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005052
5053 if (hwaddr_aton(cmd, addr))
5054 return -1;
5055
5056 pos = cmd + 17;
5057 if (*pos != ' ')
5058 return -1;
5059 pos++;
5060
5061 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005062 pos2 = os_strstr(pos, " persistent=");
5063 if (pos2) {
5064 struct wpa_ssid *ssid;
5065 persistent_id = atoi(pos2 + 12);
5066 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
5067 if (ssid == NULL || ssid->disabled != 2 ||
5068 ssid->mode != WPAS_MODE_P2P_GO) {
5069 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
5070 "SSID id=%d for persistent P2P group (GO)",
5071 persistent_id);
5072 return -1;
5073 }
5074 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005075 join = os_strstr(pos, " join") != NULL;
5076 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005077 automatic = os_strstr(pos, " auto") != NULL;
5078 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005079 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5080 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5081 vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005082
5083 pos2 = os_strstr(pos, " go_intent=");
5084 if (pos2) {
5085 pos2 += 11;
5086 go_intent = atoi(pos2);
5087 if (go_intent < 0 || go_intent > 15)
5088 return -1;
5089 }
5090
5091 pos2 = os_strstr(pos, " freq=");
5092 if (pos2) {
5093 pos2 += 6;
5094 freq = atoi(pos2);
5095 if (freq <= 0)
5096 return -1;
5097 }
5098
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005099 pos2 = os_strstr(pos, " freq2=");
5100 if (pos2)
5101 freq2 = atoi(pos2 + 7);
5102
5103 pos2 = os_strstr(pos, " max_oper_chwidth=");
5104 if (pos2)
5105 chwidth = atoi(pos2 + 18);
5106
5107 max_oper_chwidth = parse_freq(chwidth, freq2);
5108 if (max_oper_chwidth < 0)
5109 return -1;
5110
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005111 pos2 = os_strstr(pos, " ssid=");
5112 if (pos2) {
5113 char *end;
5114
5115 pos2 += 6;
5116 end = os_strchr(pos2, ' ');
5117 if (!end)
5118 group_ssid_len = os_strlen(pos2) / 2;
5119 else
5120 group_ssid_len = (end - pos2) / 2;
5121 if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
5122 hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
5123 return -1;
5124 group_ssid = _group_ssid;
5125 }
5126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005127 if (os_strncmp(pos, "pin", 3) == 0) {
5128 /* Request random PIN (to be displayed) and enable the PIN */
5129 wps_method = WPS_PIN_DISPLAY;
5130 } else if (os_strncmp(pos, "pbc", 3) == 0) {
5131 wps_method = WPS_PBC;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005132 } else if (os_strstr(pos, "p2ps") != NULL) {
5133 wps_method = WPS_P2PS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005134 } else {
5135 pin = pos;
5136 pos = os_strchr(pin, ' ');
5137 wps_method = WPS_PIN_KEYPAD;
5138 if (pos) {
5139 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005140 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005141 wps_method = WPS_PIN_DISPLAY;
5142 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07005143 if (!wps_pin_str_valid(pin)) {
5144 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
5145 return 17;
5146 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005147 }
5148
5149 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07005150 persistent_group, automatic, join,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005151 auth, go_intent, freq, freq2, persistent_id,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08005152 pd, ht40, vht, max_oper_chwidth,
5153 group_ssid, group_ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005154 if (new_pin == -2) {
5155 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
5156 return 25;
5157 }
5158 if (new_pin == -3) {
5159 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
5160 return 25;
5161 }
5162 if (new_pin < 0)
5163 return -1;
5164 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
5165 ret = os_snprintf(buf, buflen, "%08d", new_pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005166 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005167 return -1;
5168 return ret;
5169 }
5170
5171 os_memcpy(buf, "OK\n", 3);
5172 return 3;
5173}
5174
5175
5176static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
5177{
5178 unsigned int timeout = atoi(cmd);
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07005179 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
5180 wpa_dbg(wpa_s, MSG_INFO,
5181 "Reject P2P_LISTEN since interface is disabled");
5182 return -1;
5183 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005184 return wpas_p2p_listen(wpa_s, timeout);
5185}
5186
5187
5188static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
5189{
5190 u8 addr[ETH_ALEN];
5191 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005192 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005193
Dmitry Shmidt04949592012-07-19 12:16:46 -07005194 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005195
5196 if (hwaddr_aton(cmd, addr))
5197 return -1;
5198
5199 pos = cmd + 17;
5200 if (*pos != ' ')
5201 return -1;
5202 pos++;
5203
Dmitry Shmidt04949592012-07-19 12:16:46 -07005204 if (os_strstr(pos, " join") != NULL)
5205 use = WPAS_P2P_PD_FOR_JOIN;
5206 else if (os_strstr(pos, " auto") != NULL)
5207 use = WPAS_P2P_PD_AUTO;
5208
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005209 return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005210}
5211
5212
5213static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
5214 size_t buflen)
5215{
5216 struct wpa_ssid *ssid = wpa_s->current_ssid;
5217
5218 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
5219 ssid->passphrase == NULL)
5220 return -1;
5221
5222 os_strlcpy(buf, ssid->passphrase, buflen);
5223 return os_strlen(buf);
5224}
5225
5226
5227static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
5228 char *buf, size_t buflen)
5229{
5230 u64 ref;
5231 int res;
5232 u8 dst_buf[ETH_ALEN], *dst;
5233 struct wpabuf *tlvs;
5234 char *pos;
5235 size_t len;
5236
5237 if (hwaddr_aton(cmd, dst_buf))
5238 return -1;
5239 dst = dst_buf;
5240 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
5241 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
5242 dst = NULL;
5243 pos = cmd + 17;
5244 if (*pos != ' ')
5245 return -1;
5246 pos++;
5247
5248 if (os_strncmp(pos, "upnp ", 5) == 0) {
5249 u8 version;
5250 pos += 5;
5251 if (hexstr2bin(pos, &version, 1) < 0)
5252 return -1;
5253 pos += 2;
5254 if (*pos != ' ')
5255 return -1;
5256 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005257 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005258#ifdef CONFIG_WIFI_DISPLAY
5259 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
5260 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
5261#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005262 } else if (os_strncmp(pos, "asp ", 4) == 0) {
5263 char *svc_str;
5264 char *svc_info = NULL;
5265 u32 id;
5266
5267 pos += 4;
5268 if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
5269 return -1;
5270
5271 pos = os_strchr(pos, ' ');
5272 if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
5273 return -1;
5274
5275 svc_str = pos + 1;
5276
5277 pos = os_strchr(svc_str, ' ');
5278
5279 if (pos)
5280 *pos++ = '\0';
5281
5282 /* All remaining data is the svc_info string */
5283 if (pos && pos[0] && pos[0] != ' ') {
5284 len = os_strlen(pos);
5285
5286 /* Unescape in place */
5287 len = utf8_unescape(pos, len, pos, len);
5288 if (len > 0xff)
5289 return -1;
5290
5291 svc_info = pos;
5292 }
5293
5294 ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
5295 svc_str, svc_info);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005296 } else {
5297 len = os_strlen(pos);
5298 if (len & 1)
5299 return -1;
5300 len /= 2;
5301 tlvs = wpabuf_alloc(len);
5302 if (tlvs == NULL)
5303 return -1;
5304 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
5305 wpabuf_free(tlvs);
5306 return -1;
5307 }
5308
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005309 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005310 wpabuf_free(tlvs);
5311 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005312 if (ref == 0)
5313 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005314 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005315 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005316 return -1;
5317 return res;
5318}
5319
5320
5321static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
5322 char *cmd)
5323{
5324 long long unsigned val;
5325 u64 req;
5326 if (sscanf(cmd, "%llx", &val) != 1)
5327 return -1;
5328 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005329 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005330}
5331
5332
5333static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
5334{
5335 int freq;
5336 u8 dst[ETH_ALEN];
5337 u8 dialog_token;
5338 struct wpabuf *resp_tlvs;
5339 char *pos, *pos2;
5340 size_t len;
5341
5342 pos = os_strchr(cmd, ' ');
5343 if (pos == NULL)
5344 return -1;
5345 *pos++ = '\0';
5346 freq = atoi(cmd);
5347 if (freq == 0)
5348 return -1;
5349
5350 if (hwaddr_aton(pos, dst))
5351 return -1;
5352 pos += 17;
5353 if (*pos != ' ')
5354 return -1;
5355 pos++;
5356
5357 pos2 = os_strchr(pos, ' ');
5358 if (pos2 == NULL)
5359 return -1;
5360 *pos2++ = '\0';
5361 dialog_token = atoi(pos);
5362
5363 len = os_strlen(pos2);
5364 if (len & 1)
5365 return -1;
5366 len /= 2;
5367 resp_tlvs = wpabuf_alloc(len);
5368 if (resp_tlvs == NULL)
5369 return -1;
5370 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
5371 wpabuf_free(resp_tlvs);
5372 return -1;
5373 }
5374
5375 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
5376 wpabuf_free(resp_tlvs);
5377 return 0;
5378}
5379
5380
5381static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
5382 char *cmd)
5383{
Dmitry Shmidt04949592012-07-19 12:16:46 -07005384 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
5385 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005386 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
5387 return 0;
5388}
5389
5390
5391static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
5392 char *cmd)
5393{
5394 char *pos;
5395 size_t len;
5396 struct wpabuf *query, *resp;
5397
5398 pos = os_strchr(cmd, ' ');
5399 if (pos == NULL)
5400 return -1;
5401 *pos++ = '\0';
5402
5403 len = os_strlen(cmd);
5404 if (len & 1)
5405 return -1;
5406 len /= 2;
5407 query = wpabuf_alloc(len);
5408 if (query == NULL)
5409 return -1;
5410 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5411 wpabuf_free(query);
5412 return -1;
5413 }
5414
5415 len = os_strlen(pos);
5416 if (len & 1) {
5417 wpabuf_free(query);
5418 return -1;
5419 }
5420 len /= 2;
5421 resp = wpabuf_alloc(len);
5422 if (resp == NULL) {
5423 wpabuf_free(query);
5424 return -1;
5425 }
5426 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
5427 wpabuf_free(query);
5428 wpabuf_free(resp);
5429 return -1;
5430 }
5431
5432 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
5433 wpabuf_free(query);
5434 wpabuf_free(resp);
5435 return -1;
5436 }
5437 return 0;
5438}
5439
5440
5441static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5442{
5443 char *pos;
5444 u8 version;
5445
5446 pos = os_strchr(cmd, ' ');
5447 if (pos == NULL)
5448 return -1;
5449 *pos++ = '\0';
5450
5451 if (hexstr2bin(cmd, &version, 1) < 0)
5452 return -1;
5453
5454 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
5455}
5456
5457
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005458static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
5459 u8 replace, char *cmd)
5460{
5461 char *pos;
5462 char *adv_str;
5463 u32 auto_accept, adv_id, svc_state, config_methods;
5464 char *svc_info = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005465 char *cpt_prio_str;
5466 u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005467
5468 pos = os_strchr(cmd, ' ');
5469 if (pos == NULL)
5470 return -1;
5471 *pos++ = '\0';
5472
5473 /* Auto-Accept value is mandatory, and must be one of the
5474 * single values (0, 1, 2, 4) */
5475 auto_accept = atoi(cmd);
5476 switch (auto_accept) {
5477 case P2PS_SETUP_NONE: /* No auto-accept */
5478 case P2PS_SETUP_NEW:
5479 case P2PS_SETUP_CLIENT:
5480 case P2PS_SETUP_GROUP_OWNER:
5481 break;
5482 default:
5483 return -1;
5484 }
5485
5486 /* Advertisement ID is mandatory */
5487 cmd = pos;
5488 pos = os_strchr(cmd, ' ');
5489 if (pos == NULL)
5490 return -1;
5491 *pos++ = '\0';
5492
5493 /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
5494 if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
5495 return -1;
5496
5497 /* Only allow replacements if exist, and adds if not */
5498 if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
5499 if (!replace)
5500 return -1;
5501 } else {
5502 if (replace)
5503 return -1;
5504 }
5505
5506 /* svc_state between 0 - 0xff is mandatory */
5507 if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
5508 return -1;
5509
5510 pos = os_strchr(pos, ' ');
5511 if (pos == NULL)
5512 return -1;
5513
5514 /* config_methods is mandatory */
5515 pos++;
5516 if (sscanf(pos, "%x", &config_methods) != 1)
5517 return -1;
5518
5519 if (!(config_methods &
5520 (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
5521 return -1;
5522
5523 pos = os_strchr(pos, ' ');
5524 if (pos == NULL)
5525 return -1;
5526
5527 pos++;
5528 adv_str = pos;
5529
5530 /* Advertisement string is mandatory */
5531 if (!pos[0] || pos[0] == ' ')
5532 return -1;
5533
5534 /* Terminate svc string */
5535 pos = os_strchr(pos, ' ');
5536 if (pos != NULL)
5537 *pos++ = '\0';
5538
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005539 cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL;
5540 if (cpt_prio_str) {
5541 pos = os_strchr(pos, ' ');
5542 if (pos != NULL)
5543 *pos++ = '\0';
5544
5545 if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio))
5546 return -1;
5547 } else {
5548 cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5549 cpt_prio[1] = 0;
5550 }
5551
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005552 /* Service and Response Information are optional */
5553 if (pos && pos[0]) {
5554 size_t len;
5555
5556 /* Note the bare ' included, which cannot exist legally
5557 * in unescaped string. */
5558 svc_info = os_strstr(pos, "svc_info='");
5559
5560 if (svc_info) {
5561 svc_info += 9;
5562 len = os_strlen(svc_info);
5563 utf8_unescape(svc_info, len, svc_info, len);
5564 }
5565 }
5566
5567 return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
5568 (u8) svc_state, (u16) config_methods,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005569 svc_info, cpt_prio);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005570}
5571
5572
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005573static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
5574{
5575 char *pos;
5576
5577 pos = os_strchr(cmd, ' ');
5578 if (pos == NULL)
5579 return -1;
5580 *pos++ = '\0';
5581
5582 if (os_strcmp(cmd, "bonjour") == 0)
5583 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
5584 if (os_strcmp(cmd, "upnp") == 0)
5585 return p2p_ctrl_service_add_upnp(wpa_s, pos);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005586 if (os_strcmp(cmd, "asp") == 0)
5587 return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005588 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5589 return -1;
5590}
5591
5592
5593static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
5594 char *cmd)
5595{
5596 size_t len;
5597 struct wpabuf *query;
5598 int ret;
5599
5600 len = os_strlen(cmd);
5601 if (len & 1)
5602 return -1;
5603 len /= 2;
5604 query = wpabuf_alloc(len);
5605 if (query == NULL)
5606 return -1;
5607 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5608 wpabuf_free(query);
5609 return -1;
5610 }
5611
5612 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
5613 wpabuf_free(query);
5614 return ret;
5615}
5616
5617
5618static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5619{
5620 char *pos;
5621 u8 version;
5622
5623 pos = os_strchr(cmd, ' ');
5624 if (pos == NULL)
5625 return -1;
5626 *pos++ = '\0';
5627
5628 if (hexstr2bin(cmd, &version, 1) < 0)
5629 return -1;
5630
5631 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
5632}
5633
5634
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005635static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
5636{
5637 u32 adv_id;
5638
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07005639 if (os_strcmp(cmd, "all") == 0) {
5640 wpas_p2p_service_flush_asp(wpa_s);
5641 return 0;
5642 }
5643
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005644 if (sscanf(cmd, "%x", &adv_id) != 1)
5645 return -1;
5646
5647 return wpas_p2p_service_del_asp(wpa_s, adv_id);
5648}
5649
5650
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005651static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
5652{
5653 char *pos;
5654
5655 pos = os_strchr(cmd, ' ');
5656 if (pos == NULL)
5657 return -1;
5658 *pos++ = '\0';
5659
5660 if (os_strcmp(cmd, "bonjour") == 0)
5661 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
5662 if (os_strcmp(cmd, "upnp") == 0)
5663 return p2p_ctrl_service_del_upnp(wpa_s, pos);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08005664 if (os_strcmp(cmd, "asp") == 0)
5665 return p2p_ctrl_service_del_asp(wpa_s, pos);
5666 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5667 return -1;
5668}
5669
5670
5671static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
5672{
5673 char *pos;
5674
5675 pos = os_strchr(cmd, ' ');
5676 if (pos == NULL)
5677 return -1;
5678 *pos++ = '\0';
5679
5680 if (os_strcmp(cmd, "asp") == 0)
5681 return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
5682
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005683 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5684 return -1;
5685}
5686
5687
5688static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
5689{
5690 u8 addr[ETH_ALEN];
5691
5692 /* <addr> */
5693
5694 if (hwaddr_aton(cmd, addr))
5695 return -1;
5696
5697 return wpas_p2p_reject(wpa_s, addr);
5698}
5699
5700
5701static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
5702{
5703 char *pos;
5704 int id;
5705 struct wpa_ssid *ssid;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005706 u8 *_peer = NULL, peer[ETH_ALEN];
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005707 int freq = 0, pref_freq = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005708 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005709
5710 id = atoi(cmd);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005711 pos = os_strstr(cmd, " peer=");
5712 if (pos) {
5713 pos += 6;
5714 if (hwaddr_aton(pos, peer))
5715 return -1;
5716 _peer = peer;
5717 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005718 ssid = wpa_config_get_network(wpa_s->conf, id);
5719 if (ssid == NULL || ssid->disabled != 2) {
5720 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
5721 "for persistent P2P group",
5722 id);
5723 return -1;
5724 }
5725
Jouni Malinen31be0a42012-08-31 21:20:51 +03005726 pos = os_strstr(cmd, " freq=");
5727 if (pos) {
5728 pos += 6;
5729 freq = atoi(pos);
5730 if (freq <= 0)
5731 return -1;
5732 }
5733
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08005734 pos = os_strstr(cmd, " pref=");
5735 if (pos) {
5736 pos += 6;
5737 pref_freq = atoi(pos);
5738 if (pref_freq <= 0)
5739 return -1;
5740 }
5741
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005742 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5743 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5744 vht;
Jouni Malinen31be0a42012-08-31 21:20:51 +03005745
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005746 pos = os_strstr(cmd, "freq2=");
5747 if (pos)
5748 freq2 = atoi(pos + 6);
5749
5750 pos = os_strstr(cmd, " max_oper_chwidth=");
5751 if (pos)
5752 chwidth = atoi(pos + 18);
5753
5754 max_oper_chwidth = parse_freq(chwidth, freq2);
5755 if (max_oper_chwidth < 0)
5756 return -1;
5757
5758 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
5759 max_oper_chwidth, pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005760}
5761
5762
5763static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
5764{
5765 char *pos;
5766 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
5767
5768 pos = os_strstr(cmd, " peer=");
5769 if (!pos)
5770 return -1;
5771
5772 *pos = '\0';
5773 pos += 6;
5774 if (hwaddr_aton(pos, peer)) {
5775 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
5776 return -1;
5777 }
5778
5779 pos = os_strstr(pos, " go_dev_addr=");
5780 if (pos) {
5781 pos += 13;
5782 if (hwaddr_aton(pos, go_dev_addr)) {
5783 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
5784 pos);
5785 return -1;
5786 }
5787 go_dev = go_dev_addr;
5788 }
5789
5790 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
5791}
5792
5793
5794static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
5795{
5796 if (os_strncmp(cmd, "persistent=", 11) == 0)
5797 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
5798 if (os_strncmp(cmd, "group=", 6) == 0)
5799 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
5800
5801 return -1;
5802}
5803
5804
5805static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005806 int id, int freq, int vht_center_freq2,
5807 int ht40, int vht, int vht_chwidth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005808{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005809 struct wpa_ssid *ssid;
5810
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005811 ssid = wpa_config_get_network(wpa_s->conf, id);
5812 if (ssid == NULL || ssid->disabled != 2) {
5813 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
5814 "for persistent P2P group",
5815 id);
5816 return -1;
5817 }
5818
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005819 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
5820 vht_center_freq2, 0, ht40, vht,
5821 vht_chwidth, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005822}
5823
5824
5825static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
5826{
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005827 int freq = 0, persistent = 0, group_id = -1;
5828 int vht = wpa_s->conf->p2p_go_vht;
5829 int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005830 int max_oper_chwidth, chwidth = 0, freq2 = 0;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005831 char *token, *context = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005832
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005833 while ((token = str_token(cmd, " ", &context))) {
5834 if (sscanf(token, "freq=%d", &freq) == 1 ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005835 sscanf(token, "freq2=%d", &freq2) == 1 ||
5836 sscanf(token, "persistent=%d", &group_id) == 1 ||
5837 sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005838 continue;
5839 } else if (os_strcmp(token, "ht40") == 0) {
5840 ht40 = 1;
5841 } else if (os_strcmp(token, "vht") == 0) {
5842 vht = 1;
5843 ht40 = 1;
5844 } else if (os_strcmp(token, "persistent") == 0) {
5845 persistent = 1;
5846 } else {
5847 wpa_printf(MSG_DEBUG,
5848 "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
5849 token);
5850 return -1;
5851 }
5852 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005853
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005854 max_oper_chwidth = parse_freq(chwidth, freq2);
5855 if (max_oper_chwidth < 0)
5856 return -1;
5857
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07005858 if (group_id >= 0)
5859 return p2p_ctrl_group_add_persistent(wpa_s, group_id,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005860 freq, freq2, ht40, vht,
5861 max_oper_chwidth);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005862
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08005863 return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
5864 max_oper_chwidth);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005865}
5866
5867
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005868static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
5869 char *buf, size_t buflen)
5870{
5871 u8 dev_addr[ETH_ALEN];
5872 struct wpa_ssid *ssid;
5873 int res;
5874 const u8 *iaddr;
5875
5876 ssid = wpa_s->current_ssid;
5877 if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
5878 hwaddr_aton(cmd, dev_addr))
5879 return -1;
5880
5881 iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
5882 if (!iaddr)
5883 return -1;
5884 res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
5885 if (os_snprintf_error(buflen, res))
5886 return -1;
5887 return res;
5888}
5889
5890
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005891static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
5892 char *buf, size_t buflen)
5893{
5894 u8 addr[ETH_ALEN], *addr_ptr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005895 int next, res;
5896 const struct p2p_peer_info *info;
5897 char *pos, *end;
5898 char devtype[WPS_DEV_TYPE_BUFSIZE];
5899 struct wpa_ssid *ssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005900 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005901
5902 if (!wpa_s->global->p2p)
5903 return -1;
5904
5905 if (os_strcmp(cmd, "FIRST") == 0) {
5906 addr_ptr = NULL;
5907 next = 0;
5908 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
5909 if (hwaddr_aton(cmd + 5, addr) < 0)
5910 return -1;
5911 addr_ptr = addr;
5912 next = 1;
5913 } else {
5914 if (hwaddr_aton(cmd, addr) < 0)
5915 return -1;
5916 addr_ptr = addr;
5917 next = 0;
5918 }
5919
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005920 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
5921 if (info == NULL)
5922 return -1;
5923
5924 pos = buf;
5925 end = buf + buflen;
5926
5927 res = os_snprintf(pos, end - pos, MACSTR "\n"
5928 "pri_dev_type=%s\n"
5929 "device_name=%s\n"
5930 "manufacturer=%s\n"
5931 "model_name=%s\n"
5932 "model_number=%s\n"
5933 "serial_number=%s\n"
5934 "config_methods=0x%x\n"
5935 "dev_capab=0x%x\n"
5936 "group_capab=0x%x\n"
5937 "level=%d\n",
5938 MAC2STR(info->p2p_device_addr),
5939 wps_dev_type_bin2str(info->pri_dev_type,
5940 devtype, sizeof(devtype)),
5941 info->device_name,
5942 info->manufacturer,
5943 info->model_name,
5944 info->model_number,
5945 info->serial_number,
5946 info->config_methods,
5947 info->dev_capab,
5948 info->group_capab,
5949 info->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005950 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005951 return pos - buf;
5952 pos += res;
5953
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005954 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
5955 {
5956 const u8 *t;
5957 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
5958 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
5959 wps_dev_type_bin2str(t, devtype,
5960 sizeof(devtype)));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005961 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005962 return pos - buf;
5963 pos += res;
5964 }
5965
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005966 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005967 if (ssid) {
5968 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005969 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005970 return pos - buf;
5971 pos += res;
5972 }
5973
5974 res = p2p_get_peer_info_txt(info, pos, end - pos);
5975 if (res < 0)
5976 return pos - buf;
5977 pos += res;
5978
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005979 if (info->vendor_elems) {
5980 res = os_snprintf(pos, end - pos, "vendor_elems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005981 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005982 return pos - buf;
5983 pos += res;
5984
5985 pos += wpa_snprintf_hex(pos, end - pos,
5986 wpabuf_head(info->vendor_elems),
5987 wpabuf_len(info->vendor_elems));
5988
5989 res = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005990 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005991 return pos - buf;
5992 pos += res;
5993 }
5994
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005995 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005996}
5997
5998
Dmitry Shmidt04949592012-07-19 12:16:46 -07005999static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
6000 const char *param)
6001{
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006002 unsigned int i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006003
6004 if (wpa_s->global->p2p == NULL)
6005 return -1;
6006
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006007 if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
6008 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006009
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006010 for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
6011 struct wpa_freq_range *freq;
6012 freq = &wpa_s->global->p2p_disallow_freq.range[i];
Dmitry Shmidt04949592012-07-19 12:16:46 -07006013 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07006014 freq->min, freq->max);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006015 }
6016
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006017 wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006018 return 0;
6019}
6020
6021
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006022static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
6023{
6024 char *param;
6025
6026 if (wpa_s->global->p2p == NULL)
6027 return -1;
6028
6029 param = os_strchr(cmd, ' ');
6030 if (param == NULL)
6031 return -1;
6032 *param++ = '\0';
6033
6034 if (os_strcmp(cmd, "discoverability") == 0) {
6035 p2p_set_client_discoverability(wpa_s->global->p2p,
6036 atoi(param));
6037 return 0;
6038 }
6039
6040 if (os_strcmp(cmd, "managed") == 0) {
6041 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
6042 return 0;
6043 }
6044
6045 if (os_strcmp(cmd, "listen_channel") == 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006046 char *pos;
6047 u8 channel, op_class;
6048
6049 channel = atoi(param);
6050 pos = os_strchr(param, ' ');
6051 op_class = pos ? atoi(pos) : 81;
6052
6053 return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
6054 channel, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006055 }
6056
6057 if (os_strcmp(cmd, "ssid_postfix") == 0) {
6058 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
6059 os_strlen(param));
6060 }
6061
6062 if (os_strcmp(cmd, "noa") == 0) {
6063 char *pos;
6064 int count, start, duration;
6065 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
6066 count = atoi(param);
6067 pos = os_strchr(param, ',');
6068 if (pos == NULL)
6069 return -1;
6070 pos++;
6071 start = atoi(pos);
6072 pos = os_strchr(pos, ',');
6073 if (pos == NULL)
6074 return -1;
6075 pos++;
6076 duration = atoi(pos);
6077 if (count < 0 || count > 255 || start < 0 || duration < 0)
6078 return -1;
6079 if (count == 0 && duration > 0)
6080 return -1;
6081 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
6082 "start=%d duration=%d", count, start, duration);
6083 return wpas_p2p_set_noa(wpa_s, count, start, duration);
6084 }
6085
6086 if (os_strcmp(cmd, "ps") == 0)
6087 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
6088
6089 if (os_strcmp(cmd, "oppps") == 0)
6090 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
6091
6092 if (os_strcmp(cmd, "ctwindow") == 0)
6093 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
6094
6095 if (os_strcmp(cmd, "disabled") == 0) {
6096 wpa_s->global->p2p_disabled = atoi(param);
6097 wpa_printf(MSG_DEBUG, "P2P functionality %s",
6098 wpa_s->global->p2p_disabled ?
6099 "disabled" : "enabled");
6100 if (wpa_s->global->p2p_disabled) {
6101 wpas_p2p_stop_find(wpa_s);
6102 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6103 p2p_flush(wpa_s->global->p2p);
6104 }
6105 return 0;
6106 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006107
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006108 if (os_strcmp(cmd, "conc_pref") == 0) {
6109 if (os_strcmp(param, "sta") == 0)
6110 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
6111 else if (os_strcmp(param, "p2p") == 0)
6112 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006113 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006114 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006115 return -1;
6116 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07006117 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07006118 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07006119 return 0;
6120 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006121
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006122 if (os_strcmp(cmd, "force_long_sd") == 0) {
6123 wpa_s->force_long_sd = atoi(param);
6124 return 0;
6125 }
6126
6127 if (os_strcmp(cmd, "peer_filter") == 0) {
6128 u8 addr[ETH_ALEN];
6129 if (hwaddr_aton(param, addr))
6130 return -1;
6131 p2p_set_peer_filter(wpa_s->global->p2p, addr);
6132 return 0;
6133 }
6134
6135 if (os_strcmp(cmd, "cross_connect") == 0)
6136 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
6137
6138 if (os_strcmp(cmd, "go_apsd") == 0) {
6139 if (os_strcmp(param, "disable") == 0)
6140 wpa_s->set_ap_uapsd = 0;
6141 else {
6142 wpa_s->set_ap_uapsd = 1;
6143 wpa_s->ap_uapsd = atoi(param);
6144 }
6145 return 0;
6146 }
6147
6148 if (os_strcmp(cmd, "client_apsd") == 0) {
6149 if (os_strcmp(param, "disable") == 0)
6150 wpa_s->set_sta_uapsd = 0;
6151 else {
6152 int be, bk, vi, vo;
6153 char *pos;
6154 /* format: BE,BK,VI,VO;max SP Length */
6155 be = atoi(param);
6156 pos = os_strchr(param, ',');
6157 if (pos == NULL)
6158 return -1;
6159 pos++;
6160 bk = atoi(pos);
6161 pos = os_strchr(pos, ',');
6162 if (pos == NULL)
6163 return -1;
6164 pos++;
6165 vi = atoi(pos);
6166 pos = os_strchr(pos, ',');
6167 if (pos == NULL)
6168 return -1;
6169 pos++;
6170 vo = atoi(pos);
6171 /* ignore max SP Length for now */
6172
6173 wpa_s->set_sta_uapsd = 1;
6174 wpa_s->sta_uapsd = 0;
6175 if (be)
6176 wpa_s->sta_uapsd |= BIT(0);
6177 if (bk)
6178 wpa_s->sta_uapsd |= BIT(1);
6179 if (vi)
6180 wpa_s->sta_uapsd |= BIT(2);
6181 if (vo)
6182 wpa_s->sta_uapsd |= BIT(3);
6183 }
6184 return 0;
6185 }
6186
Dmitry Shmidt04949592012-07-19 12:16:46 -07006187 if (os_strcmp(cmd, "disallow_freq") == 0)
6188 return p2p_ctrl_disallow_freq(wpa_s, param);
6189
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006190 if (os_strcmp(cmd, "disc_int") == 0) {
6191 int min_disc_int, max_disc_int, max_disc_tu;
6192 char *pos;
6193
6194 pos = param;
6195
6196 min_disc_int = atoi(pos);
6197 pos = os_strchr(pos, ' ');
6198 if (pos == NULL)
6199 return -1;
6200 *pos++ = '\0';
6201
6202 max_disc_int = atoi(pos);
6203 pos = os_strchr(pos, ' ');
6204 if (pos == NULL)
6205 return -1;
6206 *pos++ = '\0';
6207
6208 max_disc_tu = atoi(pos);
6209
6210 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
6211 max_disc_int, max_disc_tu);
6212 }
6213
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07006214 if (os_strcmp(cmd, "per_sta_psk") == 0) {
6215 wpa_s->global->p2p_per_sta_psk = !!atoi(param);
6216 return 0;
6217 }
6218
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08006219#ifdef CONFIG_WPS_NFC
6220 if (os_strcmp(cmd, "nfc_tag") == 0)
6221 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
6222#endif /* CONFIG_WPS_NFC */
6223
6224 if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
6225 wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
6226 return 0;
6227 }
6228
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006229 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
6230 cmd);
6231
6232 return -1;
6233}
6234
6235
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006236static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
6237{
6238 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6239 wpa_s->force_long_sd = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006240 wpas_p2p_stop_find(wpa_s);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006241 wpa_s->parent->p2ps_method_config_any = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006242 if (wpa_s->global->p2p)
6243 p2p_flush(wpa_s->global->p2p);
6244}
6245
6246
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006247static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
6248{
6249 char *pos, *pos2;
6250 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
6251
6252 if (cmd[0]) {
6253 pos = os_strchr(cmd, ' ');
6254 if (pos == NULL)
6255 return -1;
6256 *pos++ = '\0';
6257 dur1 = atoi(cmd);
6258
6259 pos2 = os_strchr(pos, ' ');
6260 if (pos2)
6261 *pos2++ = '\0';
6262 int1 = atoi(pos);
6263 } else
6264 pos2 = NULL;
6265
6266 if (pos2) {
6267 pos = os_strchr(pos2, ' ');
6268 if (pos == NULL)
6269 return -1;
6270 *pos++ = '\0';
6271 dur2 = atoi(pos2);
6272 int2 = atoi(pos);
6273 }
6274
6275 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
6276}
6277
6278
6279static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
6280{
6281 char *pos;
6282 unsigned int period = 0, interval = 0;
6283
6284 if (cmd[0]) {
6285 pos = os_strchr(cmd, ' ');
6286 if (pos == NULL)
6287 return -1;
6288 *pos++ = '\0';
6289 period = atoi(cmd);
6290 interval = atoi(pos);
6291 }
6292
6293 return wpas_p2p_ext_listen(wpa_s, period, interval);
6294}
6295
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07006296
6297static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
6298{
6299 const char *pos;
6300 u8 peer[ETH_ALEN];
6301 int iface_addr = 0;
6302
6303 pos = cmd;
6304 if (os_strncmp(pos, "iface=", 6) == 0) {
6305 iface_addr = 1;
6306 pos += 6;
6307 }
6308 if (hwaddr_aton(pos, peer))
6309 return -1;
6310
6311 wpas_p2p_remove_client(wpa_s, peer, iface_addr);
6312 return 0;
6313}
6314
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07006315
6316static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
6317{
6318 int freq = 0, period = 0, interval = 0, count = 0;
6319
6320 if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
6321 {
6322 wpa_printf(MSG_DEBUG,
6323 "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
6324 return -1;
6325 }
6326
6327 return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
6328}
6329
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006330#endif /* CONFIG_P2P */
6331
6332
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006333static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
6334{
6335 struct wpa_freq_range_list ranges;
6336 int *freqs = NULL;
6337 struct hostapd_hw_modes *mode;
6338 u16 i;
6339
6340 if (wpa_s->hw.modes == NULL)
6341 return NULL;
6342
6343 os_memset(&ranges, 0, sizeof(ranges));
6344 if (freq_range_list_parse(&ranges, val) < 0)
6345 return NULL;
6346
6347 for (i = 0; i < wpa_s->hw.num_modes; i++) {
6348 int j;
6349
6350 mode = &wpa_s->hw.modes[i];
6351 for (j = 0; j < mode->num_channels; j++) {
6352 unsigned int freq;
6353
6354 if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
6355 continue;
6356
6357 freq = mode->channels[j].freq;
6358 if (!freq_range_list_includes(&ranges, freq))
6359 continue;
6360
6361 int_array_add_unique(&freqs, freq);
6362 }
6363 }
6364
6365 os_free(ranges.range);
6366 return freqs;
6367}
6368
6369
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006370#ifdef CONFIG_INTERWORKING
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006371
6372static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
6373{
6374 int auto_sel = 0;
6375 int *freqs = NULL;
6376
6377 if (param) {
6378 char *pos;
6379
6380 auto_sel = os_strstr(param, "auto") != NULL;
6381
6382 pos = os_strstr(param, "freq=");
6383 if (pos) {
6384 freqs = freq_range_to_channel_list(wpa_s, pos + 5);
6385 if (freqs == NULL)
6386 return -1;
6387 }
6388
6389 }
6390
6391 return interworking_select(wpa_s, auto_sel, freqs);
6392}
6393
6394
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006395static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
6396 int only_add)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006397{
6398 u8 bssid[ETH_ALEN];
6399 struct wpa_bss *bss;
6400
6401 if (hwaddr_aton(dst, bssid)) {
6402 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
6403 return -1;
6404 }
6405
6406 bss = wpa_bss_get_bssid(wpa_s, bssid);
6407 if (bss == NULL) {
6408 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
6409 MAC2STR(bssid));
6410 return -1;
6411 }
6412
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006413 if (bss->ssid_len == 0) {
6414 int found = 0;
6415
6416 wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
6417 " does not have SSID information", MAC2STR(bssid));
6418
6419 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
6420 list) {
6421 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
6422 bss->ssid_len > 0) {
6423 found = 1;
6424 break;
6425 }
6426 }
6427
6428 if (!found)
6429 return -1;
6430 wpa_printf(MSG_DEBUG,
6431 "Found another matching BSS entry with SSID");
6432 }
6433
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006434 return interworking_connect(wpa_s, bss, only_add);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006435}
6436
6437
6438static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
6439{
6440 u8 dst_addr[ETH_ALEN];
6441 int used;
6442 char *pos;
6443#define MAX_ANQP_INFO_ID 100
6444 u16 id[MAX_ANQP_INFO_ID];
6445 size_t num_id = 0;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006446 u32 subtypes = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006447 int get_cell_pref = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006448
6449 used = hwaddr_aton2(dst, dst_addr);
6450 if (used < 0)
6451 return -1;
6452 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006453 if (*pos == ' ')
6454 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006455 while (num_id < MAX_ANQP_INFO_ID) {
Dmitry Shmidt15907092014-03-25 10:42:57 -07006456 if (os_strncmp(pos, "hs20:", 5) == 0) {
6457#ifdef CONFIG_HS20
6458 int num = atoi(pos + 5);
6459 if (num <= 0 || num > 31)
6460 return -1;
6461 subtypes |= BIT(num);
6462#else /* CONFIG_HS20 */
6463 return -1;
6464#endif /* CONFIG_HS20 */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006465 } else if (os_strncmp(pos, "mbo:", 4) == 0) {
6466#ifdef CONFIG_MBO
6467 int num = atoi(pos + 4);
6468 if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
6469 return -1;
6470 get_cell_pref = 1;
6471#else /* CONFIG_MBO */
6472 return -1;
6473#endif /* CONFIG_MBO */
Dmitry Shmidt15907092014-03-25 10:42:57 -07006474 } else {
6475 id[num_id] = atoi(pos);
6476 if (id[num_id])
6477 num_id++;
6478 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006479 pos = os_strchr(pos + 1, ',');
6480 if (pos == NULL)
6481 break;
6482 pos++;
6483 }
6484
6485 if (num_id == 0)
6486 return -1;
6487
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006488 return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
6489 get_cell_pref);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006490}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006491
6492
6493static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
6494{
6495 u8 dst_addr[ETH_ALEN];
6496 struct wpabuf *advproto, *query = NULL;
6497 int used, ret = -1;
6498 char *pos, *end;
6499 size_t len;
6500
6501 used = hwaddr_aton2(cmd, dst_addr);
6502 if (used < 0)
6503 return -1;
6504
6505 pos = cmd + used;
6506 while (*pos == ' ')
6507 pos++;
6508
6509 /* Advertisement Protocol ID */
6510 end = os_strchr(pos, ' ');
6511 if (end)
6512 len = end - pos;
6513 else
6514 len = os_strlen(pos);
6515 if (len & 0x01)
6516 return -1;
6517 len /= 2;
6518 if (len == 0)
6519 return -1;
6520 advproto = wpabuf_alloc(len);
6521 if (advproto == NULL)
6522 return -1;
6523 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
6524 goto fail;
6525
6526 if (end) {
6527 /* Optional Query Request */
6528 pos = end + 1;
6529 while (*pos == ' ')
6530 pos++;
6531
6532 len = os_strlen(pos);
6533 if (len) {
6534 if (len & 0x01)
6535 goto fail;
6536 len /= 2;
6537 if (len == 0)
6538 goto fail;
6539 query = wpabuf_alloc(len);
6540 if (query == NULL)
6541 goto fail;
6542 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
6543 goto fail;
6544 }
6545 }
6546
6547 ret = gas_send_request(wpa_s, dst_addr, advproto, query);
6548
6549fail:
6550 wpabuf_free(advproto);
6551 wpabuf_free(query);
6552
6553 return ret;
6554}
6555
6556
6557static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
6558 size_t buflen)
6559{
6560 u8 addr[ETH_ALEN];
6561 int dialog_token;
6562 int used;
6563 char *pos;
6564 size_t resp_len, start, requested_len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006565 struct wpabuf *resp;
6566 int ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006567
6568 used = hwaddr_aton2(cmd, addr);
6569 if (used < 0)
6570 return -1;
6571
6572 pos = cmd + used;
6573 while (*pos == ' ')
6574 pos++;
6575 dialog_token = atoi(pos);
6576
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006577 if (wpa_s->last_gas_resp &&
6578 os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
6579 dialog_token == wpa_s->last_gas_dialog_token)
6580 resp = wpa_s->last_gas_resp;
6581 else if (wpa_s->prev_gas_resp &&
6582 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
6583 dialog_token == wpa_s->prev_gas_dialog_token)
6584 resp = wpa_s->prev_gas_resp;
6585 else
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006586 return -1;
6587
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006588 resp_len = wpabuf_len(resp);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006589 start = 0;
6590 requested_len = resp_len;
6591
6592 pos = os_strchr(pos, ' ');
6593 if (pos) {
6594 start = atoi(pos);
6595 if (start > resp_len)
6596 return os_snprintf(buf, buflen, "FAIL-Invalid range");
6597 pos = os_strchr(pos, ',');
6598 if (pos == NULL)
6599 return -1;
6600 pos++;
6601 requested_len = atoi(pos);
6602 if (start + requested_len > resp_len)
6603 return os_snprintf(buf, buflen, "FAIL-Invalid range");
6604 }
6605
6606 if (requested_len * 2 + 1 > buflen)
6607 return os_snprintf(buf, buflen, "FAIL-Too long response");
6608
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006609 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
6610 requested_len);
6611
6612 if (start + requested_len == resp_len) {
6613 /*
6614 * Free memory by dropping the response after it has been
6615 * fetched.
6616 */
6617 if (resp == wpa_s->prev_gas_resp) {
6618 wpabuf_free(wpa_s->prev_gas_resp);
6619 wpa_s->prev_gas_resp = NULL;
6620 } else {
6621 wpabuf_free(wpa_s->last_gas_resp);
6622 wpa_s->last_gas_resp = NULL;
6623 }
6624 }
6625
6626 return ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006627}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006628#endif /* CONFIG_INTERWORKING */
6629
6630
Dmitry Shmidt04949592012-07-19 12:16:46 -07006631#ifdef CONFIG_HS20
6632
6633static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
6634{
6635 u8 dst_addr[ETH_ALEN];
6636 int used;
6637 char *pos;
6638 u32 subtypes = 0;
6639
6640 used = hwaddr_aton2(dst, dst_addr);
6641 if (used < 0)
6642 return -1;
6643 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006644 if (*pos == ' ')
6645 pos++;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006646 for (;;) {
6647 int num = atoi(pos);
6648 if (num <= 0 || num > 31)
6649 return -1;
6650 subtypes |= BIT(num);
6651 pos = os_strchr(pos + 1, ',');
6652 if (pos == NULL)
6653 break;
6654 pos++;
6655 }
6656
6657 if (subtypes == 0)
6658 return -1;
6659
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006660 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006661}
6662
6663
6664static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6665 const u8 *addr, const char *realm)
6666{
6667 u8 *buf;
6668 size_t rlen, len;
6669 int ret;
6670
6671 rlen = os_strlen(realm);
6672 len = 3 + rlen;
6673 buf = os_malloc(len);
6674 if (buf == NULL)
6675 return -1;
6676 buf[0] = 1; /* NAI Home Realm Count */
6677 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
6678 buf[2] = rlen;
6679 os_memcpy(buf + 3, realm, rlen);
6680
6681 ret = hs20_anqp_send_req(wpa_s, addr,
6682 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006683 buf, len, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006684
6685 os_free(buf);
6686
6687 return ret;
6688}
6689
6690
6691static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6692 char *dst)
6693{
6694 struct wpa_cred *cred = wpa_s->conf->cred;
6695 u8 dst_addr[ETH_ALEN];
6696 int used;
6697 u8 *buf;
6698 size_t len;
6699 int ret;
6700
6701 used = hwaddr_aton2(dst, dst_addr);
6702 if (used < 0)
6703 return -1;
6704
6705 while (dst[used] == ' ')
6706 used++;
6707 if (os_strncmp(dst + used, "realm=", 6) == 0)
6708 return hs20_nai_home_realm_list(wpa_s, dst_addr,
6709 dst + used + 6);
6710
6711 len = os_strlen(dst + used);
6712
6713 if (len == 0 && cred && cred->realm)
6714 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
6715
Dmitry Shmidt623d63a2014-06-13 11:05:14 -07006716 if (len & 1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07006717 return -1;
6718 len /= 2;
6719 buf = os_malloc(len);
6720 if (buf == NULL)
6721 return -1;
6722 if (hexstr2bin(dst + used, buf, len) < 0) {
6723 os_free(buf);
6724 return -1;
6725 }
6726
6727 ret = hs20_anqp_send_req(wpa_s, dst_addr,
6728 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006729 buf, len, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07006730 os_free(buf);
6731
6732 return ret;
6733}
6734
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006735
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006736static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
6737 int buflen)
6738{
6739 u8 dst_addr[ETH_ALEN];
6740 int used;
6741 char *ctx = NULL, *icon, *poffset, *psize;
6742
6743 used = hwaddr_aton2(cmd, dst_addr);
6744 if (used < 0)
6745 return -1;
6746 cmd += used;
6747
6748 icon = str_token(cmd, " ", &ctx);
6749 poffset = str_token(cmd, " ", &ctx);
6750 psize = str_token(cmd, " ", &ctx);
6751 if (!icon || !poffset || !psize)
6752 return -1;
6753
6754 wpa_s->fetch_osu_icon_in_progress = 0;
6755 return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
6756 reply, buflen);
6757}
6758
6759
6760static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
6761{
6762 u8 dst_addr[ETH_ALEN];
6763 int used;
6764 char *icon;
6765
6766 if (!cmd[0])
6767 return hs20_del_icon(wpa_s, NULL, NULL);
6768
6769 used = hwaddr_aton2(cmd, dst_addr);
6770 if (used < 0)
6771 return -1;
6772
6773 while (cmd[used] == ' ')
6774 used++;
6775 icon = cmd[used] ? &cmd[used] : NULL;
6776
6777 return hs20_del_icon(wpa_s, dst_addr, icon);
6778}
6779
6780
6781static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006782{
6783 u8 dst_addr[ETH_ALEN];
6784 int used;
6785 char *icon;
6786
6787 used = hwaddr_aton2(cmd, dst_addr);
6788 if (used < 0)
6789 return -1;
6790
6791 while (cmd[used] == ' ')
6792 used++;
6793 icon = &cmd[used];
6794
6795 wpa_s->fetch_osu_icon_in_progress = 0;
6796 return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006797 (u8 *) icon, os_strlen(icon), inmem);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006798}
6799
Dmitry Shmidt04949592012-07-19 12:16:46 -07006800#endif /* CONFIG_HS20 */
6801
6802
Dmitry Shmidt04949592012-07-19 12:16:46 -07006803#ifdef CONFIG_AUTOSCAN
6804
6805static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
6806 char *cmd)
6807{
6808 enum wpa_states state = wpa_s->wpa_state;
6809 char *new_params = NULL;
6810
6811 if (os_strlen(cmd) > 0) {
6812 new_params = os_strdup(cmd);
6813 if (new_params == NULL)
6814 return -1;
6815 }
6816
6817 os_free(wpa_s->conf->autoscan);
6818 wpa_s->conf->autoscan = new_params;
6819
6820 if (wpa_s->conf->autoscan == NULL)
6821 autoscan_deinit(wpa_s);
6822 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
6823 autoscan_init(wpa_s, 1);
6824 else if (state == WPA_SCANNING)
6825 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006826 else
6827 wpa_printf(MSG_DEBUG, "No autoscan update in state %s",
6828 wpa_supplicant_state_txt(state));
Dmitry Shmidt04949592012-07-19 12:16:46 -07006829
6830 return 0;
6831}
6832
6833#endif /* CONFIG_AUTOSCAN */
6834
6835
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006836#ifdef CONFIG_WNM
6837
6838static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
6839{
6840 int enter;
6841 int intval = 0;
6842 char *pos;
6843 int ret;
6844 struct wpabuf *tfs_req = NULL;
6845
6846 if (os_strncmp(cmd, "enter", 5) == 0)
6847 enter = 1;
6848 else if (os_strncmp(cmd, "exit", 4) == 0)
6849 enter = 0;
6850 else
6851 return -1;
6852
6853 pos = os_strstr(cmd, " interval=");
6854 if (pos)
6855 intval = atoi(pos + 10);
6856
6857 pos = os_strstr(cmd, " tfs_req=");
6858 if (pos) {
6859 char *end;
6860 size_t len;
6861 pos += 9;
6862 end = os_strchr(pos, ' ');
6863 if (end)
6864 len = end - pos;
6865 else
6866 len = os_strlen(pos);
6867 if (len & 1)
6868 return -1;
6869 len /= 2;
6870 tfs_req = wpabuf_alloc(len);
6871 if (tfs_req == NULL)
6872 return -1;
6873 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
6874 wpabuf_free(tfs_req);
6875 return -1;
6876 }
6877 }
6878
6879 ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
6880 WNM_SLEEP_MODE_EXIT, intval,
6881 tfs_req);
6882 wpabuf_free(tfs_req);
6883
6884 return ret;
6885}
6886
Dmitry Shmidt44c95782013-05-17 09:51:35 -07006887
6888static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
6889{
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006890 int query_reason, list = 0;
Dmitry Shmidt44c95782013-05-17 09:51:35 -07006891
6892 query_reason = atoi(cmd);
6893
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006894 cmd = os_strchr(cmd, ' ');
6895 if (cmd) {
6896 cmd++;
6897 if (os_strncmp(cmd, "list", 4) == 0) {
6898 list = 1;
6899 } else {
6900 wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
6901 cmd);
6902 return -1;
6903 }
6904 }
Dmitry Shmidt44c95782013-05-17 09:51:35 -07006905
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006906 wpa_printf(MSG_DEBUG,
6907 "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
6908 query_reason, list ? " candidate list" : "");
6909
6910 return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
Dmitry Shmidt44c95782013-05-17 09:51:35 -07006911}
6912
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006913#endif /* CONFIG_WNM */
6914
6915
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006916static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
6917 size_t buflen)
6918{
6919 struct wpa_signal_info si;
6920 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006921 char *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006922
6923 ret = wpa_drv_signal_poll(wpa_s, &si);
6924 if (ret)
6925 return -1;
6926
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006927 pos = buf;
6928 end = buf + buflen;
6929
6930 ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006931 "NOISE=%d\nFREQUENCY=%u\n",
6932 si.current_signal, si.current_txrate / 1000,
6933 si.current_noise, si.frequency);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006934 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006935 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006936 pos += ret;
6937
6938 if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
6939 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006940 channel_width_to_string(si.chanwidth));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006941 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006942 return -1;
6943 pos += ret;
6944 }
6945
6946 if (si.center_frq1 > 0 && si.center_frq2 > 0) {
6947 ret = os_snprintf(pos, end - pos,
6948 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
6949 si.center_frq1, si.center_frq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006950 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006951 return -1;
6952 pos += ret;
6953 }
6954
6955 if (si.avg_signal) {
6956 ret = os_snprintf(pos, end - pos,
6957 "AVG_RSSI=%d\n", si.avg_signal);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006958 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006959 return -1;
6960 pos += ret;
6961 }
6962
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07006963 if (si.avg_beacon_signal) {
6964 ret = os_snprintf(pos, end - pos,
6965 "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
6966 if (os_snprintf_error(end - pos, ret))
6967 return -1;
6968 pos += ret;
6969 }
6970
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006971 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006972}
6973
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03006974
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08006975static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
6976 const char *cmd)
6977{
6978 const char *pos;
6979 int threshold = 0;
6980 int hysteresis = 0;
6981
6982 if (wpa_s->bgscan && wpa_s->bgscan_priv) {
6983 wpa_printf(MSG_DEBUG,
6984 "Reject SIGNAL_MONITOR command - bgscan is active");
6985 return -1;
6986 }
6987 pos = os_strstr(cmd, "THRESHOLD=");
6988 if (pos)
6989 threshold = atoi(pos + 10);
6990 pos = os_strstr(cmd, "HYSTERESIS=");
6991 if (pos)
6992 hysteresis = atoi(pos + 11);
6993 return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
6994}
6995
6996
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006997static int wpas_ctrl_iface_get_pref_freq_list(
6998 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
6999{
7000 unsigned int freq_list[100], num = 100, i;
7001 int ret;
7002 enum wpa_driver_if_type iface_type;
7003 char *pos, *end;
7004
7005 pos = buf;
7006 end = buf + buflen;
7007
7008 /* buf: "<interface_type>" */
7009 if (os_strcmp(cmd, "STATION") == 0)
7010 iface_type = WPA_IF_STATION;
7011 else if (os_strcmp(cmd, "AP") == 0)
7012 iface_type = WPA_IF_AP_BSS;
7013 else if (os_strcmp(cmd, "P2P_GO") == 0)
7014 iface_type = WPA_IF_P2P_GO;
7015 else if (os_strcmp(cmd, "P2P_CLIENT") == 0)
7016 iface_type = WPA_IF_P2P_CLIENT;
7017 else if (os_strcmp(cmd, "IBSS") == 0)
7018 iface_type = WPA_IF_IBSS;
7019 else if (os_strcmp(cmd, "TDLS") == 0)
7020 iface_type = WPA_IF_TDLS;
7021 else
7022 return -1;
7023
7024 wpa_printf(MSG_DEBUG,
7025 "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
7026 iface_type, buf);
7027
7028 ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
7029 if (ret)
7030 return -1;
7031
7032 for (i = 0; i < num; i++) {
7033 ret = os_snprintf(pos, end - pos, "%s%u",
7034 i > 0 ? "," : "", freq_list[i]);
7035 if (os_snprintf_error(end - pos, ret))
7036 return -1;
7037 pos += ret;
7038 }
7039
7040 return pos - buf;
7041}
7042
7043
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07007044static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
7045 char *buf, size_t buflen)
7046{
7047 int ret, i;
7048 char *pos, *end;
7049
7050 ret = os_snprintf(buf, buflen, "%016llX:\n",
7051 (long long unsigned) wpa_s->drv_flags);
7052 if (os_snprintf_error(buflen, ret))
7053 return -1;
7054
7055 pos = buf + ret;
7056 end = buf + buflen;
7057
7058 for (i = 0; i < 64; i++) {
7059 if (wpa_s->drv_flags & (1LLU << i)) {
7060 ret = os_snprintf(pos, end - pos, "%s\n",
7061 driver_flag_to_string(1LLU << i));
7062 if (os_snprintf_error(end - pos, ret))
7063 return -1;
7064 pos += ret;
7065 }
7066 }
7067
7068 return pos - buf;
7069}
7070
7071
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07007072static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
7073 size_t buflen)
7074{
7075 struct hostap_sta_driver_data sta;
7076 int ret;
7077
7078 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
7079 if (ret)
7080 return -1;
7081
7082 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007083 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007084 if (os_snprintf_error(buflen, ret))
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07007085 return -1;
7086 return ret;
7087}
7088
7089
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007090#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007091static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7092 char *buf, size_t buflen)
7093{
7094 int ret;
7095
7096 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
Dmitry Shmidt9432e122013-09-12 12:39:30 -07007097 if (ret == 0) {
7098 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
7099 struct p2p_data *p2p = wpa_s->global->p2p;
7100 if (p2p) {
7101 char country[3];
7102 country[0] = cmd[8];
7103 country[1] = cmd[9];
7104 country[2] = 0x04;
7105 p2p_set_country(p2p, country);
7106 }
7107 }
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08007108 ret = os_snprintf(buf, buflen, "%s\n", "OK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007109 if (os_snprintf_error(buflen, ret))
7110 ret = -1;
Dmitry Shmidt9432e122013-09-12 12:39:30 -07007111 }
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007112 return ret;
7113}
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08007114#endif /* ANDROID */
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007115
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07007116
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007117static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7118 char *buf, size_t buflen)
7119{
7120 int ret;
7121 char *pos;
7122 u8 *data = NULL;
7123 unsigned int vendor_id, subcmd;
7124 struct wpabuf *reply;
7125 size_t data_len = 0;
7126
7127 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
7128 vendor_id = strtoul(cmd, &pos, 16);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007129 if (!isblank((unsigned char) *pos))
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007130 return -EINVAL;
7131
7132 subcmd = strtoul(pos, &pos, 10);
7133
7134 if (*pos != '\0') {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007135 if (!isblank((unsigned char) *pos++))
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007136 return -EINVAL;
7137 data_len = os_strlen(pos);
7138 }
7139
7140 if (data_len) {
7141 data_len /= 2;
7142 data = os_malloc(data_len);
7143 if (!data)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007144 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007145
7146 if (hexstr2bin(pos, data, data_len)) {
7147 wpa_printf(MSG_DEBUG,
7148 "Vendor command: wrong parameter format");
7149 os_free(data);
7150 return -EINVAL;
7151 }
7152 }
7153
7154 reply = wpabuf_alloc((buflen - 1) / 2);
7155 if (!reply) {
7156 os_free(data);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07007157 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007158 }
7159
7160 ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
7161 reply);
7162
7163 if (ret == 0)
7164 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
7165 wpabuf_len(reply));
7166
7167 wpabuf_free(reply);
7168 os_free(data);
7169
7170 return ret;
7171}
7172
7173
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007174static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
7175{
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007176#ifdef CONFIG_P2P
7177 struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
7178 wpa_s->global->p2p_init_wpa_s : wpa_s;
7179#endif /* CONFIG_P2P */
7180
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007181 wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
7182
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007183 wpas_abort_ongoing_scan(wpa_s);
7184
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007185 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
7186 /*
7187 * Avoid possible auto connect re-connection on getting
7188 * disconnected due to state flush.
7189 */
7190 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
7191 }
7192
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007193#ifdef CONFIG_P2P
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007194 wpas_p2p_group_remove(p2p_wpa_s, "*");
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007195 wpas_p2p_cancel(p2p_wpa_s);
7196 p2p_ctrl_flush(p2p_wpa_s);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007197 wpas_p2p_service_flush(p2p_wpa_s);
7198 p2p_wpa_s->global->p2p_disabled = 0;
7199 p2p_wpa_s->global->p2p_per_sta_psk = 0;
7200 p2p_wpa_s->conf->num_sec_device_types = 0;
7201 p2p_wpa_s->p2p_disable_ip_addr_req = 0;
7202 os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
7203 p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007204 p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08007205 p2p_wpa_s->global->pending_p2ps_group = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007206 p2p_wpa_s->global->pending_p2ps_group_freq = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007207#endif /* CONFIG_P2P */
7208
7209#ifdef CONFIG_WPS_TESTING
7210 wps_version_number = 0x20;
7211 wps_testing_dummy_cred = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08007212 wps_corrupt_pkhash = 0;
Dmitry Shmidtde47be72016-01-07 12:52:55 -08007213 wps_force_auth_types_in_use = 0;
7214 wps_force_encr_types_in_use = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007215#endif /* CONFIG_WPS_TESTING */
7216#ifdef CONFIG_WPS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007217 wpa_s->wps_fragment_size = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007218 wpas_wps_cancel(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007219 wps_registrar_flush(wpa_s->wps->registrar);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007220#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07007221 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007222 wpa_s->known_wps_freq = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007223
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007224#ifdef CONFIG_TDLS
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007225#ifdef CONFIG_TDLS_TESTING
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007226 tdls_testing = 0;
7227#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007228 wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
7229 wpa_tdls_enable(wpa_s->wpa, 1);
7230#endif /* CONFIG_TDLS */
7231
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007232 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
7233 wpa_supplicant_stop_countermeasures(wpa_s, NULL);
7234
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007235 wpa_s->no_keep_alive = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08007236 wpa_s->own_disconnect_req = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007237
7238 os_free(wpa_s->disallow_aps_bssid);
7239 wpa_s->disallow_aps_bssid = NULL;
7240 wpa_s->disallow_aps_bssid_count = 0;
7241 os_free(wpa_s->disallow_aps_ssid);
7242 wpa_s->disallow_aps_ssid = NULL;
7243 wpa_s->disallow_aps_ssid_count = 0;
7244
7245 wpa_s->set_sta_uapsd = 0;
7246 wpa_s->sta_uapsd = 0;
7247
7248 wpa_drv_radio_disable(wpa_s, 0);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007249 wpa_blacklist_clear(wpa_s);
Dmitry Shmidt4b060592013-04-29 16:42:49 -07007250 wpa_s->extra_blacklist_count = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007251 wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
7252 wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
Dmitry Shmidt344abd32014-01-14 13:17:00 -08007253 wpa_config_flush_blobs(wpa_s->conf);
Dmitry Shmidt18463232014-01-24 12:29:41 -08007254 wpa_s->conf->auto_interworking = 0;
7255 wpa_s->conf->okc = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007256
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007257 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
7258 rsn_preauth_deinit(wpa_s->wpa);
7259
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007260 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
7261 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
7262 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
7263 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
7264
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007265 radio_remove_works(wpa_s, NULL, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007266 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007267
7268 wpa_s->next_ssid = NULL;
7269
7270#ifdef CONFIG_INTERWORKING
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007271#ifdef CONFIG_HS20
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007272 hs20_cancel_fetch_osu(wpa_s);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08007273 hs20_del_icon(wpa_s, NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007274#endif /* CONFIG_HS20 */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007275#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt818ea482014-03-10 13:15:21 -07007276
7277 wpa_s->ext_mgmt_frame_handling = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007278 wpa_s->ext_eapol_frame_io = 0;
7279#ifdef CONFIG_TESTING_OPTIONS
7280 wpa_s->extra_roc_dur = 0;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007281 wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007282 wpa_s->p2p_go_csa_on_inv = 0;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07007283 wpa_s->ignore_auth_resp = 0;
7284 wpa_s->ignore_assoc_disallow = 0;
7285 wpa_s->reject_btm_req_reason = 0;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08007286 wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007287#endif /* CONFIG_TESTING_OPTIONS */
7288
7289 wpa_s->disconnected = 0;
7290 os_free(wpa_s->next_scan_freqs);
7291 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007292
7293 wpa_bss_flush(wpa_s);
7294 if (!dl_list_empty(&wpa_s->bss)) {
7295 wpa_printf(MSG_DEBUG,
7296 "BSS table not empty after flush: %u entries, current_bss=%p bssid="
7297 MACSTR " pending_bssid=" MACSTR,
7298 dl_list_len(&wpa_s->bss), wpa_s->current_bss,
7299 MAC2STR(wpa_s->bssid),
7300 MAC2STR(wpa_s->pending_bssid));
7301 }
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07007302
7303 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
Dmitry Shmidtb70d0bb2015-11-16 10:43:06 -08007304 wpa_s->wnmsleep_used = 0;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07007305
7306#ifdef CONFIG_SME
7307 wpa_s->sme.last_unprot_disconnect.sec = 0;
7308#endif /* CONFIG_SME */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007309}
7310
7311
7312static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
7313 char *buf, size_t buflen)
7314{
7315 struct wpa_radio_work *work;
7316 char *pos, *end;
7317 struct os_reltime now, diff;
7318
7319 pos = buf;
7320 end = buf + buflen;
7321
7322 os_get_reltime(&now);
7323
7324 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7325 {
7326 int ret;
7327
7328 os_reltime_sub(&now, &work->time, &diff);
7329 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
7330 work->type, work->wpa_s->ifname, work->freq,
7331 work->started, diff.sec, diff.usec);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007332 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007333 break;
7334 pos += ret;
7335 }
7336
7337 return pos - buf;
7338}
7339
7340
7341static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
7342{
7343 struct wpa_radio_work *work = eloop_ctx;
7344 struct wpa_external_work *ework = work->ctx;
7345
7346 wpa_dbg(work->wpa_s, MSG_DEBUG,
7347 "Timing out external radio work %u (%s)",
7348 ework->id, work->type);
7349 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007350 work->wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007351 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07007352 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007353}
7354
7355
7356static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
7357{
7358 struct wpa_external_work *ework = work->ctx;
7359
7360 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08007361 if (work->started)
7362 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7363 work, NULL);
7364
Dmitry Shmidt849734c2016-05-27 09:59:01 -07007365 /*
7366 * work->type points to a buffer in ework, so need to replace
7367 * that here with a fixed string to avoid use of freed memory
7368 * in debug prints.
7369 */
7370 work->type = "freed-ext-work";
7371 work->ctx = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007372 os_free(ework);
7373 return;
7374 }
7375
7376 wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
7377 ework->id, ework->type);
7378 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007379 work->wpa_s->ext_work_in_progress = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007380 if (!ework->timeout)
7381 ework->timeout = 10;
7382 eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
7383 work, NULL);
7384}
7385
7386
7387static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
7388 char *buf, size_t buflen)
7389{
7390 struct wpa_external_work *ework;
7391 char *pos, *pos2;
7392 size_t type_len;
7393 int ret;
7394 unsigned int freq = 0;
7395
7396 /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
7397
7398 ework = os_zalloc(sizeof(*ework));
7399 if (ework == NULL)
7400 return -1;
7401
7402 pos = os_strchr(cmd, ' ');
7403 if (pos) {
7404 type_len = pos - cmd;
7405 pos++;
7406
7407 pos2 = os_strstr(pos, "freq=");
7408 if (pos2)
7409 freq = atoi(pos2 + 5);
7410
7411 pos2 = os_strstr(pos, "timeout=");
7412 if (pos2)
7413 ework->timeout = atoi(pos2 + 8);
7414 } else {
7415 type_len = os_strlen(cmd);
7416 }
7417 if (4 + type_len >= sizeof(ework->type))
7418 type_len = sizeof(ework->type) - 4 - 1;
7419 os_strlcpy(ework->type, "ext:", sizeof(ework->type));
7420 os_memcpy(ework->type + 4, cmd, type_len);
7421 ework->type[4 + type_len] = '\0';
7422
7423 wpa_s->ext_work_id++;
7424 if (wpa_s->ext_work_id == 0)
7425 wpa_s->ext_work_id++;
7426 ework->id = wpa_s->ext_work_id;
7427
7428 if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
7429 ework) < 0) {
7430 os_free(ework);
7431 return -1;
7432 }
7433
7434 ret = os_snprintf(buf, buflen, "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007435 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007436 return -1;
7437 return ret;
7438}
7439
7440
7441static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
7442{
7443 struct wpa_radio_work *work;
7444 unsigned int id = atoi(cmd);
7445
7446 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7447 {
7448 struct wpa_external_work *ework;
7449
7450 if (os_strncmp(work->type, "ext:", 4) != 0)
7451 continue;
7452 ework = work->ctx;
7453 if (id && ework->id != id)
7454 continue;
7455 wpa_dbg(wpa_s, MSG_DEBUG,
7456 "Completed external radio work %u (%s)",
7457 ework->id, ework->type);
7458 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007459 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007460 radio_work_done(work);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07007461 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007462 return 3; /* "OK\n" */
7463 }
7464
7465 return -1;
7466}
7467
7468
7469static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
7470 char *buf, size_t buflen)
7471{
7472 if (os_strcmp(cmd, "show") == 0)
7473 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
7474 if (os_strncmp(cmd, "add ", 4) == 0)
7475 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
7476 if (os_strncmp(cmd, "done ", 5) == 0)
7477 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
7478 return -1;
7479}
7480
7481
7482void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
7483{
7484 struct wpa_radio_work *work, *tmp;
7485
Dmitry Shmidt18463232014-01-24 12:29:41 -08007486 if (!wpa_s || !wpa_s->radio)
7487 return;
7488
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007489 dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
7490 struct wpa_radio_work, list) {
7491 struct wpa_external_work *ework;
7492
7493 if (os_strncmp(work->type, "ext:", 4) != 0)
7494 continue;
7495 ework = work->ctx;
7496 wpa_dbg(wpa_s, MSG_DEBUG,
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07007497 "Flushing%s external radio work %u (%s)",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007498 work->started ? " started" : "", ework->id,
7499 ework->type);
7500 if (work->started)
7501 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7502 work, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007503 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07007504 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007505 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007506}
7507
7508
Dmitry Shmidt051af732013-10-22 13:52:46 -07007509static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
7510{
7511 struct wpa_supplicant *wpa_s = eloop_ctx;
7512 eapol_sm_notify_ctrl_response(wpa_s->eapol);
7513}
7514
7515
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007516static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
7517 unsigned int *scan_id_count, int scan_id[])
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007518{
7519 const char *pos = value;
7520
7521 while (pos) {
7522 if (*pos == ' ' || *pos == '\0')
7523 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007524 if (*scan_id_count == MAX_SCAN_ID)
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007525 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007526 scan_id[(*scan_id_count)++] = atoi(pos);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007527 pos = os_strchr(pos, ',');
7528 if (pos)
7529 pos++;
7530 }
7531
7532 return 0;
7533}
7534
7535
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007536static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
7537 char *reply, int reply_size, int *reply_len)
7538{
7539 char *pos;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007540 unsigned int manual_scan_passive = 0;
7541 unsigned int manual_scan_use_id = 0;
7542 unsigned int manual_scan_only_new = 0;
7543 unsigned int scan_only = 0;
7544 unsigned int scan_id_count = 0;
7545 int scan_id[MAX_SCAN_ID];
7546 void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
7547 struct wpa_scan_results *scan_res);
7548 int *manual_scan_freqs = NULL;
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07007549 struct wpa_ssid_value *ssid = NULL, *ns;
7550 unsigned int ssid_count = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007551
7552 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
7553 *reply_len = -1;
7554 return;
7555 }
7556
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007557 if (radio_work_pending(wpa_s, "scan")) {
7558 wpa_printf(MSG_DEBUG,
7559 "Pending scan scheduled - reject new request");
7560 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7561 return;
7562 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007563
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07007564#ifdef CONFIG_INTERWORKING
7565 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
7566 wpa_printf(MSG_DEBUG,
7567 "Interworking select in progress - reject new scan");
7568 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7569 return;
7570 }
7571#endif /* CONFIG_INTERWORKING */
7572
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007573 if (params) {
7574 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007575 scan_only = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007576
7577 pos = os_strstr(params, "freq=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007578 if (pos) {
7579 manual_scan_freqs = freq_range_to_channel_list(wpa_s,
7580 pos + 5);
7581 if (manual_scan_freqs == NULL) {
7582 *reply_len = -1;
7583 goto done;
7584 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007585 }
7586
7587 pos = os_strstr(params, "passive=");
7588 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007589 manual_scan_passive = !!atoi(pos + 8);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007590
7591 pos = os_strstr(params, "use_id=");
7592 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007593 manual_scan_use_id = atoi(pos + 7);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007594
7595 pos = os_strstr(params, "only_new=1");
7596 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007597 manual_scan_only_new = 1;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007598
7599 pos = os_strstr(params, "scan_id=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007600 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
7601 scan_id) < 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007602 *reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007603 goto done;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07007604 }
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07007605
7606 pos = params;
7607 while (pos && *pos != '\0') {
7608 if (os_strncmp(pos, "ssid ", 5) == 0) {
7609 char *end;
7610
7611 pos += 5;
7612 end = pos;
7613 while (*end) {
7614 if (*end == '\0' || *end == ' ')
7615 break;
7616 end++;
7617 }
7618
7619 ns = os_realloc_array(
7620 ssid, ssid_count + 1,
7621 sizeof(struct wpa_ssid_value));
7622 if (ns == NULL) {
7623 *reply_len = -1;
7624 goto done;
7625 }
7626 ssid = ns;
7627
7628 if ((end - pos) & 0x01 ||
7629 end - pos > 2 * SSID_MAX_LEN ||
7630 hexstr2bin(pos, ssid[ssid_count].ssid,
7631 (end - pos) / 2) < 0) {
7632 wpa_printf(MSG_DEBUG,
7633 "Invalid SSID value '%s'",
7634 pos);
7635 *reply_len = -1;
7636 goto done;
7637 }
7638 ssid[ssid_count].ssid_len = (end - pos) / 2;
7639 wpa_hexdump_ascii(MSG_DEBUG, "scan SSID",
7640 ssid[ssid_count].ssid,
7641 ssid[ssid_count].ssid_len);
7642 ssid_count++;
7643 pos = end;
7644 }
7645
7646 pos = os_strchr(pos, ' ');
7647 if (pos)
7648 pos++;
7649 }
7650 }
7651
7652 wpa_s->num_ssids_from_scan_req = ssid_count;
7653 os_free(wpa_s->ssids_from_scan_req);
7654 if (ssid_count) {
7655 wpa_s->ssids_from_scan_req = ssid;
7656 ssid = NULL;
7657 } else {
7658 wpa_s->ssids_from_scan_req = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007659 }
7660
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007661 if (scan_only)
7662 scan_res_handler = scan_only_handler;
7663 else if (wpa_s->scan_res_handler == scan_only_handler)
7664 scan_res_handler = NULL;
7665 else
7666 scan_res_handler = wpa_s->scan_res_handler;
7667
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007668 if (!wpa_s->sched_scanning && !wpa_s->scanning &&
7669 ((wpa_s->wpa_state <= WPA_SCANNING) ||
7670 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007671 wpa_s->manual_scan_passive = manual_scan_passive;
7672 wpa_s->manual_scan_use_id = manual_scan_use_id;
7673 wpa_s->manual_scan_only_new = manual_scan_only_new;
7674 wpa_s->scan_id_count = scan_id_count;
7675 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
7676 wpa_s->scan_res_handler = scan_res_handler;
7677 os_free(wpa_s->manual_scan_freqs);
7678 wpa_s->manual_scan_freqs = manual_scan_freqs;
7679 manual_scan_freqs = NULL;
7680
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007681 wpa_s->normal_scans = 0;
7682 wpa_s->scan_req = MANUAL_SCAN_REQ;
7683 wpa_s->after_wps = 0;
7684 wpa_s->known_wps_freq = 0;
7685 wpa_supplicant_req_scan(wpa_s, 0, 0);
7686 if (wpa_s->manual_scan_use_id) {
7687 wpa_s->manual_scan_id++;
7688 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
7689 wpa_s->manual_scan_id);
7690 *reply_len = os_snprintf(reply, reply_size, "%u\n",
7691 wpa_s->manual_scan_id);
7692 }
7693 } else if (wpa_s->sched_scanning) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007694 wpa_s->manual_scan_passive = manual_scan_passive;
7695 wpa_s->manual_scan_use_id = manual_scan_use_id;
7696 wpa_s->manual_scan_only_new = manual_scan_only_new;
7697 wpa_s->scan_id_count = scan_id_count;
7698 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
7699 wpa_s->scan_res_handler = scan_res_handler;
7700 os_free(wpa_s->manual_scan_freqs);
7701 wpa_s->manual_scan_freqs = manual_scan_freqs;
7702 manual_scan_freqs = NULL;
7703
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007704 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
7705 wpa_supplicant_cancel_sched_scan(wpa_s);
7706 wpa_s->scan_req = MANUAL_SCAN_REQ;
7707 wpa_supplicant_req_scan(wpa_s, 0, 0);
7708 if (wpa_s->manual_scan_use_id) {
7709 wpa_s->manual_scan_id++;
7710 *reply_len = os_snprintf(reply, reply_size, "%u\n",
7711 wpa_s->manual_scan_id);
7712 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
7713 wpa_s->manual_scan_id);
7714 }
7715 } else {
7716 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
7717 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7718 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007719
7720done:
7721 os_free(manual_scan_freqs);
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07007722 os_free(ssid);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007723}
7724
7725
Dmitry Shmidt818ea482014-03-10 13:15:21 -07007726#ifdef CONFIG_TESTING_OPTIONS
7727
7728static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
7729 unsigned int freq, const u8 *dst,
7730 const u8 *src, const u8 *bssid,
7731 const u8 *data, size_t data_len,
7732 enum offchannel_send_action_result
7733 result)
7734{
7735 wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
7736 " src=" MACSTR " bssid=" MACSTR " result=%s",
7737 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
7738 result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
7739 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
7740 "NO_ACK" : "FAILED"));
7741}
7742
7743
7744static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
7745{
7746 char *pos, *param;
7747 size_t len;
7748 u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
7749 int res, used;
7750 int freq = 0, no_cck = 0, wait_time = 0;
7751
7752 /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
7753 * <action=Action frame payload> */
7754
7755 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
7756
7757 pos = cmd;
7758 used = hwaddr_aton2(pos, da);
7759 if (used < 0)
7760 return -1;
7761 pos += used;
7762 while (*pos == ' ')
7763 pos++;
7764 used = hwaddr_aton2(pos, bssid);
7765 if (used < 0)
7766 return -1;
7767 pos += used;
7768
7769 param = os_strstr(pos, " freq=");
7770 if (param) {
7771 param += 6;
7772 freq = atoi(param);
7773 }
7774
7775 param = os_strstr(pos, " no_cck=");
7776 if (param) {
7777 param += 8;
7778 no_cck = atoi(param);
7779 }
7780
7781 param = os_strstr(pos, " wait_time=");
7782 if (param) {
7783 param += 11;
7784 wait_time = atoi(param);
7785 }
7786
7787 param = os_strstr(pos, " action=");
7788 if (param == NULL)
7789 return -1;
7790 param += 8;
7791
7792 len = os_strlen(param);
7793 if (len & 1)
7794 return -1;
7795 len /= 2;
7796
7797 buf = os_malloc(len);
7798 if (buf == NULL)
7799 return -1;
7800
7801 if (hexstr2bin(param, buf, len) < 0) {
7802 os_free(buf);
7803 return -1;
7804 }
7805
7806 res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
7807 buf, len, wait_time,
7808 wpas_ctrl_iface_mgmt_tx_cb, no_cck);
7809 os_free(buf);
7810 return res;
7811}
7812
7813
7814static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
7815{
7816 wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
7817 offchannel_send_action_done(wpa_s);
7818}
7819
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07007820
Dmitry Shmidt849734c2016-05-27 09:59:01 -07007821static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
7822 char *cmd)
7823{
7824 char *pos, *param;
7825 size_t len;
7826 u8 *buf;
7827 int freq = 0, datarate = 0, ssi_signal = 0;
7828 union wpa_event_data event;
7829
7830 if (!wpa_s->ext_mgmt_frame_handling)
7831 return -1;
7832
7833 /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
7834
7835 wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
7836
7837 pos = cmd;
7838 param = os_strstr(pos, "freq=");
7839 if (param) {
7840 param += 5;
7841 freq = atoi(param);
7842 }
7843
7844 param = os_strstr(pos, " datarate=");
7845 if (param) {
7846 param += 10;
7847 datarate = atoi(param);
7848 }
7849
7850 param = os_strstr(pos, " ssi_signal=");
7851 if (param) {
7852 param += 12;
7853 ssi_signal = atoi(param);
7854 }
7855
7856 param = os_strstr(pos, " frame=");
7857 if (param == NULL)
7858 return -1;
7859 param += 7;
7860
7861 len = os_strlen(param);
7862 if (len & 1)
7863 return -1;
7864 len /= 2;
7865
7866 buf = os_malloc(len);
7867 if (buf == NULL)
7868 return -1;
7869
7870 if (hexstr2bin(param, buf, len) < 0) {
7871 os_free(buf);
7872 return -1;
7873 }
7874
7875 os_memset(&event, 0, sizeof(event));
7876 event.rx_mgmt.freq = freq;
7877 event.rx_mgmt.frame = buf;
7878 event.rx_mgmt.frame_len = len;
7879 event.rx_mgmt.ssi_signal = ssi_signal;
7880 event.rx_mgmt.datarate = datarate;
7881 wpa_s->ext_mgmt_frame_handling = 0;
7882 wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
7883 wpa_s->ext_mgmt_frame_handling = 1;
7884
7885 os_free(buf);
7886
7887 return 0;
7888}
7889
7890
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07007891static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
7892{
7893 char *pos, *param;
7894 union wpa_event_data event;
7895 enum wpa_event_type ev;
7896
7897 /* <event name> [parameters..] */
7898
7899 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
7900
7901 pos = cmd;
7902 param = os_strchr(pos, ' ');
7903 if (param)
7904 *param++ = '\0';
7905
7906 os_memset(&event, 0, sizeof(event));
7907
7908 if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
7909 ev = EVENT_INTERFACE_ENABLED;
7910 } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
7911 ev = EVENT_INTERFACE_DISABLED;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07007912 } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
7913 ev = EVENT_AVOID_FREQUENCIES;
7914 if (param == NULL)
7915 param = "";
7916 if (freq_range_list_parse(&event.freq_range, param) < 0)
7917 return -1;
7918 wpa_supplicant_event(wpa_s, ev, &event);
7919 os_free(event.freq_range.range);
7920 return 0;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07007921 } else {
7922 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
7923 cmd);
7924 return -1;
7925 }
7926
7927 wpa_supplicant_event(wpa_s, ev, &event);
7928
7929 return 0;
7930}
7931
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007932
7933static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
7934{
7935 char *pos;
7936 u8 src[ETH_ALEN], *buf;
7937 int used;
7938 size_t len;
7939
7940 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
7941
7942 pos = cmd;
7943 used = hwaddr_aton2(pos, src);
7944 if (used < 0)
7945 return -1;
7946 pos += used;
7947 while (*pos == ' ')
7948 pos++;
7949
7950 len = os_strlen(pos);
7951 if (len & 1)
7952 return -1;
7953 len /= 2;
7954
7955 buf = os_malloc(len);
7956 if (buf == NULL)
7957 return -1;
7958
7959 if (hexstr2bin(pos, buf, len) < 0) {
7960 os_free(buf);
7961 return -1;
7962 }
7963
7964 wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
7965 os_free(buf);
7966
7967 return 0;
7968}
7969
7970
7971static u16 ipv4_hdr_checksum(const void *buf, size_t len)
7972{
7973 size_t i;
7974 u32 sum = 0;
7975 const u16 *pos = buf;
7976
7977 for (i = 0; i < len / 2; i++)
7978 sum += *pos++;
7979
7980 while (sum >> 16)
7981 sum = (sum & 0xffff) + (sum >> 16);
7982
7983 return sum ^ 0xffff;
7984}
7985
7986
7987#define HWSIM_PACKETLEN 1500
7988#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
7989
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07007990static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
7991 size_t len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007992{
7993 struct wpa_supplicant *wpa_s = ctx;
7994 const struct ether_header *eth;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007995 struct iphdr ip;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007996 const u8 *pos;
7997 unsigned int i;
7998
7999 if (len != HWSIM_PACKETLEN)
8000 return;
8001
8002 eth = (const struct ether_header *) buf;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008003 os_memcpy(&ip, eth + 1, sizeof(ip));
8004 pos = &buf[sizeof(*eth) + sizeof(ip)];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008005
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008006 if (ip.ihl != 5 || ip.version != 4 ||
8007 ntohs(ip.tot_len) != HWSIM_IP_LEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008008 return;
8009
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008010 for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008011 if (*pos != (u8) i)
8012 return;
8013 pos++;
8014 }
8015
8016 wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
8017 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
8018}
8019
8020
8021static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
8022 char *cmd)
8023{
8024 int enabled = atoi(cmd);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008025 char *pos;
8026 const char *ifname;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008027
8028 if (!enabled) {
8029 if (wpa_s->l2_test) {
8030 l2_packet_deinit(wpa_s->l2_test);
8031 wpa_s->l2_test = NULL;
8032 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
8033 }
8034 return 0;
8035 }
8036
8037 if (wpa_s->l2_test)
8038 return 0;
8039
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008040 pos = os_strstr(cmd, " ifname=");
8041 if (pos)
8042 ifname = pos + 8;
8043 else
8044 ifname = wpa_s->ifname;
8045
8046 wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008047 ETHERTYPE_IP, wpas_data_test_rx,
8048 wpa_s, 1);
8049 if (wpa_s->l2_test == NULL)
8050 return -1;
8051
8052 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
8053
8054 return 0;
8055}
8056
8057
8058static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
8059{
8060 u8 dst[ETH_ALEN], src[ETH_ALEN];
8061 char *pos;
8062 int used;
8063 long int val;
8064 u8 tos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008065 u8 buf[2 + HWSIM_PACKETLEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008066 struct ether_header *eth;
8067 struct iphdr *ip;
8068 u8 *dpos;
8069 unsigned int i;
8070
8071 if (wpa_s->l2_test == NULL)
8072 return -1;
8073
8074 /* format: <dst> <src> <tos> */
8075
8076 pos = cmd;
8077 used = hwaddr_aton2(pos, dst);
8078 if (used < 0)
8079 return -1;
8080 pos += used;
8081 while (*pos == ' ')
8082 pos++;
8083 used = hwaddr_aton2(pos, src);
8084 if (used < 0)
8085 return -1;
8086 pos += used;
8087
8088 val = strtol(pos, NULL, 0);
8089 if (val < 0 || val > 0xff)
8090 return -1;
8091 tos = val;
8092
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008093 eth = (struct ether_header *) &buf[2];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008094 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
8095 os_memcpy(eth->ether_shost, src, ETH_ALEN);
8096 eth->ether_type = htons(ETHERTYPE_IP);
8097 ip = (struct iphdr *) (eth + 1);
8098 os_memset(ip, 0, sizeof(*ip));
8099 ip->ihl = 5;
8100 ip->version = 4;
8101 ip->ttl = 64;
8102 ip->tos = tos;
8103 ip->tot_len = htons(HWSIM_IP_LEN);
8104 ip->protocol = 1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008105 ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
8106 ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008107 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
8108 dpos = (u8 *) (ip + 1);
8109 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
8110 *dpos++ = i;
8111
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008112 if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008113 HWSIM_PACKETLEN) < 0)
8114 return -1;
8115
8116 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
8117 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
8118
8119 return 0;
8120}
8121
8122
8123static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
8124 char *cmd)
8125{
8126 u8 *buf;
8127 struct ether_header *eth;
8128 struct l2_packet_data *l2 = NULL;
8129 size_t len;
8130 u16 ethertype;
8131 int res = -1;
8132
8133 len = os_strlen(cmd);
8134 if (len & 1 || len < ETH_HLEN * 2)
8135 return -1;
8136 len /= 2;
8137
8138 buf = os_malloc(len);
8139 if (buf == NULL)
8140 return -1;
8141
8142 if (hexstr2bin(cmd, buf, len) < 0)
8143 goto done;
8144
8145 eth = (struct ether_header *) buf;
8146 ethertype = ntohs(eth->ether_type);
8147
8148 l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
8149 wpas_data_test_rx, wpa_s, 1);
8150 if (l2 == NULL)
8151 goto done;
8152
8153 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
8154 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
8155done:
8156 if (l2)
8157 l2_packet_deinit(l2);
8158 os_free(buf);
8159
8160 return res < 0 ? -1 : 0;
8161}
8162
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008163
8164static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
8165{
8166#ifdef WPA_TRACE_BFD
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008167 char *pos;
8168
8169 wpa_trace_fail_after = atoi(cmd);
8170 pos = os_strchr(cmd, ':');
8171 if (pos) {
8172 pos++;
8173 os_strlcpy(wpa_trace_fail_func, pos,
8174 sizeof(wpa_trace_fail_func));
8175 } else {
8176 wpa_trace_fail_after = 0;
8177 }
8178 return 0;
8179#else /* WPA_TRACE_BFD */
8180 return -1;
8181#endif /* WPA_TRACE_BFD */
8182}
8183
8184
8185static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
8186 char *buf, size_t buflen)
8187{
8188#ifdef WPA_TRACE_BFD
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008189 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
8190 wpa_trace_fail_func);
8191#else /* WPA_TRACE_BFD */
8192 return -1;
8193#endif /* WPA_TRACE_BFD */
8194}
8195
Jouni Malinenc4818362015-10-04 11:45:13 +03008196
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008197static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
8198{
8199#ifdef WPA_TRACE_BFD
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008200 char *pos;
8201
8202 wpa_trace_test_fail_after = atoi(cmd);
8203 pos = os_strchr(cmd, ':');
8204 if (pos) {
8205 pos++;
8206 os_strlcpy(wpa_trace_test_fail_func, pos,
8207 sizeof(wpa_trace_test_fail_func));
8208 } else {
8209 wpa_trace_test_fail_after = 0;
8210 }
8211 return 0;
8212#else /* WPA_TRACE_BFD */
8213 return -1;
8214#endif /* WPA_TRACE_BFD */
8215}
8216
8217
8218static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
8219 char *buf, size_t buflen)
8220{
8221#ifdef WPA_TRACE_BFD
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008222 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
8223 wpa_trace_test_fail_func);
8224#else /* WPA_TRACE_BFD */
8225 return -1;
8226#endif /* WPA_TRACE_BFD */
8227}
8228
8229
Jouni Malinenc4818362015-10-04 11:45:13 +03008230static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
8231{
8232 struct wpa_supplicant *wpa_s = eloop_ctx;
8233 int i, count = (intptr_t) timeout_ctx;
8234
8235 wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
8236 count);
8237 for (i = 0; i < count; i++) {
8238 wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
8239 i + 1, count);
8240 }
8241}
8242
8243
8244static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
8245{
8246 int count;
8247
8248 count = atoi(cmd);
8249 if (count <= 0)
8250 return -1;
8251
8252 return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
8253 (void *) (intptr_t) count);
8254}
8255
Dmitry Shmidt818ea482014-03-10 13:15:21 -07008256
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008257static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
8258 const char *cmd)
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008259{
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008260 struct wpabuf *buf;
8261 size_t len;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008262
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008263 len = os_strlen(cmd);
8264 if (len & 1)
8265 return -1;
8266 len /= 2;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008267
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008268 if (len == 0) {
8269 buf = NULL;
8270 } else {
8271 buf = wpabuf_alloc(len);
8272 if (buf == NULL)
8273 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008274
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008275 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
8276 wpabuf_free(buf);
8277 return -1;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008278 }
8279 }
8280
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008281 wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
8282 return 0;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008283}
8284
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008285#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008286
8287
8288static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
8289{
8290 char *pos = cmd;
8291 int frame;
8292 size_t len;
8293 struct wpabuf *buf;
8294 struct ieee802_11_elems elems;
8295
8296 frame = atoi(pos);
8297 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8298 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008299 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008300
8301 pos = os_strchr(pos, ' ');
8302 if (pos == NULL)
8303 return -1;
8304 pos++;
8305
8306 len = os_strlen(pos);
8307 if (len == 0)
8308 return 0;
8309 if (len & 1)
8310 return -1;
8311 len /= 2;
8312
8313 buf = wpabuf_alloc(len);
8314 if (buf == NULL)
8315 return -1;
8316
8317 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
8318 wpabuf_free(buf);
8319 return -1;
8320 }
8321
8322 if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
8323 ParseFailed) {
8324 wpabuf_free(buf);
8325 return -1;
8326 }
8327
8328 if (wpa_s->vendor_elem[frame] == NULL) {
8329 wpa_s->vendor_elem[frame] = buf;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008330 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008331 return 0;
8332 }
8333
8334 if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
8335 wpabuf_free(buf);
8336 return -1;
8337 }
8338
8339 wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
8340 wpabuf_free(buf);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008341 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008342
8343 return 0;
8344}
8345
8346
8347static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
8348 char *buf, size_t buflen)
8349{
8350 int frame = atoi(cmd);
8351
8352 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8353 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008354 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008355
8356 if (wpa_s->vendor_elem[frame] == NULL)
8357 return 0;
8358
8359 return wpa_snprintf_hex(buf, buflen,
8360 wpabuf_head_u8(wpa_s->vendor_elem[frame]),
8361 wpabuf_len(wpa_s->vendor_elem[frame]));
8362}
8363
8364
8365static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
8366{
8367 char *pos = cmd;
8368 int frame;
8369 size_t len;
8370 u8 *buf;
8371 struct ieee802_11_elems elems;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008372 int res;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008373
8374 frame = atoi(pos);
8375 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8376 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008377 wpa_s = wpas_vendor_elem(wpa_s, frame);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008378
8379 pos = os_strchr(pos, ' ');
8380 if (pos == NULL)
8381 return -1;
8382 pos++;
8383
8384 if (*pos == '*') {
8385 wpabuf_free(wpa_s->vendor_elem[frame]);
8386 wpa_s->vendor_elem[frame] = NULL;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008387 wpas_vendor_elem_update(wpa_s);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008388 return 0;
8389 }
8390
8391 if (wpa_s->vendor_elem[frame] == NULL)
8392 return -1;
8393
8394 len = os_strlen(pos);
8395 if (len == 0)
8396 return 0;
8397 if (len & 1)
8398 return -1;
8399 len /= 2;
8400
8401 buf = os_malloc(len);
8402 if (buf == NULL)
8403 return -1;
8404
8405 if (hexstr2bin(pos, buf, len) < 0) {
8406 os_free(buf);
8407 return -1;
8408 }
8409
8410 if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
8411 os_free(buf);
8412 return -1;
8413 }
8414
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008415 res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008416 os_free(buf);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08008417 return res;
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07008418}
8419
8420
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008421static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
8422{
8423 struct wpa_supplicant *wpa_s = ctx;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008424 size_t len;
8425 const u8 *data;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008426
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008427 /*
8428 * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
8429 * BSSID[6]
8430 * BSSID Information[4]
8431 * Operating Class[1]
8432 * Channel Number[1]
8433 * PHY Type[1]
8434 * Optional Subelements[variable]
8435 */
8436#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
8437
8438 if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008439 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008440 goto out;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008441 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008442
8443 data = wpabuf_head_u8(neighbor_rep);
8444 len = wpabuf_len(neighbor_rep);
8445
8446 while (len >= 2 + NR_IE_MIN_LEN) {
8447 const u8 *nr;
8448 char lci[256 * 2 + 1];
8449 char civic[256 * 2 + 1];
8450 u8 nr_len = data[1];
8451 const u8 *pos = data, *end;
8452
8453 if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
8454 nr_len < NR_IE_MIN_LEN) {
8455 wpa_printf(MSG_DEBUG,
8456 "CTRL: Invalid Neighbor Report element: id=%u len=%u",
8457 data[0], nr_len);
8458 goto out;
8459 }
8460
8461 if (2U + nr_len > len) {
8462 wpa_printf(MSG_DEBUG,
8463 "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
8464 data[0], len, nr_len);
8465 goto out;
8466 }
8467 pos += 2;
8468 end = pos + nr_len;
8469
8470 nr = pos;
8471 pos += NR_IE_MIN_LEN;
8472
8473 lci[0] = '\0';
8474 civic[0] = '\0';
8475 while (end - pos > 2) {
8476 u8 s_id, s_len;
8477
8478 s_id = *pos++;
8479 s_len = *pos++;
8480 if (s_len > end - pos)
8481 goto out;
8482 if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
8483 /* Measurement Token[1] */
8484 /* Measurement Report Mode[1] */
8485 /* Measurement Type[1] */
8486 /* Measurement Report[variable] */
8487 switch (pos[2]) {
8488 case MEASURE_TYPE_LCI:
8489 if (lci[0])
8490 break;
8491 wpa_snprintf_hex(lci, sizeof(lci),
8492 pos, s_len);
8493 break;
8494 case MEASURE_TYPE_LOCATION_CIVIC:
8495 if (civic[0])
8496 break;
8497 wpa_snprintf_hex(civic, sizeof(civic),
8498 pos, s_len);
8499 break;
8500 }
8501 }
8502
8503 pos += s_len;
8504 }
8505
8506 wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
8507 "bssid=" MACSTR
8508 " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
8509 MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
8510 nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
8511 nr[ETH_ALEN + 6],
8512 lci[0] ? " lci=" : "", lci,
8513 civic[0] ? " civic=" : "", civic);
8514
8515 data = end;
8516 len -= 2 + nr_len;
8517 }
8518
8519out:
8520 wpabuf_free(neighbor_rep);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008521}
8522
8523
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008524static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
8525 char *cmd)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008526{
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008527 struct wpa_ssid_value ssid, *ssid_p = NULL;
8528 int ret, lci = 0, civic = 0;
8529 char *ssid_s;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008530
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008531 ssid_s = os_strstr(cmd, "ssid=");
8532 if (ssid_s) {
8533 if (ssid_parse(ssid_s + 5, &ssid)) {
8534 wpa_printf(MSG_ERROR,
8535 "CTRL: Send Neighbor Report: bad SSID");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008536 return -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008537 }
8538
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008539 ssid_p = &ssid;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008540
8541 /*
8542 * Move cmd after the SSID text that may include "lci" or
8543 * "civic".
8544 */
8545 cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
8546 if (cmd)
8547 cmd++;
8548
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008549 }
8550
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008551 if (cmd && os_strstr(cmd, "lci"))
8552 lci = 1;
8553
8554 if (cmd && os_strstr(cmd, "civic"))
8555 civic = 1;
8556
8557 ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008558 wpas_ctrl_neighbor_rep_cb,
8559 wpa_s);
8560
8561 return ret;
8562}
8563
8564
8565static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
8566{
8567 eapol_sm_erp_flush(wpa_s->eapol);
8568 return 0;
8569}
8570
8571
8572static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
8573 char *cmd)
8574{
8575 char *token, *context = NULL;
8576 unsigned int enable = ~0, type = 0;
8577 u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
8578 u8 *addr = NULL, *mask = NULL;
8579
8580 while ((token = str_token(cmd, " ", &context))) {
8581 if (os_strcasecmp(token, "scan") == 0) {
8582 type |= MAC_ADDR_RAND_SCAN;
8583 } else if (os_strcasecmp(token, "sched") == 0) {
8584 type |= MAC_ADDR_RAND_SCHED_SCAN;
8585 } else if (os_strcasecmp(token, "pno") == 0) {
8586 type |= MAC_ADDR_RAND_PNO;
8587 } else if (os_strcasecmp(token, "all") == 0) {
8588 type = wpa_s->mac_addr_rand_supported;
8589 } else if (os_strncasecmp(token, "enable=", 7) == 0) {
8590 enable = atoi(token + 7);
8591 } else if (os_strncasecmp(token, "addr=", 5) == 0) {
8592 addr = _addr;
8593 if (hwaddr_aton(token + 5, addr)) {
8594 wpa_printf(MSG_INFO,
8595 "CTRL: Invalid MAC address: %s",
8596 token);
8597 return -1;
8598 }
8599 } else if (os_strncasecmp(token, "mask=", 5) == 0) {
8600 mask = _mask;
8601 if (hwaddr_aton(token + 5, mask)) {
8602 wpa_printf(MSG_INFO,
8603 "CTRL: Invalid MAC address mask: %s",
8604 token);
8605 return -1;
8606 }
8607 } else {
8608 wpa_printf(MSG_INFO,
8609 "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
8610 token);
8611 return -1;
8612 }
8613 }
8614
8615 if (!type) {
8616 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
8617 return -1;
8618 }
8619
8620 if ((wpa_s->mac_addr_rand_supported & type) != type) {
8621 wpa_printf(MSG_INFO,
8622 "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
8623 type, wpa_s->mac_addr_rand_supported);
8624 return -1;
8625 }
8626
8627 if (enable > 1) {
8628 wpa_printf(MSG_INFO,
8629 "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
8630 return -1;
8631 }
8632
8633 if (!enable) {
8634 wpas_mac_addr_rand_scan_clear(wpa_s, type);
8635 if (wpa_s->pno) {
8636 if (type & MAC_ADDR_RAND_PNO) {
8637 wpas_stop_pno(wpa_s);
8638 wpas_start_pno(wpa_s);
8639 }
8640 } else if (wpa_s->sched_scanning &&
8641 (type & MAC_ADDR_RAND_SCHED_SCAN)) {
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008642 wpas_scan_restart_sched_scan(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008643 }
8644 return 0;
8645 }
8646
8647 if ((addr && !mask) || (!addr && mask)) {
8648 wpa_printf(MSG_INFO,
8649 "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
8650 return -1;
8651 }
8652
8653 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
8654 wpa_printf(MSG_INFO,
8655 "CTRL: MAC_RAND_SCAN cannot allow multicast address");
8656 return -1;
8657 }
8658
8659 if (type & MAC_ADDR_RAND_SCAN) {
8660 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
8661 addr, mask);
8662 }
8663
8664 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
8665 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
8666 addr, mask);
8667
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008668 if (wpa_s->sched_scanning && !wpa_s->pno)
8669 wpas_scan_restart_sched_scan(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008670 }
8671
8672 if (type & MAC_ADDR_RAND_PNO) {
8673 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
8674 addr, mask);
8675 if (wpa_s->pno) {
8676 wpas_stop_pno(wpa_s);
8677 wpas_start_pno(wpa_s);
8678 }
8679 }
8680
8681 return 0;
8682}
8683
8684
Dmitry Shmidte4663042016-04-04 10:07:49 -07008685static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
8686 char *buf, size_t buflen)
8687{
8688 size_t reply_len;
8689
8690 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
8691#ifdef CONFIG_AP
8692 reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
8693 buflen - reply_len);
8694#endif /* CONFIG_AP */
8695 return reply_len;
8696}
8697
8698
8699static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
8700{
8701 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
8702#ifdef CONFIG_AP
8703 wpas_ap_pmksa_cache_flush(wpa_s);
8704#endif /* CONFIG_AP */
8705}
8706
8707
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008708static int wpas_ctrl_cmd_debug_level(const char *cmd)
8709{
8710 if (os_strcmp(cmd, "PING") == 0 ||
8711 os_strncmp(cmd, "BSS ", 4) == 0 ||
8712 os_strncmp(cmd, "GET_NETWORK ", 12) == 0 ||
8713 os_strncmp(cmd, "STATUS", 6) == 0 ||
8714 os_strncmp(cmd, "STA ", 4) == 0 ||
8715 os_strncmp(cmd, "STA-", 4) == 0)
8716 return MSG_EXCESSIVE;
8717 return MSG_DEBUG;
8718}
8719
8720
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008721char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
8722 char *buf, size_t *resp_len)
8723{
8724 char *reply;
8725 const int reply_size = 4096;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008726 int reply_len;
8727
8728 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008729 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
8730 if (wpa_debug_show_keys)
8731 wpa_dbg(wpa_s, MSG_DEBUG,
8732 "Control interface command '%s'", buf);
8733 else
8734 wpa_dbg(wpa_s, MSG_DEBUG,
8735 "Control interface command '%s [REMOVED]'",
8736 os_strncmp(buf, WPA_CTRL_RSP,
8737 os_strlen(WPA_CTRL_RSP)) == 0 ?
8738 WPA_CTRL_RSP : "SET_NETWORK");
8739 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
Dmitry Shmidt21de2142014-04-08 10:50:52 -07008740 os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008741 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
8742 (const u8 *) buf, os_strlen(buf));
8743 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008744 int level = wpas_ctrl_cmd_debug_level(buf);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008745 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008746 }
8747
8748 reply = os_malloc(reply_size);
8749 if (reply == NULL) {
8750 *resp_len = 1;
8751 return NULL;
8752 }
8753
8754 os_memcpy(reply, "OK\n", 3);
8755 reply_len = 3;
8756
8757 if (os_strcmp(buf, "PING") == 0) {
8758 os_memcpy(reply, "PONG\n", 5);
8759 reply_len = 5;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008760 } else if (os_strcmp(buf, "IFNAME") == 0) {
8761 reply_len = os_strlen(wpa_s->ifname);
8762 os_memcpy(reply, wpa_s->ifname, reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008763 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
8764 if (wpa_debug_reopen_file() < 0)
8765 reply_len = -1;
8766 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
8767 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
8768 } else if (os_strcmp(buf, "MIB") == 0) {
8769 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
8770 if (reply_len >= 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008771 reply_len += eapol_sm_get_mib(wpa_s->eapol,
8772 reply + reply_len,
8773 reply_size - reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008774 }
8775 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
8776 reply_len = wpa_supplicant_ctrl_iface_status(
8777 wpa_s, buf + 6, reply, reply_size);
8778 } else if (os_strcmp(buf, "PMKSA") == 0) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07008779 reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008780 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07008781 wpas_ctrl_iface_pmksa_flush(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008782 } else if (os_strncmp(buf, "SET ", 4) == 0) {
8783 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
8784 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08008785 } else if (os_strncmp(buf, "DUMP", 4) == 0) {
8786 reply_len = wpa_config_dump_values(wpa_s->conf,
8787 reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008788 } else if (os_strncmp(buf, "GET ", 4) == 0) {
8789 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
8790 reply, reply_size);
8791 } else if (os_strcmp(buf, "LOGON") == 0) {
8792 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
8793 } else if (os_strcmp(buf, "LOGOFF") == 0) {
8794 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
8795 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
8796 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
8797 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008798 else
8799 wpas_request_connection(wpa_s);
Dmitry Shmidt98660862014-03-11 17:26:21 -07008800 } else if (os_strcmp(buf, "REATTACH") == 0) {
8801 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
8802 !wpa_s->current_ssid)
8803 reply_len = -1;
8804 else {
8805 wpa_s->reattach = 1;
8806 wpas_request_connection(wpa_s);
8807 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008808 } else if (os_strcmp(buf, "RECONNECT") == 0) {
8809 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
8810 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008811 else if (wpa_s->disconnected)
8812 wpas_request_connection(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008813#ifdef IEEE8021X_EAPOL
8814 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
8815 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
8816 reply_len = -1;
8817#endif /* IEEE8021X_EAPOL */
8818#ifdef CONFIG_PEERKEY
8819 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
8820 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
8821 reply_len = -1;
8822#endif /* CONFIG_PEERKEY */
8823#ifdef CONFIG_IEEE80211R
8824 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
8825 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
8826 reply_len = -1;
8827#endif /* CONFIG_IEEE80211R */
8828#ifdef CONFIG_WPS
8829 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
8830 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
8831 if (res == -2) {
8832 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8833 reply_len = 17;
8834 } else if (res)
8835 reply_len = -1;
8836 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
8837 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
8838 if (res == -2) {
8839 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8840 reply_len = 17;
8841 } else if (res)
8842 reply_len = -1;
8843 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
8844 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
8845 reply,
8846 reply_size);
8847 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
8848 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
8849 wpa_s, buf + 14, reply, reply_size);
8850 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
8851 if (wpas_wps_cancel(wpa_s))
8852 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008853#ifdef CONFIG_WPS_NFC
8854 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
8855 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
8856 reply_len = -1;
8857 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
8858 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
8859 reply_len = -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08008860 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
8861 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
8862 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008863 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
8864 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
8865 wpa_s, buf + 14, reply, reply_size);
8866 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
8867 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
8868 buf + 17))
8869 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08008870 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
8871 reply_len = wpas_ctrl_nfc_get_handover_req(
8872 wpa_s, buf + 21, reply, reply_size);
8873 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
8874 reply_len = wpas_ctrl_nfc_get_handover_sel(
8875 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08008876 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
8877 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
8878 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008879#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008880 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
8881 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
8882 reply_len = -1;
8883#ifdef CONFIG_AP
8884 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
8885 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
8886 wpa_s, buf + 11, reply, reply_size);
8887#endif /* CONFIG_AP */
8888#ifdef CONFIG_WPS_ER
8889 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
8890 if (wpas_wps_er_start(wpa_s, NULL))
8891 reply_len = -1;
8892 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
8893 if (wpas_wps_er_start(wpa_s, buf + 13))
8894 reply_len = -1;
8895 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008896 wpas_wps_er_stop(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008897 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
8898 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
8899 reply_len = -1;
8900 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
8901 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
8902 if (ret == -2) {
8903 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8904 reply_len = 17;
8905 } else if (ret == -3) {
8906 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
8907 reply_len = 18;
8908 } else if (ret == -4) {
8909 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
8910 reply_len = 20;
8911 } else if (ret)
8912 reply_len = -1;
8913 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
8914 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
8915 reply_len = -1;
8916 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
8917 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
8918 buf + 18))
8919 reply_len = -1;
8920 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
8921 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
8922 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008923#ifdef CONFIG_WPS_NFC
8924 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
8925 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
8926 wpa_s, buf + 24, reply, reply_size);
8927#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008928#endif /* CONFIG_WPS_ER */
8929#endif /* CONFIG_WPS */
8930#ifdef CONFIG_IBSS_RSN
8931 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
8932 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
8933 reply_len = -1;
8934#endif /* CONFIG_IBSS_RSN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008935#ifdef CONFIG_MESH
8936 } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
8937 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
8938 wpa_s, buf + 19, reply, reply_size);
8939 } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
8940 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
8941 wpa_s, "", reply, reply_size);
8942 } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
8943 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
8944 reply_len = -1;
8945 } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
8946 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
8947 buf + 18))
8948 reply_len = -1;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008949 } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
8950 if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
8951 reply_len = -1;
8952 } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
8953 if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
8954 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008955#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008956#ifdef CONFIG_P2P
8957 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08008958 if (p2p_ctrl_find(wpa_s, buf + 8))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008959 reply_len = -1;
8960 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
8961 if (p2p_ctrl_find(wpa_s, ""))
8962 reply_len = -1;
8963 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
8964 wpas_p2p_stop_find(wpa_s);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08008965 } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
8966 if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
8967 reply_len = -1;
8968 } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
8969 if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
8970 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008971 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
8972 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
8973 reply_size);
8974 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
8975 if (p2p_ctrl_listen(wpa_s, buf + 11))
8976 reply_len = -1;
8977 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
8978 if (p2p_ctrl_listen(wpa_s, ""))
8979 reply_len = -1;
8980 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
8981 if (wpas_p2p_group_remove(wpa_s, buf + 17))
8982 reply_len = -1;
8983 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07008984 if (p2p_ctrl_group_add(wpa_s, ""))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008985 reply_len = -1;
8986 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
8987 if (p2p_ctrl_group_add(wpa_s, buf + 14))
8988 reply_len = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07008989 } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
8990 reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
8991 reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008992 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
8993 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
8994 reply_len = -1;
8995 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
8996 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
8997 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
8998 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
8999 reply_size);
9000 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
9001 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
9002 reply_len = -1;
9003 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
9004 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
9005 reply_len = -1;
9006 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
9007 wpas_p2p_sd_service_update(wpa_s);
9008 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
9009 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
9010 reply_len = -1;
9011 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
9012 wpas_p2p_service_flush(wpa_s);
9013 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
9014 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
9015 reply_len = -1;
9016 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
9017 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
9018 reply_len = -1;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009019 } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
9020 if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
9021 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009022 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
9023 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
9024 reply_len = -1;
9025 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
9026 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
9027 reply_len = -1;
9028 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
9029 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
9030 reply_size);
9031 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
9032 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
9033 reply_len = -1;
9034 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
Dmitry Shmidt444d5672013-04-01 13:08:44 -07009035 p2p_ctrl_flush(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009036 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
9037 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
9038 reply_len = -1;
9039 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
9040 if (wpas_p2p_cancel(wpa_s))
9041 reply_len = -1;
9042 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
9043 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
9044 reply_len = -1;
9045 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
9046 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
9047 reply_len = -1;
9048 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
9049 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
9050 reply_len = -1;
9051 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
9052 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
9053 reply_len = -1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07009054 } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
9055 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
9056 reply_len = -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07009057 } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
9058 if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
9059 reply_len = -1;
9060 } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
9061 if (wpas_p2p_lo_stop(wpa_s))
9062 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009063#endif /* CONFIG_P2P */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009064#ifdef CONFIG_WIFI_DISPLAY
9065 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
9066 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
9067 reply_len = -1;
9068 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
9069 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
9070 reply, reply_size);
9071#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009072#ifdef CONFIG_INTERWORKING
9073 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
9074 if (interworking_fetch_anqp(wpa_s) < 0)
9075 reply_len = -1;
9076 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
9077 interworking_stop_fetch_anqp(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009078 } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
9079 if (ctrl_interworking_select(wpa_s, NULL) < 0)
9080 reply_len = -1;
9081 } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
9082 if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009083 reply_len = -1;
9084 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009085 if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009086 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009087 } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
9088 int id;
9089
9090 id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
9091 if (id < 0)
9092 reply_len = -1;
9093 else {
9094 reply_len = os_snprintf(reply, reply_size, "%d\n", id);
9095 if (os_snprintf_error(reply_size, reply_len))
9096 reply_len = -1;
9097 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009098 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
9099 if (get_anqp(wpa_s, buf + 9) < 0)
9100 reply_len = -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009101 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
9102 if (gas_request(wpa_s, buf + 12) < 0)
9103 reply_len = -1;
9104 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
9105 reply_len = gas_response_get(wpa_s, buf + 17, reply,
9106 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009107#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07009108#ifdef CONFIG_HS20
9109 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
9110 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
9111 reply_len = -1;
9112 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
9113 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
9114 reply_len = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009115 } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08009116 if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
9117 reply_len = -1;
9118 } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
9119 if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
9120 reply_len = -1;
9121 } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
9122 reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
9123 } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
9124 if (del_hs20_icon(wpa_s, buf + 14) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009125 reply_len = -1;
9126 } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07009127 if (hs20_fetch_osu(wpa_s, 0) < 0)
9128 reply_len = -1;
9129 } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
9130 if (hs20_fetch_osu(wpa_s, 1) < 0)
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08009131 reply_len = -1;
9132 } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
9133 hs20_cancel_fetch_osu(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009134#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009135 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
9136 {
9137 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
9138 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
9139 reply_len = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07009140 else {
9141 /*
9142 * Notify response from timeout to allow the control
9143 * interface response to be sent first.
9144 */
9145 eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
9146 wpa_s, NULL);
9147 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009148 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
9149 if (wpa_supplicant_reload_configuration(wpa_s))
9150 reply_len = -1;
9151 } else if (os_strcmp(buf, "TERMINATE") == 0) {
9152 wpa_supplicant_terminate_proc(wpa_s->global);
9153 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
9154 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
9155 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -07009156 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009157 reply_len = wpa_supplicant_ctrl_iface_blacklist(
9158 wpa_s, buf + 9, reply, reply_size);
9159 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
9160 reply_len = wpa_supplicant_ctrl_iface_log_level(
9161 wpa_s, buf + 9, reply, reply_size);
Vinit Deshpandeda134e92014-12-02 10:59:29 -08009162 } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
9163 reply_len = wpa_supplicant_ctrl_iface_list_networks(
9164 wpa_s, buf + 14, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009165 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
9166 reply_len = wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -08009167 wpa_s, NULL, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009168 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07009169 wpas_request_disconnection(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009170 } else if (os_strcmp(buf, "SCAN") == 0) {
9171 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
9172 } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
9173 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009174 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
9175 reply_len = wpa_supplicant_ctrl_iface_scan_results(
9176 wpa_s, reply, reply_size);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009177 } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
9178 if (wpas_abort_ongoing_scan(wpa_s) < 0)
9179 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009180 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
9181 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
9182 reply_len = -1;
9183 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
9184 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
9185 reply_len = -1;
9186 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
9187 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
9188 reply_len = -1;
9189 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
9190 reply_len = wpa_supplicant_ctrl_iface_add_network(
9191 wpa_s, reply, reply_size);
9192 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
9193 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
9194 reply_len = -1;
9195 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
9196 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
9197 reply_len = -1;
9198 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
9199 reply_len = wpa_supplicant_ctrl_iface_get_network(
9200 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07009201 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009202 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12,
9203 wpa_s))
Dmitry Shmidt684785c2014-05-12 13:34:29 -07009204 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07009205 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
9206 reply_len = wpa_supplicant_ctrl_iface_list_creds(
9207 wpa_s, reply, reply_size);
9208 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
9209 reply_len = wpa_supplicant_ctrl_iface_add_cred(
9210 wpa_s, reply, reply_size);
9211 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
9212 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
9213 reply_len = -1;
9214 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
9215 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
9216 reply_len = -1;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07009217 } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
9218 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
9219 reply,
9220 reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009221#ifndef CONFIG_NO_CONFIG_WRITE
9222 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
9223 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
9224 reply_len = -1;
9225#endif /* CONFIG_NO_CONFIG_WRITE */
9226 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
9227 reply_len = wpa_supplicant_ctrl_iface_get_capability(
9228 wpa_s, buf + 15, reply, reply_size);
9229 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
9230 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
9231 reply_len = -1;
9232 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
9233 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
9234 reply_len = -1;
9235 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
9236 reply_len = wpa_supplicant_global_iface_list(
9237 wpa_s->global, reply, reply_size);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08009238 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009239 reply_len = wpa_supplicant_global_iface_interfaces(
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08009240 wpa_s->global, buf + 10, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009241 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
9242 reply_len = wpa_supplicant_ctrl_iface_bss(
9243 wpa_s, buf + 4, reply, reply_size);
9244#ifdef CONFIG_AP
9245 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
9246 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
9247 } else if (os_strncmp(buf, "STA ", 4) == 0) {
9248 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
9249 reply_size);
9250 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
9251 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
9252 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009253 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
9254 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
9255 reply_len = -1;
9256 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
9257 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
9258 reply_len = -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009259 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
9260 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
9261 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009262 } else if (os_strcmp(buf, "STOP_AP") == 0) {
9263 if (wpas_ap_stop_ap(wpa_s))
9264 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009265#endif /* CONFIG_AP */
9266 } else if (os_strcmp(buf, "SUSPEND") == 0) {
9267 wpas_notify_suspend(wpa_s->global);
9268 } else if (os_strcmp(buf, "RESUME") == 0) {
9269 wpas_notify_resume(wpa_s->global);
Dmitry Shmidt21de2142014-04-08 10:50:52 -07009270#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009271 } else if (os_strcmp(buf, "DROP_SA") == 0) {
9272 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
Dmitry Shmidt21de2142014-04-08 10:50:52 -07009273#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009274 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
9275 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
9276 reply_len = -1;
9277 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009278 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009279 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
9280 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
9281 reply_len = -1;
9282 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
9283 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
9284 buf + 17))
9285 reply_len = -1;
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07009286 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009287 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009288#ifdef CONFIG_TDLS
9289 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
9290 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
9291 reply_len = -1;
9292 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
9293 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
9294 reply_len = -1;
9295 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
9296 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
9297 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009298 } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
9299 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
9300 buf + 17))
9301 reply_len = -1;
9302 } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
9303 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
9304 buf + 24))
9305 reply_len = -1;
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07009306 } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) {
9307 reply_len = wpa_supplicant_ctrl_iface_tdls_link_status(
9308 wpa_s, buf + 17, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009309#endif /* CONFIG_TDLS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009310 } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
9311 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
9312 } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
9313 if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
9314 reply_len = -1;
9315 } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
9316 if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
9317 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009318 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
9319 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
9320 reply_size);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08009321 } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
9322 if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
9323 reply_len = -1;
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07009324 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
9325 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
9326 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07009327#ifdef CONFIG_AUTOSCAN
9328 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
9329 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
9330 reply_len = -1;
9331#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07009332 } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
9333 reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
9334 reply_size);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009335#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07009336 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
9337 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
9338 reply_size);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009339#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009340 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
9341 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
9342 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009343 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08009344 pmksa_cache_clear_current(wpa_s->wpa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009345 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08009346#ifdef CONFIG_WNM
9347 } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
9348 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
9349 reply_len = -1;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08009350 } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
9351 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
Dmitry Shmidt44c95782013-05-17 09:51:35 -07009352 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08009353#endif /* CONFIG_WNM */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07009354 } else if (os_strcmp(buf, "FLUSH") == 0) {
9355 wpa_supplicant_ctrl_iface_flush(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009356 } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
9357 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
9358 reply_size);
Dmitry Shmidt818ea482014-03-10 13:15:21 -07009359#ifdef CONFIG_TESTING_OPTIONS
9360 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
9361 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
9362 reply_len = -1;
9363 } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
9364 wpas_ctrl_iface_mgmt_tx_done(wpa_s);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009365 } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
9366 if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
9367 reply_len = -1;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07009368 } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
9369 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
9370 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009371 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
9372 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
9373 reply_len = -1;
9374 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
9375 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
9376 reply_len = -1;
9377 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
9378 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
9379 reply_len = -1;
9380 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
9381 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
9382 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009383 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
9384 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
9385 reply_len = -1;
9386 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
9387 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009388 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
9389 if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0)
9390 reply_len = -1;
9391 } else if (os_strcmp(buf, "GET_FAIL") == 0) {
9392 reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
Jouni Malinenc4818362015-10-04 11:45:13 +03009393 } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
9394 if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
9395 reply_len = -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08009396 } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
9397 if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
9398 reply_len = -1;
Dmitry Shmidt818ea482014-03-10 13:15:21 -07009399#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07009400 } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
9401 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
9402 reply_len = -1;
9403 } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
9404 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
9405 reply_size);
9406 } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
9407 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
9408 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009409 } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009410 if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009411 reply_len = -1;
9412 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
9413 wpas_ctrl_iface_erp_flush(wpa_s);
9414 } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
9415 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
9416 reply_len = -1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009417 } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
9418 reply_len = wpas_ctrl_iface_get_pref_freq_list(
9419 wpa_s, buf + 19, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009420 } else {
9421 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
9422 reply_len = 16;
9423 }
9424
9425 if (reply_len < 0) {
9426 os_memcpy(reply, "FAIL\n", 5);
9427 reply_len = 5;
9428 }
9429
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009430 *resp_len = reply_len;
9431 return reply;
9432}
9433
9434
9435static int wpa_supplicant_global_iface_add(struct wpa_global *global,
9436 char *cmd)
9437{
9438 struct wpa_interface iface;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009439 char *pos, *extra;
9440 struct wpa_supplicant *wpa_s;
9441 unsigned int create_iface = 0;
9442 u8 mac_addr[ETH_ALEN];
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009443 enum wpa_driver_if_type type = WPA_IF_STATION;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009444
9445 /*
9446 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009447 * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009448 */
9449 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
9450
9451 os_memset(&iface, 0, sizeof(iface));
9452
9453 do {
9454 iface.ifname = pos = cmd;
9455 pos = os_strchr(pos, '\t');
9456 if (pos)
9457 *pos++ = '\0';
9458 if (iface.ifname[0] == '\0')
9459 return -1;
9460 if (pos == NULL)
9461 break;
9462
9463 iface.confname = pos;
9464 pos = os_strchr(pos, '\t');
9465 if (pos)
9466 *pos++ = '\0';
9467 if (iface.confname[0] == '\0')
9468 iface.confname = NULL;
9469 if (pos == NULL)
9470 break;
9471
9472 iface.driver = pos;
9473 pos = os_strchr(pos, '\t');
9474 if (pos)
9475 *pos++ = '\0';
9476 if (iface.driver[0] == '\0')
9477 iface.driver = NULL;
9478 if (pos == NULL)
9479 break;
9480
9481 iface.ctrl_interface = pos;
9482 pos = os_strchr(pos, '\t');
9483 if (pos)
9484 *pos++ = '\0';
9485 if (iface.ctrl_interface[0] == '\0')
9486 iface.ctrl_interface = NULL;
9487 if (pos == NULL)
9488 break;
9489
9490 iface.driver_param = pos;
9491 pos = os_strchr(pos, '\t');
9492 if (pos)
9493 *pos++ = '\0';
9494 if (iface.driver_param[0] == '\0')
9495 iface.driver_param = NULL;
9496 if (pos == NULL)
9497 break;
9498
9499 iface.bridge_ifname = pos;
9500 pos = os_strchr(pos, '\t');
9501 if (pos)
9502 *pos++ = '\0';
9503 if (iface.bridge_ifname[0] == '\0')
9504 iface.bridge_ifname = NULL;
9505 if (pos == NULL)
9506 break;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009507
9508 extra = pos;
9509 pos = os_strchr(pos, '\t');
9510 if (pos)
9511 *pos++ = '\0';
Dmitry Shmidt83474442015-04-15 13:47:09 -07009512 if (!extra[0])
9513 break;
9514
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009515 if (os_strcmp(extra, "create") == 0) {
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009516 create_iface = 1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009517 if (!pos)
9518 break;
9519
9520 if (os_strcmp(pos, "sta") == 0) {
9521 type = WPA_IF_STATION;
9522 } else if (os_strcmp(pos, "ap") == 0) {
9523 type = WPA_IF_AP_BSS;
9524 } else {
9525 wpa_printf(MSG_DEBUG,
9526 "INTERFACE_ADD unsupported interface type: '%s'",
9527 pos);
9528 return -1;
9529 }
9530 } else {
Dmitry Shmidt83474442015-04-15 13:47:09 -07009531 wpa_printf(MSG_DEBUG,
9532 "INTERFACE_ADD unsupported extra parameter: '%s'",
9533 extra);
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009534 return -1;
Dmitry Shmidt83474442015-04-15 13:47:09 -07009535 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009536 } while (0);
9537
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009538 if (create_iface) {
9539 wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
9540 iface.ifname);
9541 if (!global->ifaces)
9542 return -1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009543 if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009544 NULL, NULL, NULL, mac_addr, NULL) < 0) {
9545 wpa_printf(MSG_ERROR,
9546 "CTRL_IFACE interface creation failed");
9547 return -1;
9548 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009549
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009550 wpa_printf(MSG_DEBUG,
9551 "CTRL_IFACE interface '%s' created with MAC addr: "
9552 MACSTR, iface.ifname, MAC2STR(mac_addr));
9553 }
9554
9555 if (wpa_supplicant_get_iface(global, iface.ifname))
9556 goto fail;
9557
9558 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
9559 if (!wpa_s)
9560 goto fail;
9561 wpa_s->added_vif = create_iface;
9562 return 0;
9563
9564fail:
9565 if (create_iface)
9566 wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
9567 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009568}
9569
9570
9571static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
9572 char *cmd)
9573{
9574 struct wpa_supplicant *wpa_s;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009575 int ret;
9576 unsigned int delete_iface;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009577
9578 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
9579
9580 wpa_s = wpa_supplicant_get_iface(global, cmd);
9581 if (wpa_s == NULL)
9582 return -1;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07009583 delete_iface = wpa_s->added_vif;
9584 ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
9585 if (!ret && delete_iface) {
9586 wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
9587 cmd);
9588 ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
9589 }
9590 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009591}
9592
9593
9594static void wpa_free_iface_info(struct wpa_interface_info *iface)
9595{
9596 struct wpa_interface_info *prev;
9597
9598 while (iface) {
9599 prev = iface;
9600 iface = iface->next;
9601
9602 os_free(prev->ifname);
9603 os_free(prev->desc);
9604 os_free(prev);
9605 }
9606}
9607
9608
9609static int wpa_supplicant_global_iface_list(struct wpa_global *global,
9610 char *buf, int len)
9611{
9612 int i, res;
9613 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
9614 char *pos, *end;
9615
9616 for (i = 0; wpa_drivers[i]; i++) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009617 const struct wpa_driver_ops *drv = wpa_drivers[i];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009618 if (drv->get_interfaces == NULL)
9619 continue;
9620 tmp = drv->get_interfaces(global->drv_priv[i]);
9621 if (tmp == NULL)
9622 continue;
9623
9624 if (last == NULL)
9625 iface = last = tmp;
9626 else
9627 last->next = tmp;
9628 while (last->next)
9629 last = last->next;
9630 }
9631
9632 pos = buf;
9633 end = buf + len;
9634 for (tmp = iface; tmp; tmp = tmp->next) {
9635 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
9636 tmp->drv_name, tmp->ifname,
9637 tmp->desc ? tmp->desc : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009638 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009639 *pos = '\0';
9640 break;
9641 }
9642 pos += res;
9643 }
9644
9645 wpa_free_iface_info(iface);
9646
9647 return pos - buf;
9648}
9649
9650
9651static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08009652 const char *input,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009653 char *buf, int len)
9654{
9655 int res;
9656 char *pos, *end;
9657 struct wpa_supplicant *wpa_s;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08009658 int show_ctrl = 0;
9659
9660 if (input)
9661 show_ctrl = !!os_strstr(input, "ctrl");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009662
9663 wpa_s = global->ifaces;
9664 pos = buf;
9665 end = buf + len;
9666
9667 while (wpa_s) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08009668 if (show_ctrl)
9669 res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
9670 wpa_s->ifname,
9671 wpa_s->conf->ctrl_interface ?
9672 wpa_s->conf->ctrl_interface : "N/A");
9673 else
9674 res = os_snprintf(pos, end - pos, "%s\n",
9675 wpa_s->ifname);
9676
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009677 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009678 *pos = '\0';
9679 break;
9680 }
9681 pos += res;
9682 wpa_s = wpa_s->next;
9683 }
9684 return pos - buf;
9685}
9686
9687
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009688static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
9689 const char *ifname,
9690 char *cmd, size_t *resp_len)
9691{
9692 struct wpa_supplicant *wpa_s;
9693
9694 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9695 if (os_strcmp(ifname, wpa_s->ifname) == 0)
9696 break;
9697 }
9698
9699 if (wpa_s == NULL) {
9700 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
9701 if (resp)
9702 *resp_len = os_strlen(resp);
9703 else
9704 *resp_len = 1;
9705 return resp;
9706 }
9707
9708 return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
9709}
9710
9711
9712static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
9713 char *buf, size_t *resp_len)
9714{
9715#ifdef CONFIG_P2P
9716 static const char * cmd[] = {
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07009717 "LIST_NETWORKS",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009718 "P2P_FIND",
9719 "P2P_STOP_FIND",
9720 "P2P_LISTEN",
9721 "P2P_GROUP_ADD",
9722 "P2P_GET_PASSPHRASE",
9723 "P2P_SERVICE_UPDATE",
9724 "P2P_SERVICE_FLUSH",
9725 "P2P_FLUSH",
9726 "P2P_CANCEL",
9727 "P2P_PRESENCE_REQ",
9728 "P2P_EXT_LISTEN",
9729 NULL
9730 };
9731 static const char * prefix[] = {
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08009732#ifdef ANDROID
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07009733 "DRIVER ",
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08009734#endif /* ANDROID */
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07009735 "GET_NETWORK ",
9736 "REMOVE_NETWORK ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009737 "P2P_FIND ",
9738 "P2P_CONNECT ",
9739 "P2P_LISTEN ",
9740 "P2P_GROUP_REMOVE ",
9741 "P2P_GROUP_ADD ",
Dmitry Shmidt849734c2016-05-27 09:59:01 -07009742 "P2P_GROUP_MEMBER ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009743 "P2P_PROV_DISC ",
9744 "P2P_SERV_DISC_REQ ",
9745 "P2P_SERV_DISC_CANCEL_REQ ",
9746 "P2P_SERV_DISC_RESP ",
9747 "P2P_SERV_DISC_EXTERNAL ",
9748 "P2P_SERVICE_ADD ",
9749 "P2P_SERVICE_DEL ",
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009750 "P2P_SERVICE_REP ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009751 "P2P_REJECT ",
9752 "P2P_INVITE ",
9753 "P2P_PEER ",
9754 "P2P_SET ",
9755 "P2P_UNAUTHORIZE ",
9756 "P2P_PRESENCE_REQ ",
9757 "P2P_EXT_LISTEN ",
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07009758 "P2P_REMOVE_CLIENT ",
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08009759 "WPS_NFC_TOKEN ",
9760 "WPS_NFC_TAG_READ ",
Dmitry Shmidt413dde72014-04-11 10:23:22 -07009761 "NFC_GET_HANDOVER_SEL ",
9762 "NFC_GET_HANDOVER_REQ ",
9763 "NFC_REPORT_HANDOVER ",
Dmitry Shmidt216983b2015-02-06 10:50:36 -08009764 "P2P_ASP_PROVISION ",
9765 "P2P_ASP_PROVISION_RESP ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07009766 NULL
9767 };
9768 int found = 0;
9769 int i;
9770
9771 if (global->p2p_init_wpa_s == NULL)
9772 return NULL;
9773
9774 for (i = 0; !found && cmd[i]; i++) {
9775 if (os_strcmp(buf, cmd[i]) == 0)
9776 found = 1;
9777 }
9778
9779 for (i = 0; !found && prefix[i]; i++) {
9780 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
9781 found = 1;
9782 }
9783
9784 if (found)
9785 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
9786 buf, resp_len);
9787#endif /* CONFIG_P2P */
9788 return NULL;
9789}
9790
9791
9792static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
9793 char *buf, size_t *resp_len)
9794{
9795#ifdef CONFIG_WIFI_DISPLAY
9796 if (global->p2p_init_wpa_s == NULL)
9797 return NULL;
9798 if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
9799 os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
9800 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
9801 buf, resp_len);
9802#endif /* CONFIG_WIFI_DISPLAY */
9803 return NULL;
9804}
9805
9806
9807static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
9808 char *buf, size_t *resp_len)
9809{
9810 char *ret;
9811
9812 ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
9813 if (ret)
9814 return ret;
9815
9816 ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
9817 if (ret)
9818 return ret;
9819
9820 return NULL;
9821}
9822
9823
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009824static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
9825{
9826 char *value;
9827
9828 value = os_strchr(cmd, ' ');
9829 if (value == NULL)
9830 return -1;
9831 *value++ = '\0';
9832
9833 wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
9834
9835#ifdef CONFIG_WIFI_DISPLAY
9836 if (os_strcasecmp(cmd, "wifi_display") == 0) {
9837 wifi_display_enable(global, !!atoi(value));
9838 return 0;
9839 }
9840#endif /* CONFIG_WIFI_DISPLAY */
9841
Dmitry Shmidt61593f02014-04-21 16:27:35 -07009842 /* Restore cmd to its original value to allow redirection */
9843 value[-1] = ' ';
9844
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009845 return -1;
9846}
9847
9848
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009849static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global,
9850 char *cmd)
9851{
9852 struct wpa_supplicant *wpa_s[2]; /* src, dst */
9853 char *p;
9854 unsigned int i;
9855
9856 /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id>
9857 * <variable name> */
9858
9859 for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) {
9860 p = os_strchr(cmd, ' ');
9861 if (p == NULL)
9862 return -1;
9863 *p = '\0';
9864
9865 wpa_s[i] = global->ifaces;
9866 for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) {
9867 if (os_strcmp(cmd, wpa_s[i]->ifname) == 0)
9868 break;
9869 }
9870
9871 if (!wpa_s[i]) {
9872 wpa_printf(MSG_DEBUG,
9873 "CTRL_IFACE: Could not find iface=%s", cmd);
9874 return -1;
9875 }
9876
9877 cmd = p + 1;
9878 }
9879
9880 return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]);
9881}
9882
9883
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009884#ifndef CONFIG_NO_CONFIG_WRITE
9885static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
9886{
Dmitry Shmidt61593f02014-04-21 16:27:35 -07009887 int ret = 0, saved = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009888 struct wpa_supplicant *wpa_s;
9889
9890 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9891 if (!wpa_s->conf->update_config) {
9892 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
9893 continue;
9894 }
9895
9896 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
9897 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
9898 ret = 1;
9899 } else {
9900 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
Dmitry Shmidt61593f02014-04-21 16:27:35 -07009901 saved++;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009902 }
9903 }
9904
Dmitry Shmidt61593f02014-04-21 16:27:35 -07009905 if (!saved && !ret) {
9906 wpa_dbg(wpa_s, MSG_DEBUG,
9907 "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
9908 ret = 1;
9909 }
9910
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009911 return ret;
9912}
9913#endif /* CONFIG_NO_CONFIG_WRITE */
9914
9915
9916static int wpas_global_ctrl_iface_status(struct wpa_global *global,
9917 char *buf, size_t buflen)
9918{
9919 char *pos, *end;
9920 int ret;
9921 struct wpa_supplicant *wpa_s;
9922
9923 pos = buf;
9924 end = buf + buflen;
9925
9926#ifdef CONFIG_P2P
9927 if (global->p2p && !global->p2p_disabled) {
9928 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
9929 "\n"
9930 "p2p_state=%s\n",
9931 MAC2STR(global->p2p_dev_addr),
9932 p2p_get_state_txt(global->p2p));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009933 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009934 return pos - buf;
9935 pos += ret;
9936 } else if (global->p2p) {
9937 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009938 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009939 return pos - buf;
9940 pos += ret;
9941 }
9942#endif /* CONFIG_P2P */
9943
9944#ifdef CONFIG_WIFI_DISPLAY
9945 ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
9946 !!global->wifi_display);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009947 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009948 return pos - buf;
9949 pos += ret;
9950#endif /* CONFIG_WIFI_DISPLAY */
9951
9952 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9953 ret = os_snprintf(pos, end - pos, "ifname=%s\n"
9954 "address=" MACSTR "\n",
9955 wpa_s->ifname, MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009956 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009957 return pos - buf;
9958 pos += ret;
9959 }
9960
9961 return pos - buf;
9962}
9963
9964
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009965#ifdef CONFIG_FST
9966
9967static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global,
9968 char *cmd, char *buf,
9969 size_t reply_size)
9970{
9971 char ifname[IFNAMSIZ + 1];
9972 struct fst_iface_cfg cfg;
9973 struct wpa_supplicant *wpa_s;
9974 struct fst_wpa_obj iface_obj;
9975
9976 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
9977 wpa_s = wpa_supplicant_get_iface(global, ifname);
9978 if (wpa_s) {
9979 if (wpa_s->fst) {
9980 wpa_printf(MSG_INFO, "FST: Already attached");
9981 return -1;
9982 }
9983 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
9984 wpa_s->fst = fst_attach(ifname, wpa_s->own_addr,
9985 &iface_obj, &cfg);
9986 if (wpa_s->fst)
9987 return os_snprintf(buf, reply_size, "OK\n");
9988 }
9989 }
9990
9991 return -1;
9992}
9993
9994
9995static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global,
9996 char *cmd, char *buf,
9997 size_t reply_size)
9998{
9999 char ifname[IFNAMSIZ + 1];
10000 struct wpa_supplicant *wpa_s;
10001
10002 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
10003 wpa_s = wpa_supplicant_get_iface(global, ifname);
10004 if (wpa_s) {
10005 if (!fst_iface_detach(ifname)) {
10006 wpa_s->fst = NULL;
10007 return os_snprintf(buf, reply_size, "OK\n");
10008 }
10009 }
10010 }
10011
10012 return -1;
10013}
10014
10015#endif /* CONFIG_FST */
10016
10017
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010018char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
10019 char *buf, size_t *resp_len)
10020{
10021 char *reply;
10022 const int reply_size = 2048;
10023 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010024 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010025
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -070010026 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
10027 char *pos = os_strchr(buf + 7, ' ');
10028 if (pos) {
10029 *pos++ = '\0';
10030 return wpas_global_ctrl_iface_ifname(global,
10031 buf + 7, pos,
10032 resp_len);
10033 }
10034 }
10035
10036 reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
10037 if (reply)
10038 return reply;
10039
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010040 if (os_strcmp(buf, "PING") == 0)
10041 level = MSG_EXCESSIVE;
10042 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010043 (const u8 *) buf, os_strlen(buf));
10044
10045 reply = os_malloc(reply_size);
10046 if (reply == NULL) {
10047 *resp_len = 1;
10048 return NULL;
10049 }
10050
10051 os_memcpy(reply, "OK\n", 3);
10052 reply_len = 3;
10053
10054 if (os_strcmp(buf, "PING") == 0) {
10055 os_memcpy(reply, "PONG\n", 5);
10056 reply_len = 5;
10057 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
10058 if (wpa_supplicant_global_iface_add(global, buf + 14))
10059 reply_len = -1;
10060 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
10061 if (wpa_supplicant_global_iface_remove(global, buf + 17))
10062 reply_len = -1;
10063 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
10064 reply_len = wpa_supplicant_global_iface_list(
10065 global, reply, reply_size);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010066 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010067 reply_len = wpa_supplicant_global_iface_interfaces(
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080010068 global, buf + 10, reply, reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010069#ifdef CONFIG_FST
10070 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
10071 reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
10072 reply,
10073 reply_size);
10074 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
10075 reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11,
10076 reply,
10077 reply_size);
10078 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
10079 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
10080#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010081 } else if (os_strcmp(buf, "TERMINATE") == 0) {
10082 wpa_supplicant_terminate_proc(global);
10083 } else if (os_strcmp(buf, "SUSPEND") == 0) {
10084 wpas_notify_suspend(global);
10085 } else if (os_strcmp(buf, "RESUME") == 0) {
10086 wpas_notify_resume(global);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010087 } else if (os_strncmp(buf, "SET ", 4) == 0) {
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010088 if (wpas_global_ctrl_iface_set(global, buf + 4)) {
10089#ifdef CONFIG_P2P
10090 if (global->p2p_init_wpa_s) {
10091 os_free(reply);
10092 /* Check if P2P redirection would work for this
10093 * command. */
10094 return wpa_supplicant_ctrl_iface_process(
10095 global->p2p_init_wpa_s,
10096 buf, resp_len);
10097 }
10098#endif /* CONFIG_P2P */
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010099 reply_len = -1;
Dmitry Shmidt61593f02014-04-21 16:27:35 -070010100 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010101 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
10102 if (wpas_global_ctrl_iface_dup_network(global, buf + 12))
10103 reply_len = -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010104#ifndef CONFIG_NO_CONFIG_WRITE
10105 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
10106 if (wpas_global_ctrl_iface_save_config(global))
10107 reply_len = -1;
10108#endif /* CONFIG_NO_CONFIG_WRITE */
10109 } else if (os_strcmp(buf, "STATUS") == 0) {
10110 reply_len = wpas_global_ctrl_iface_status(global, reply,
10111 reply_size);
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -080010112#ifdef CONFIG_MODULE_TESTS
10113 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -080010114 if (wpas_module_tests() < 0)
10115 reply_len = -1;
10116#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010117 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
10118 if (wpa_debug_reopen_file() < 0)
10119 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010120 } else {
10121 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
10122 reply_len = 16;
10123 }
10124
10125 if (reply_len < 0) {
10126 os_memcpy(reply, "FAIL\n", 5);
10127 reply_len = 5;
10128 }
10129
10130 *resp_len = reply_len;
10131 return reply;
10132}