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