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