blob: 9c3f93d6627d5870cd46040448e1ef266a3fd7c1 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / Control interface (shared code for all backends)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010#ifdef CONFIG_TESTING_OPTIONS
11#include <net/ethernet.h>
12#include <netinet/ip.h>
13#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014
15#include "utils/common.h"
16#include "utils/eloop.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080017#include "utils/uuid.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018#include "common/version.h"
19#include "common/ieee802_11_defs.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070020#include "common/ieee802_11_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "common/wpa_ctrl.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080022#include "crypto/tls.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080023#include "ap/hostapd.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024#include "eap_peer/eap.h"
25#include "eapol_supp/eapol_supp_sm.h"
26#include "rsn_supp/wpa.h"
27#include "rsn_supp/preauth.h"
28#include "rsn_supp/pmksa_cache.h"
29#include "l2_packet/l2_packet.h"
30#include "wps/wps.h"
31#include "config.h"
32#include "wpa_supplicant_i.h"
33#include "driver_i.h"
34#include "wps_supplicant.h"
35#include "ibss_rsn.h"
36#include "ap.h"
37#include "p2p_supplicant.h"
38#include "p2p/p2p.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070039#include "hs20_supplicant.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070040#include "wifi_display.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041#include "notify.h"
42#include "bss.h"
43#include "scan.h"
44#include "ctrl_iface.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080045#include "interworking.h"
Dmitry Shmidte19501d2011-03-16 14:32:18 -070046#include "blacklist.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070047#include "autoscan.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080048#include "wnm_sta.h"
Dmitry Shmidt818ea482014-03-10 13:15:21 -070049#include "offchannel.h"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070050#include "drivers/driver.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080051#include "mesh.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070052
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070053static int wpa_supplicant_global_iface_list(struct wpa_global *global,
54 char *buf, int len);
55static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
56 char *buf, int len);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -070057static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
58 char *val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070059
Dmitry Shmidt04949592012-07-19 12:16:46 -070060static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
61{
62 char *pos;
63 u8 addr[ETH_ALEN], *filter = NULL, *n;
64 size_t count = 0;
65
66 pos = val;
67 while (pos) {
68 if (*pos == '\0')
69 break;
70 if (hwaddr_aton(pos, addr)) {
71 os_free(filter);
72 return -1;
73 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070074 n = os_realloc_array(filter, count + 1, ETH_ALEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -070075 if (n == NULL) {
76 os_free(filter);
77 return -1;
78 }
79 filter = n;
80 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
81 count++;
82
83 pos = os_strchr(pos, ' ');
84 if (pos)
85 pos++;
86 }
87
88 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
89 os_free(wpa_s->bssid_filter);
90 wpa_s->bssid_filter = filter;
91 wpa_s->bssid_filter_count = count;
92
93 return 0;
94}
95
96
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080097static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
98{
99 char *pos;
100 u8 addr[ETH_ALEN], *bssid = NULL, *n;
101 struct wpa_ssid_value *ssid = NULL, *ns;
102 size_t count = 0, ssid_count = 0;
103 struct wpa_ssid *c;
104
105 /*
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800106 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800107 * SSID_SPEC ::= ssid <SSID_HEX>
108 * BSSID_SPEC ::= bssid <BSSID_HEX>
109 */
110
111 pos = val;
112 while (pos) {
113 if (*pos == '\0')
114 break;
115 if (os_strncmp(pos, "bssid ", 6) == 0) {
116 int res;
117 pos += 6;
118 res = hwaddr_aton2(pos, addr);
119 if (res < 0) {
120 os_free(ssid);
121 os_free(bssid);
122 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
123 "BSSID value '%s'", pos);
124 return -1;
125 }
126 pos += res;
127 n = os_realloc_array(bssid, count + 1, ETH_ALEN);
128 if (n == NULL) {
129 os_free(ssid);
130 os_free(bssid);
131 return -1;
132 }
133 bssid = n;
134 os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
135 count++;
136 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
137 char *end;
138 pos += 5;
139
140 end = pos;
141 while (*end) {
142 if (*end == '\0' || *end == ' ')
143 break;
144 end++;
145 }
146
147 ns = os_realloc_array(ssid, ssid_count + 1,
148 sizeof(struct wpa_ssid_value));
149 if (ns == NULL) {
150 os_free(ssid);
151 os_free(bssid);
152 return -1;
153 }
154 ssid = ns;
155
156 if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
157 hexstr2bin(pos, ssid[ssid_count].ssid,
158 (end - pos) / 2) < 0) {
159 os_free(ssid);
160 os_free(bssid);
161 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
162 "SSID value '%s'", pos);
163 return -1;
164 }
165 ssid[ssid_count].ssid_len = (end - pos) / 2;
166 wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
167 ssid[ssid_count].ssid,
168 ssid[ssid_count].ssid_len);
169 ssid_count++;
170 pos = end;
171 } else {
172 wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
173 "'%s'", pos);
174 os_free(ssid);
175 os_free(bssid);
176 return -1;
177 }
178
179 pos = os_strchr(pos, ' ');
180 if (pos)
181 pos++;
182 }
183
184 wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
185 os_free(wpa_s->disallow_aps_bssid);
186 wpa_s->disallow_aps_bssid = bssid;
187 wpa_s->disallow_aps_bssid_count = count;
188
189 wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
190 os_free(wpa_s->disallow_aps_ssid);
191 wpa_s->disallow_aps_ssid = ssid;
192 wpa_s->disallow_aps_ssid_count = ssid_count;
193
194 if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
195 return 0;
196
197 c = wpa_s->current_ssid;
198 if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
199 return 0;
200
201 if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
202 !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
203 return 0;
204
205 wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
206 "because current AP was marked disallowed");
207
208#ifdef CONFIG_SME
209 wpa_s->sme.prev_bssid_set = 0;
210#endif /* CONFIG_SME */
211 wpa_s->reassociate = 1;
212 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
213 wpa_supplicant_req_scan(wpa_s, 0, 0);
214
215 return 0;
216}
217
218
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700219#ifndef CONFIG_NO_CONFIG_BLOBS
220static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
221{
222 char *name = pos;
223 struct wpa_config_blob *blob;
224 size_t len;
225
226 pos = os_strchr(pos, ' ');
227 if (pos == NULL)
228 return -1;
229 *pos++ = '\0';
230 len = os_strlen(pos);
231 if (len & 1)
232 return -1;
233
234 wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
235 blob = os_zalloc(sizeof(*blob));
236 if (blob == NULL)
237 return -1;
238 blob->name = os_strdup(name);
239 blob->data = os_malloc(len / 2);
240 if (blob->name == NULL || blob->data == NULL) {
241 wpa_config_free_blob(blob);
242 return -1;
243 }
244
245 if (hexstr2bin(pos, blob->data, len / 2) < 0) {
246 wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
247 wpa_config_free_blob(blob);
248 return -1;
249 }
250 blob->len = len / 2;
251
252 wpa_config_set_blob(wpa_s->conf, blob);
253
254 return 0;
255}
256#endif /* CONFIG_NO_CONFIG_BLOBS */
257
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700258
259static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
260{
261 char *params;
262 char *pos;
263 int *freqs = NULL;
264 int ret;
265
266 if (atoi(cmd)) {
267 params = os_strchr(cmd, ' ');
268 os_free(wpa_s->manual_sched_scan_freqs);
269 if (params) {
270 params++;
271 pos = os_strstr(params, "freq=");
272 if (pos)
273 freqs = freq_range_to_channel_list(wpa_s,
274 pos + 5);
275 }
276 wpa_s->manual_sched_scan_freqs = freqs;
277 ret = wpas_start_pno(wpa_s);
278 } else {
279 ret = wpas_stop_pno(wpa_s);
280 }
281 return ret;
282}
283
284
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
286 char *cmd)
287{
288 char *value;
289 int ret = 0;
290
291 value = os_strchr(cmd, ' ');
292 if (value == NULL)
293 return -1;
294 *value++ = '\0';
295
296 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
297 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
298 eapol_sm_configure(wpa_s->eapol,
299 atoi(value), -1, -1, -1);
300 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
301 eapol_sm_configure(wpa_s->eapol,
302 -1, atoi(value), -1, -1);
303 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
304 eapol_sm_configure(wpa_s->eapol,
305 -1, -1, atoi(value), -1);
306 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
307 eapol_sm_configure(wpa_s->eapol,
308 -1, -1, -1, atoi(value));
309 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
310 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
311 atoi(value)))
312 ret = -1;
313 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
314 0) {
315 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
316 atoi(value)))
317 ret = -1;
318 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
319 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
320 ret = -1;
321 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
322 wpa_s->wps_fragment_size = atoi(value);
323#ifdef CONFIG_WPS_TESTING
324 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
325 long int val;
326 val = strtol(value, NULL, 0);
327 if (val < 0 || val > 0xff) {
328 ret = -1;
329 wpa_printf(MSG_DEBUG, "WPS: Invalid "
330 "wps_version_number %ld", val);
331 } else {
332 wps_version_number = val;
333 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
334 "version %u.%u",
335 (wps_version_number & 0xf0) >> 4,
336 wps_version_number & 0x0f);
337 }
338 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
339 wps_testing_dummy_cred = atoi(value);
340 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
341 wps_testing_dummy_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800342 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
343 wps_corrupt_pkhash = atoi(value);
344 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
345 wps_corrupt_pkhash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346#endif /* CONFIG_WPS_TESTING */
347 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
348 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
349 ret = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800350#ifdef CONFIG_TDLS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700351#ifdef CONFIG_TDLS_TESTING
352 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
353 extern unsigned int tdls_testing;
354 tdls_testing = strtol(value, NULL, 0);
355 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
356#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
358 int disabled = atoi(value);
359 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
360 if (disabled) {
361 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
362 ret = -1;
363 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
364 ret = -1;
365 wpa_tdls_enable(wpa_s->wpa, !disabled);
366#endif /* CONFIG_TDLS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800367 } else if (os_strcasecmp(cmd, "pno") == 0) {
Dmitry Shmidtd11f0192014-03-24 12:09:47 -0700368 ret = wpas_ctrl_pno(wpa_s, value);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700369 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
370 int disabled = atoi(value);
371 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
372 ret = -1;
373 else if (disabled)
374 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
375 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
376 if (os_strcmp(value, "disable") == 0)
377 wpa_s->set_sta_uapsd = 0;
378 else {
379 int be, bk, vi, vo;
380 char *pos;
381 /* format: BE,BK,VI,VO;max SP Length */
382 be = atoi(value);
383 pos = os_strchr(value, ',');
384 if (pos == NULL)
385 return -1;
386 pos++;
387 bk = atoi(pos);
388 pos = os_strchr(pos, ',');
389 if (pos == NULL)
390 return -1;
391 pos++;
392 vi = atoi(pos);
393 pos = os_strchr(pos, ',');
394 if (pos == NULL)
395 return -1;
396 pos++;
397 vo = atoi(pos);
398 /* ignore max SP Length for now */
399
400 wpa_s->set_sta_uapsd = 1;
401 wpa_s->sta_uapsd = 0;
402 if (be)
403 wpa_s->sta_uapsd |= BIT(0);
404 if (bk)
405 wpa_s->sta_uapsd |= BIT(1);
406 if (vi)
407 wpa_s->sta_uapsd |= BIT(2);
408 if (vo)
409 wpa_s->sta_uapsd |= BIT(3);
410 }
Jouni Malinen21d6bc82012-04-10 16:17:59 -0700411 } else if (os_strcasecmp(cmd, "ps") == 0) {
412 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700413#ifdef CONFIG_WIFI_DISPLAY
414 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800415 int enabled = !!atoi(value);
416 if (enabled && !wpa_s->global->p2p)
417 ret = -1;
418 else
419 wifi_display_enable(wpa_s->global, enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700420#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700421 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
422 ret = set_bssid_filter(wpa_s, value);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800423 } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
424 ret = set_disallow_aps(wpa_s, value);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800425 } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
426 wpa_s->no_keep_alive = !!atoi(value);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700427#ifdef CONFIG_TESTING_OPTIONS
428 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
429 wpa_s->ext_mgmt_frame_handling = !!atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800430 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
431 wpa_s->ext_eapol_frame_io = !!atoi(value);
432#ifdef CONFIG_AP
433 if (wpa_s->ap_iface) {
434 wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
435 wpa_s->ext_eapol_frame_io;
436 }
437#endif /* CONFIG_AP */
438 } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
439 wpa_s->extra_roc_dur = atoi(value);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700440#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700441#ifndef CONFIG_NO_CONFIG_BLOBS
442 } else if (os_strcmp(cmd, "blob") == 0) {
443 ret = wpas_ctrl_set_blob(wpa_s, value);
444#endif /* CONFIG_NO_CONFIG_BLOBS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800445 } else if (os_strcasecmp(cmd, "setband") == 0) {
446 if (os_strcmp(value, "AUTO") == 0)
447 wpa_s->setband = WPA_SETBAND_AUTO;
448 else if (os_strcmp(value, "5G") == 0)
449 wpa_s->setband = WPA_SETBAND_5G;
450 else if (os_strcmp(value, "2G") == 0)
451 wpa_s->setband = WPA_SETBAND_2G;
452 else
453 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700454 } else {
455 value[-1] = '=';
456 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
457 if (ret == 0)
458 wpa_supplicant_update_config(wpa_s);
459 }
460
461 return ret;
462}
463
464
465static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
466 char *cmd, char *buf, size_t buflen)
467{
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700468 int res = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700469
470 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
471
472 if (os_strcmp(cmd, "version") == 0) {
473 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700474 } else if (os_strcasecmp(cmd, "country") == 0) {
475 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
476 res = os_snprintf(buf, buflen, "%c%c",
477 wpa_s->conf->country[0],
478 wpa_s->conf->country[1]);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700479#ifdef CONFIG_WIFI_DISPLAY
480 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
Dmitry Shmidted003d22014-02-06 10:09:12 -0800481 int enabled;
482 if (wpa_s->global->p2p == NULL ||
483 wpa_s->global->p2p_disabled)
484 enabled = 0;
485 else
486 enabled = wpa_s->global->wifi_display;
487 res = os_snprintf(buf, buflen, "%d", enabled);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700488#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700489#ifdef CONFIG_TESTING_GET_GTK
490 } else if (os_strcmp(cmd, "gtk") == 0) {
491 if (wpa_s->last_gtk_len == 0)
492 return -1;
493 res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
494 wpa_s->last_gtk_len);
495 return res;
496#endif /* CONFIG_TESTING_GET_GTK */
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800497 } else if (os_strcmp(cmd, "tls_library") == 0) {
498 res = tls_get_library_version(buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700499 }
500
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800501 if (os_snprintf_error(buflen, res))
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700502 return -1;
503 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700504}
505
506
507#ifdef IEEE8021X_EAPOL
508static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
509 char *addr)
510{
511 u8 bssid[ETH_ALEN];
512 struct wpa_ssid *ssid = wpa_s->current_ssid;
513
514 if (hwaddr_aton(addr, bssid)) {
515 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
516 "'%s'", addr);
517 return -1;
518 }
519
520 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
521 rsn_preauth_deinit(wpa_s->wpa);
522 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
523 return -1;
524
525 return 0;
526}
527#endif /* IEEE8021X_EAPOL */
528
529
530#ifdef CONFIG_PEERKEY
531/* MLME-STKSTART.request(peer) */
532static int wpa_supplicant_ctrl_iface_stkstart(
533 struct wpa_supplicant *wpa_s, char *addr)
534{
535 u8 peer[ETH_ALEN];
536
537 if (hwaddr_aton(addr, peer)) {
538 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
539 "address '%s'", addr);
540 return -1;
541 }
542
543 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
544 MAC2STR(peer));
545
546 return wpa_sm_stkstart(wpa_s->wpa, peer);
547}
548#endif /* CONFIG_PEERKEY */
549
550
551#ifdef CONFIG_TDLS
552
553static int wpa_supplicant_ctrl_iface_tdls_discover(
554 struct wpa_supplicant *wpa_s, char *addr)
555{
556 u8 peer[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800557 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700558
559 if (hwaddr_aton(addr, peer)) {
560 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
561 "address '%s'", addr);
562 return -1;
563 }
564
565 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
566 MAC2STR(peer));
567
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800568 if (wpa_tdls_is_external_setup(wpa_s->wpa))
569 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
570 else
571 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
572
573 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700574}
575
576
577static int wpa_supplicant_ctrl_iface_tdls_setup(
578 struct wpa_supplicant *wpa_s, char *addr)
579{
580 u8 peer[ETH_ALEN];
581 int ret;
582
583 if (hwaddr_aton(addr, peer)) {
584 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
585 "address '%s'", addr);
586 return -1;
587 }
588
589 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
590 MAC2STR(peer));
591
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800592 if ((wpa_s->conf->tdls_external_control) &&
593 wpa_tdls_is_external_setup(wpa_s->wpa))
594 return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
595
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800596 wpa_tdls_remove(wpa_s->wpa, peer);
597
598 if (wpa_tdls_is_external_setup(wpa_s->wpa))
599 ret = wpa_tdls_start(wpa_s->wpa, peer);
600 else
601 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800602
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700603 return ret;
604}
605
606
607static int wpa_supplicant_ctrl_iface_tdls_teardown(
608 struct wpa_supplicant *wpa_s, char *addr)
609{
610 u8 peer[ETH_ALEN];
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700611 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700612
Dmitry Shmidt43cb5782014-06-16 16:23:22 -0700613 if (os_strcmp(addr, "*") == 0) {
614 /* remove everyone */
615 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
616 wpa_tdls_teardown_peers(wpa_s->wpa);
617 return 0;
618 }
619
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700620 if (hwaddr_aton(addr, peer)) {
621 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
622 "address '%s'", addr);
623 return -1;
624 }
625
626 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
627 MAC2STR(peer));
628
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800629 if ((wpa_s->conf->tdls_external_control) &&
630 wpa_tdls_is_external_setup(wpa_s->wpa))
631 return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
632
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700633 if (wpa_tdls_is_external_setup(wpa_s->wpa))
634 ret = wpa_tdls_teardown_link(
635 wpa_s->wpa, peer,
636 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
637 else
638 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
639
640 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700641}
642
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700643
644static int ctrl_iface_get_capability_tdls(
645 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
646{
647 int ret;
648
649 ret = os_snprintf(buf, buflen, "%s\n",
650 wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
651 (wpa_s->drv_flags &
652 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
653 "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800654 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700655 return -1;
656 return ret;
657}
658
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800659
660static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
661 struct wpa_supplicant *wpa_s, char *cmd)
662{
663 u8 peer[ETH_ALEN];
664 struct hostapd_freq_params freq_params;
665 u8 oper_class;
666 char *pos, *end;
667
668 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
669 wpa_printf(MSG_INFO,
670 "tdls_chanswitch: Only supported with external setup");
671 return -1;
672 }
673
674 os_memset(&freq_params, 0, sizeof(freq_params));
675
676 pos = os_strchr(cmd, ' ');
677 if (pos == NULL)
678 return -1;
679 *pos++ = '\0';
680
681 oper_class = strtol(pos, &end, 10);
682 if (pos == end) {
683 wpa_printf(MSG_INFO,
684 "tdls_chanswitch: Invalid op class provided");
685 return -1;
686 }
687
688 pos = end;
689 freq_params.freq = atoi(pos);
690 if (freq_params.freq == 0) {
691 wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
692 return -1;
693 }
694
695#define SET_FREQ_SETTING(str) \
696 do { \
697 const char *pos2 = os_strstr(pos, " " #str "="); \
698 if (pos2) { \
699 pos2 += sizeof(" " #str "=") - 1; \
700 freq_params.str = atoi(pos2); \
701 } \
702 } while (0)
703
704 SET_FREQ_SETTING(center_freq1);
705 SET_FREQ_SETTING(center_freq2);
706 SET_FREQ_SETTING(bandwidth);
707 SET_FREQ_SETTING(sec_channel_offset);
708#undef SET_FREQ_SETTING
709
710 freq_params.ht_enabled = !!os_strstr(pos, " ht");
711 freq_params.vht_enabled = !!os_strstr(pos, " vht");
712
713 if (hwaddr_aton(cmd, peer)) {
714 wpa_printf(MSG_DEBUG,
715 "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
716 cmd);
717 return -1;
718 }
719
720 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
721 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
722 MAC2STR(peer), oper_class, freq_params.freq,
723 freq_params.center_freq1, freq_params.center_freq2,
724 freq_params.bandwidth, freq_params.sec_channel_offset,
725 freq_params.ht_enabled ? " HT" : "",
726 freq_params.vht_enabled ? " VHT" : "");
727
728 return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
729 &freq_params);
730}
731
732
733static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
734 struct wpa_supplicant *wpa_s, char *cmd)
735{
736 u8 peer[ETH_ALEN];
737
738 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
739 wpa_printf(MSG_INFO,
740 "tdls_chanswitch: Only supported with external setup");
741 return -1;
742 }
743
744 if (hwaddr_aton(cmd, peer)) {
745 wpa_printf(MSG_DEBUG,
746 "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
747 cmd);
748 return -1;
749 }
750
751 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
752 MAC2STR(peer));
753
754 return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
755}
756
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700757#endif /* CONFIG_TDLS */
758
759
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800760static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
761{
762 char *token, *context = NULL;
763 struct wmm_ac_ts_setup_params params = {
764 .tsid = 0xff,
765 .direction = 0xff,
766 };
767
768 while ((token = str_token(cmd, " ", &context))) {
769 if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
770 sscanf(token, "up=%i", &params.user_priority) == 1 ||
771 sscanf(token, "nominal_msdu_size=%i",
772 &params.nominal_msdu_size) == 1 ||
773 sscanf(token, "mean_data_rate=%i",
774 &params.mean_data_rate) == 1 ||
775 sscanf(token, "min_phy_rate=%i",
776 &params.minimum_phy_rate) == 1 ||
777 sscanf(token, "sba=%i",
778 &params.surplus_bandwidth_allowance) == 1)
779 continue;
780
781 if (os_strcasecmp(token, "downlink") == 0) {
782 params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
783 } else if (os_strcasecmp(token, "uplink") == 0) {
784 params.direction = WMM_TSPEC_DIRECTION_UPLINK;
785 } else if (os_strcasecmp(token, "bidi") == 0) {
786 params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
787 } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
788 params.fixed_nominal_msdu = 1;
789 } else {
790 wpa_printf(MSG_DEBUG,
791 "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
792 token);
793 return -1;
794 }
795
796 }
797
798 return wpas_wmm_ac_addts(wpa_s, &params);
799}
800
801
802static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
803{
804 u8 tsid = atoi(cmd);
805
806 return wpas_wmm_ac_delts(wpa_s, tsid);
807}
808
809
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810#ifdef CONFIG_IEEE80211R
811static int wpa_supplicant_ctrl_iface_ft_ds(
812 struct wpa_supplicant *wpa_s, char *addr)
813{
814 u8 target_ap[ETH_ALEN];
815 struct wpa_bss *bss;
816 const u8 *mdie;
817
818 if (hwaddr_aton(addr, target_ap)) {
819 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
820 "address '%s'", addr);
821 return -1;
822 }
823
824 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
825
826 bss = wpa_bss_get_bssid(wpa_s, target_ap);
827 if (bss)
828 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
829 else
830 mdie = NULL;
831
832 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
833}
834#endif /* CONFIG_IEEE80211R */
835
836
837#ifdef CONFIG_WPS
838static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
839 char *cmd)
840{
841 u8 bssid[ETH_ALEN], *_bssid = bssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700842#ifdef CONFIG_P2P
843 u8 p2p_dev_addr[ETH_ALEN];
844#endif /* CONFIG_P2P */
845#ifdef CONFIG_AP
846 u8 *_p2p_dev_addr = NULL;
847#endif /* CONFIG_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800848
Dmitry Shmidtc0a8db02013-11-08 11:18:33 -0800849 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700850 _bssid = NULL;
851#ifdef CONFIG_P2P
852 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
853 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
854 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
855 "P2P Device Address '%s'",
856 cmd + 13);
857 return -1;
858 }
859 _p2p_dev_addr = p2p_dev_addr;
860#endif /* CONFIG_P2P */
861 } else if (hwaddr_aton(cmd, bssid)) {
862 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
863 cmd);
864 return -1;
865 }
866
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800867#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700868 if (wpa_s->ap_iface)
869 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
870#endif /* CONFIG_AP */
871
872 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
873}
874
875
876static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
877 char *cmd, char *buf,
878 size_t buflen)
879{
880 u8 bssid[ETH_ALEN], *_bssid = bssid;
881 char *pin;
882 int ret;
883
884 pin = os_strchr(cmd, ' ');
885 if (pin)
886 *pin++ = '\0';
887
888 if (os_strcmp(cmd, "any") == 0)
889 _bssid = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800890 else if (os_strcmp(cmd, "get") == 0) {
891 ret = wps_generate_pin();
892 goto done;
893 } else if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700894 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
895 cmd);
896 return -1;
897 }
898
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800899#ifdef CONFIG_AP
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800900 if (wpa_s->ap_iface) {
901 int timeout = 0;
902 char *pos;
903
904 if (pin) {
905 pos = os_strchr(pin, ' ');
906 if (pos) {
907 *pos++ = '\0';
908 timeout = atoi(pos);
909 }
910 }
911
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700912 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800913 buf, buflen, timeout);
914 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700915#endif /* CONFIG_AP */
916
917 if (pin) {
918 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
919 DEV_PW_DEFAULT);
920 if (ret < 0)
921 return -1;
922 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800923 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700924 return -1;
925 return ret;
926 }
927
928 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
929 if (ret < 0)
930 return -1;
931
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800932done:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 /* Return the generated PIN */
934 ret = os_snprintf(buf, buflen, "%08d", ret);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800935 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700936 return -1;
937 return ret;
938}
939
940
941static int wpa_supplicant_ctrl_iface_wps_check_pin(
942 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
943{
944 char pin[9];
945 size_t len;
946 char *pos;
947 int ret;
948
949 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
950 (u8 *) cmd, os_strlen(cmd));
951 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
952 if (*pos < '0' || *pos > '9')
953 continue;
954 pin[len++] = *pos;
955 if (len == 9) {
956 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
957 return -1;
958 }
959 }
960 if (len != 4 && len != 8) {
961 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
962 return -1;
963 }
964 pin[len] = '\0';
965
966 if (len == 8) {
967 unsigned int pin_val;
968 pin_val = atoi(pin);
969 if (!wps_pin_valid(pin_val)) {
970 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
971 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800972 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700973 return -1;
974 return ret;
975 }
976 }
977
978 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800979 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700980 return -1;
981
982 return ret;
983}
984
985
Dmitry Shmidt04949592012-07-19 12:16:46 -0700986#ifdef CONFIG_WPS_NFC
987
988static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
989 char *cmd)
990{
991 u8 bssid[ETH_ALEN], *_bssid = bssid;
992
993 if (cmd == NULL || cmd[0] == '\0')
994 _bssid = NULL;
995 else if (hwaddr_aton(cmd, bssid))
996 return -1;
997
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800998 return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
999 0, 0);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001000}
1001
1002
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001003static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
1004 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1005{
1006 int ndef;
1007 struct wpabuf *buf;
1008 int res;
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001009 char *pos;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001010
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001011 pos = os_strchr(cmd, ' ');
1012 if (pos)
1013 *pos++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001014 if (os_strcmp(cmd, "WPS") == 0)
1015 ndef = 0;
1016 else if (os_strcmp(cmd, "NDEF") == 0)
1017 ndef = 1;
1018 else
1019 return -1;
1020
Dmitry Shmidt1e78e762013-04-02 11:05:36 -07001021 buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001022 if (buf == NULL)
1023 return -1;
1024
1025 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1026 wpabuf_len(buf));
1027 reply[res++] = '\n';
1028 reply[res] = '\0';
1029
1030 wpabuf_free(buf);
1031
1032 return res;
1033}
1034
1035
Dmitry Shmidt04949592012-07-19 12:16:46 -07001036static int wpa_supplicant_ctrl_iface_wps_nfc_token(
1037 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1038{
1039 int ndef;
1040 struct wpabuf *buf;
1041 int res;
1042
1043 if (os_strcmp(cmd, "WPS") == 0)
1044 ndef = 0;
1045 else if (os_strcmp(cmd, "NDEF") == 0)
1046 ndef = 1;
1047 else
1048 return -1;
1049
1050 buf = wpas_wps_nfc_token(wpa_s, ndef);
1051 if (buf == NULL)
1052 return -1;
1053
1054 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1055 wpabuf_len(buf));
1056 reply[res++] = '\n';
1057 reply[res] = '\0';
1058
1059 wpabuf_free(buf);
1060
1061 return res;
1062}
1063
1064
1065static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
1066 struct wpa_supplicant *wpa_s, char *pos)
1067{
1068 size_t len;
1069 struct wpabuf *buf;
1070 int ret;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001071 char *freq;
1072 int forced_freq = 0;
1073
1074 freq = strstr(pos, " freq=");
1075 if (freq) {
1076 *freq = '\0';
1077 freq += 6;
1078 forced_freq = atoi(freq);
1079 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001080
1081 len = os_strlen(pos);
1082 if (len & 0x01)
1083 return -1;
1084 len /= 2;
1085
1086 buf = wpabuf_alloc(len);
1087 if (buf == NULL)
1088 return -1;
1089 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
1090 wpabuf_free(buf);
1091 return -1;
1092 }
1093
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001094 ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001095 wpabuf_free(buf);
1096
1097 return ret;
1098}
1099
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001100
1101static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001102 char *reply, size_t max_len,
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001103 int ndef)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001104{
1105 struct wpabuf *buf;
1106 int res;
1107
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001108 buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001109 if (buf == NULL)
1110 return -1;
1111
1112 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1113 wpabuf_len(buf));
1114 reply[res++] = '\n';
1115 reply[res] = '\0';
1116
1117 wpabuf_free(buf);
1118
1119 return res;
1120}
1121
1122
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001123#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001124static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
1125 char *reply, size_t max_len,
1126 int ndef)
1127{
1128 struct wpabuf *buf;
1129 int res;
1130
1131 buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
1132 if (buf == NULL) {
1133 wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
1134 return -1;
1135 }
1136
1137 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1138 wpabuf_len(buf));
1139 reply[res++] = '\n';
1140 reply[res] = '\0';
1141
1142 wpabuf_free(buf);
1143
1144 return res;
1145}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001146#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001147
1148
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001149static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
1150 char *cmd, char *reply,
1151 size_t max_len)
1152{
1153 char *pos;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001154 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001155
1156 pos = os_strchr(cmd, ' ');
1157 if (pos == NULL)
1158 return -1;
1159 *pos++ = '\0';
1160
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001161 if (os_strcmp(cmd, "WPS") == 0)
1162 ndef = 0;
1163 else if (os_strcmp(cmd, "NDEF") == 0)
1164 ndef = 1;
1165 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001166 return -1;
1167
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001168 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001169 if (!ndef)
1170 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001171 return wpas_ctrl_nfc_get_handover_req_wps(
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001172 wpa_s, reply, max_len, ndef);
1173 }
1174
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001175#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001176 if (os_strcmp(pos, "P2P-CR") == 0) {
1177 return wpas_ctrl_nfc_get_handover_req_p2p(
1178 wpa_s, reply, max_len, ndef);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001179 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001180#endif /* CONFIG_P2P */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001181
1182 return -1;
1183}
1184
1185
1186static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001187 char *reply, size_t max_len,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001188 int ndef, int cr, char *uuid)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001189{
1190 struct wpabuf *buf;
1191 int res;
1192
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001193 buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001194 if (buf == NULL)
1195 return -1;
1196
1197 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1198 wpabuf_len(buf));
1199 reply[res++] = '\n';
1200 reply[res] = '\0';
1201
1202 wpabuf_free(buf);
1203
1204 return res;
1205}
1206
1207
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001208#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001209static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
1210 char *reply, size_t max_len,
1211 int ndef, int tag)
1212{
1213 struct wpabuf *buf;
1214 int res;
1215
1216 buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
1217 if (buf == NULL)
1218 return -1;
1219
1220 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1221 wpabuf_len(buf));
1222 reply[res++] = '\n';
1223 reply[res] = '\0';
1224
1225 wpabuf_free(buf);
1226
1227 return res;
1228}
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001229#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001230
1231
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001232static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
1233 char *cmd, char *reply,
1234 size_t max_len)
1235{
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001236 char *pos, *pos2;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001237 int ndef;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001238
1239 pos = os_strchr(cmd, ' ');
1240 if (pos == NULL)
1241 return -1;
1242 *pos++ = '\0';
1243
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001244 if (os_strcmp(cmd, "WPS") == 0)
1245 ndef = 0;
1246 else if (os_strcmp(cmd, "NDEF") == 0)
1247 ndef = 1;
1248 else
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001249 return -1;
1250
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001251 pos2 = os_strchr(pos, ' ');
1252 if (pos2)
1253 *pos2++ = '\0';
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001254 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001255 if (!ndef)
1256 return -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001257 return wpas_ctrl_nfc_get_handover_sel_wps(
1258 wpa_s, reply, max_len, ndef,
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -08001259 os_strcmp(pos, "WPS-CR") == 0, pos2);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001260 }
1261
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001262#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001263 if (os_strcmp(pos, "P2P-CR") == 0) {
1264 return wpas_ctrl_nfc_get_handover_sel_p2p(
1265 wpa_s, reply, max_len, ndef, 0);
1266 }
1267
1268 if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
1269 return wpas_ctrl_nfc_get_handover_sel_p2p(
1270 wpa_s, reply, max_len, ndef, 1);
1271 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001272#endif /* CONFIG_P2P */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001273
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001274 return -1;
1275}
1276
1277
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001278static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
1279 char *cmd)
1280{
1281 size_t len;
1282 struct wpabuf *req, *sel;
1283 int ret;
1284 char *pos, *role, *type, *pos2;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001285#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001286 char *freq;
1287 int forced_freq = 0;
1288
1289 freq = strstr(cmd, " freq=");
1290 if (freq) {
1291 *freq = '\0';
1292 freq += 6;
1293 forced_freq = atoi(freq);
1294 }
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001295#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001296
1297 role = cmd;
1298 pos = os_strchr(role, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001299 if (pos == NULL) {
1300 wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001301 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001302 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001303 *pos++ = '\0';
1304
1305 type = pos;
1306 pos = os_strchr(type, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001307 if (pos == NULL) {
1308 wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001309 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001310 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001311 *pos++ = '\0';
1312
1313 pos2 = os_strchr(pos, ' ');
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001314 if (pos2 == NULL) {
1315 wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001316 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001317 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001318 *pos2++ = '\0';
1319
1320 len = os_strlen(pos);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001321 if (len & 0x01) {
1322 wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001323 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001324 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001325 len /= 2;
1326
1327 req = wpabuf_alloc(len);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001328 if (req == NULL) {
1329 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001330 return -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001331 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001332 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001333 wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001334 wpabuf_free(req);
1335 return -1;
1336 }
1337
1338 len = os_strlen(pos2);
1339 if (len & 0x01) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001340 wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001341 wpabuf_free(req);
1342 return -1;
1343 }
1344 len /= 2;
1345
1346 sel = wpabuf_alloc(len);
1347 if (sel == NULL) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001348 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001349 wpabuf_free(req);
1350 return -1;
1351 }
1352 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001353 wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001354 wpabuf_free(req);
1355 wpabuf_free(sel);
1356 return -1;
1357 }
1358
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001359 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
1360 role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
1361
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001362 if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
1363 ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001364#ifdef CONFIG_AP
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001365 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
1366 {
1367 ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
1368 if (ret < 0)
1369 ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001370#endif /* CONFIG_AP */
1371#ifdef CONFIG_P2P
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001372 } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
1373 {
1374 ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
1375 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
1376 {
1377 ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
1378 forced_freq);
Dmitry Shmidt96be6222014-02-13 10:16:51 -08001379#endif /* CONFIG_P2P */
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001380 } else {
1381 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
1382 "reported: role=%s type=%s", role, type);
1383 ret = -1;
1384 }
1385 wpabuf_free(req);
1386 wpabuf_free(sel);
1387
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001388 if (ret)
1389 wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
1390
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001391 return ret;
1392}
1393
Dmitry Shmidt04949592012-07-19 12:16:46 -07001394#endif /* CONFIG_WPS_NFC */
1395
1396
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001397static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
1398 char *cmd)
1399{
1400 u8 bssid[ETH_ALEN];
1401 char *pin;
1402 char *new_ssid;
1403 char *new_auth;
1404 char *new_encr;
1405 char *new_key;
1406 struct wps_new_ap_settings ap;
1407
1408 pin = os_strchr(cmd, ' ');
1409 if (pin == NULL)
1410 return -1;
1411 *pin++ = '\0';
1412
1413 if (hwaddr_aton(cmd, bssid)) {
1414 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1415 cmd);
1416 return -1;
1417 }
1418
1419 new_ssid = os_strchr(pin, ' ');
1420 if (new_ssid == NULL)
1421 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
1422 *new_ssid++ = '\0';
1423
1424 new_auth = os_strchr(new_ssid, ' ');
1425 if (new_auth == NULL)
1426 return -1;
1427 *new_auth++ = '\0';
1428
1429 new_encr = os_strchr(new_auth, ' ');
1430 if (new_encr == NULL)
1431 return -1;
1432 *new_encr++ = '\0';
1433
1434 new_key = os_strchr(new_encr, ' ');
1435 if (new_key == NULL)
1436 return -1;
1437 *new_key++ = '\0';
1438
1439 os_memset(&ap, 0, sizeof(ap));
1440 ap.ssid_hex = new_ssid;
1441 ap.auth = new_auth;
1442 ap.encr = new_encr;
1443 ap.key_hex = new_key;
1444 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1445}
1446
1447
1448#ifdef CONFIG_AP
1449static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1450 char *cmd, char *buf,
1451 size_t buflen)
1452{
1453 int timeout = 300;
1454 char *pos;
1455 const char *pin_txt;
1456
1457 if (!wpa_s->ap_iface)
1458 return -1;
1459
1460 pos = os_strchr(cmd, ' ');
1461 if (pos)
1462 *pos++ = '\0';
1463
1464 if (os_strcmp(cmd, "disable") == 0) {
1465 wpas_wps_ap_pin_disable(wpa_s);
1466 return os_snprintf(buf, buflen, "OK\n");
1467 }
1468
1469 if (os_strcmp(cmd, "random") == 0) {
1470 if (pos)
1471 timeout = atoi(pos);
1472 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1473 if (pin_txt == NULL)
1474 return -1;
1475 return os_snprintf(buf, buflen, "%s", pin_txt);
1476 }
1477
1478 if (os_strcmp(cmd, "get") == 0) {
1479 pin_txt = wpas_wps_ap_pin_get(wpa_s);
1480 if (pin_txt == NULL)
1481 return -1;
1482 return os_snprintf(buf, buflen, "%s", pin_txt);
1483 }
1484
1485 if (os_strcmp(cmd, "set") == 0) {
1486 char *pin;
1487 if (pos == NULL)
1488 return -1;
1489 pin = pos;
1490 pos = os_strchr(pos, ' ');
1491 if (pos) {
1492 *pos++ = '\0';
1493 timeout = atoi(pos);
1494 }
1495 if (os_strlen(pin) > buflen)
1496 return -1;
1497 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1498 return -1;
1499 return os_snprintf(buf, buflen, "%s", pin);
1500 }
1501
1502 return -1;
1503}
1504#endif /* CONFIG_AP */
1505
1506
1507#ifdef CONFIG_WPS_ER
1508static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1509 char *cmd)
1510{
1511 char *uuid = cmd, *pin, *pos;
1512 u8 addr_buf[ETH_ALEN], *addr = NULL;
1513 pin = os_strchr(uuid, ' ');
1514 if (pin == NULL)
1515 return -1;
1516 *pin++ = '\0';
1517 pos = os_strchr(pin, ' ');
1518 if (pos) {
1519 *pos++ = '\0';
1520 if (hwaddr_aton(pos, addr_buf) == 0)
1521 addr = addr_buf;
1522 }
1523 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1524}
1525
1526
1527static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1528 char *cmd)
1529{
1530 char *uuid = cmd, *pin;
1531 pin = os_strchr(uuid, ' ');
1532 if (pin == NULL)
1533 return -1;
1534 *pin++ = '\0';
1535 return wpas_wps_er_learn(wpa_s, uuid, pin);
1536}
1537
1538
1539static int wpa_supplicant_ctrl_iface_wps_er_set_config(
1540 struct wpa_supplicant *wpa_s, char *cmd)
1541{
1542 char *uuid = cmd, *id;
1543 id = os_strchr(uuid, ' ');
1544 if (id == NULL)
1545 return -1;
1546 *id++ = '\0';
1547 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1548}
1549
1550
1551static int wpa_supplicant_ctrl_iface_wps_er_config(
1552 struct wpa_supplicant *wpa_s, char *cmd)
1553{
1554 char *pin;
1555 char *new_ssid;
1556 char *new_auth;
1557 char *new_encr;
1558 char *new_key;
1559 struct wps_new_ap_settings ap;
1560
1561 pin = os_strchr(cmd, ' ');
1562 if (pin == NULL)
1563 return -1;
1564 *pin++ = '\0';
1565
1566 new_ssid = os_strchr(pin, ' ');
1567 if (new_ssid == NULL)
1568 return -1;
1569 *new_ssid++ = '\0';
1570
1571 new_auth = os_strchr(new_ssid, ' ');
1572 if (new_auth == NULL)
1573 return -1;
1574 *new_auth++ = '\0';
1575
1576 new_encr = os_strchr(new_auth, ' ');
1577 if (new_encr == NULL)
1578 return -1;
1579 *new_encr++ = '\0';
1580
1581 new_key = os_strchr(new_encr, ' ');
1582 if (new_key == NULL)
1583 return -1;
1584 *new_key++ = '\0';
1585
1586 os_memset(&ap, 0, sizeof(ap));
1587 ap.ssid_hex = new_ssid;
1588 ap.auth = new_auth;
1589 ap.encr = new_encr;
1590 ap.key_hex = new_key;
1591 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1592}
Dmitry Shmidt04949592012-07-19 12:16:46 -07001593
1594
1595#ifdef CONFIG_WPS_NFC
1596static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1597 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1598{
1599 int ndef;
1600 struct wpabuf *buf;
1601 int res;
1602 char *uuid;
1603
1604 uuid = os_strchr(cmd, ' ');
1605 if (uuid == NULL)
1606 return -1;
1607 *uuid++ = '\0';
1608
1609 if (os_strcmp(cmd, "WPS") == 0)
1610 ndef = 0;
1611 else if (os_strcmp(cmd, "NDEF") == 0)
1612 ndef = 1;
1613 else
1614 return -1;
1615
1616 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1617 if (buf == NULL)
1618 return -1;
1619
1620 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1621 wpabuf_len(buf));
1622 reply[res++] = '\n';
1623 reply[res] = '\0';
1624
1625 wpabuf_free(buf);
1626
1627 return res;
1628}
1629#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001630#endif /* CONFIG_WPS_ER */
1631
1632#endif /* CONFIG_WPS */
1633
1634
1635#ifdef CONFIG_IBSS_RSN
1636static int wpa_supplicant_ctrl_iface_ibss_rsn(
1637 struct wpa_supplicant *wpa_s, char *addr)
1638{
1639 u8 peer[ETH_ALEN];
1640
1641 if (hwaddr_aton(addr, peer)) {
1642 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1643 "address '%s'", addr);
1644 return -1;
1645 }
1646
1647 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1648 MAC2STR(peer));
1649
1650 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1651}
1652#endif /* CONFIG_IBSS_RSN */
1653
1654
1655static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1656 char *rsp)
1657{
1658#ifdef IEEE8021X_EAPOL
1659 char *pos, *id_pos;
1660 int id;
1661 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001662
1663 pos = os_strchr(rsp, '-');
1664 if (pos == NULL)
1665 return -1;
1666 *pos++ = '\0';
1667 id_pos = pos;
1668 pos = os_strchr(pos, ':');
1669 if (pos == NULL)
1670 return -1;
1671 *pos++ = '\0';
1672 id = atoi(id_pos);
1673 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1674 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1675 (u8 *) pos, os_strlen(pos));
1676
1677 ssid = wpa_config_get_network(wpa_s->conf, id);
1678 if (ssid == NULL) {
1679 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1680 "to update", id);
1681 return -1;
1682 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001683
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001684 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1685 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001686#else /* IEEE8021X_EAPOL */
1687 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1688 return -1;
1689#endif /* IEEE8021X_EAPOL */
1690}
1691
1692
1693static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1694 const char *params,
1695 char *buf, size_t buflen)
1696{
1697 char *pos, *end, tmp[30];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001698 int res, verbose, wps, ret;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001699#ifdef CONFIG_HS20
1700 const u8 *hs20;
1701#endif /* CONFIG_HS20 */
Dmitry Shmidt44da0252011-08-23 12:30:30 -07001702
Dmitry Shmidt56052862013-10-04 10:23:25 -07001703 if (os_strcmp(params, "-DRIVER") == 0)
1704 return wpa_drv_status(wpa_s, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001705 verbose = os_strcmp(params, "-VERBOSE") == 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001706 wps = os_strcmp(params, "-WPS") == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001707 pos = buf;
1708 end = buf + buflen;
1709 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1710 struct wpa_ssid *ssid = wpa_s->current_ssid;
1711 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1712 MAC2STR(wpa_s->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001713 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001714 return pos - buf;
1715 pos += ret;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001716 ret = os_snprintf(pos, end - pos, "freq=%u\n",
1717 wpa_s->assoc_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001718 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001719 return pos - buf;
1720 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001721 if (ssid) {
1722 u8 *_ssid = ssid->ssid;
1723 size_t ssid_len = ssid->ssid_len;
1724 u8 ssid_buf[MAX_SSID_LEN];
1725 if (ssid_len == 0) {
1726 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1727 if (_res < 0)
1728 ssid_len = 0;
1729 else
1730 ssid_len = _res;
1731 _ssid = ssid_buf;
1732 }
1733 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1734 wpa_ssid_txt(_ssid, ssid_len),
1735 ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001736 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001737 return pos - buf;
1738 pos += ret;
1739
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001740 if (wps && ssid->passphrase &&
1741 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1742 (ssid->mode == WPAS_MODE_AP ||
1743 ssid->mode == WPAS_MODE_P2P_GO)) {
1744 ret = os_snprintf(pos, end - pos,
1745 "passphrase=%s\n",
1746 ssid->passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001747 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001748 return pos - buf;
1749 pos += ret;
1750 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001751 if (ssid->id_str) {
1752 ret = os_snprintf(pos, end - pos,
1753 "id_str=%s\n",
1754 ssid->id_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001755 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001756 return pos - buf;
1757 pos += ret;
1758 }
1759
1760 switch (ssid->mode) {
1761 case WPAS_MODE_INFRA:
1762 ret = os_snprintf(pos, end - pos,
1763 "mode=station\n");
1764 break;
1765 case WPAS_MODE_IBSS:
1766 ret = os_snprintf(pos, end - pos,
1767 "mode=IBSS\n");
1768 break;
1769 case WPAS_MODE_AP:
1770 ret = os_snprintf(pos, end - pos,
1771 "mode=AP\n");
1772 break;
1773 case WPAS_MODE_P2P_GO:
1774 ret = os_snprintf(pos, end - pos,
1775 "mode=P2P GO\n");
1776 break;
1777 case WPAS_MODE_P2P_GROUP_FORMATION:
1778 ret = os_snprintf(pos, end - pos,
1779 "mode=P2P GO - group "
1780 "formation\n");
1781 break;
1782 default:
1783 ret = 0;
1784 break;
1785 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001786 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001787 return pos - buf;
1788 pos += ret;
1789 }
1790
1791#ifdef CONFIG_AP
1792 if (wpa_s->ap_iface) {
1793 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1794 end - pos,
1795 verbose);
1796 } else
1797#endif /* CONFIG_AP */
1798 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1799 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001800#ifdef CONFIG_SAE
1801 if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001802#ifdef CONFIG_AP
1803 !wpa_s->ap_iface &&
1804#endif /* CONFIG_AP */
1805 wpa_s->sme.sae.state == SAE_ACCEPTED) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001806 ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
1807 wpa_s->sme.sae.group);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001808 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001809 return pos - buf;
1810 pos += ret;
1811 }
1812#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001813 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1814 wpa_supplicant_state_txt(wpa_s->wpa_state));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001815 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001816 return pos - buf;
1817 pos += ret;
1818
1819 if (wpa_s->l2 &&
1820 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1821 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001822 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001823 return pos - buf;
1824 pos += ret;
1825 }
1826
1827#ifdef CONFIG_P2P
1828 if (wpa_s->global->p2p) {
1829 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1830 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001831 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001832 return pos - buf;
1833 pos += ret;
1834 }
1835#endif /* CONFIG_P2P */
1836
1837 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1838 MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001839 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001840 return pos - buf;
1841 pos += ret;
1842
Dmitry Shmidt04949592012-07-19 12:16:46 -07001843#ifdef CONFIG_HS20
1844 if (wpa_s->current_bss &&
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001845 (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
1846 HS20_IE_VENDOR_TYPE)) &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001847 wpa_s->wpa_proto == WPA_PROTO_RSN &&
1848 wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001849 int release = 1;
1850 if (hs20[1] >= 5) {
1851 u8 rel_num = (hs20[6] & 0xf0) >> 4;
1852 release = rel_num + 1;
1853 }
1854 ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001855 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07001856 return pos - buf;
1857 pos += ret;
1858 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001859
1860 if (wpa_s->current_ssid) {
1861 struct wpa_cred *cred;
1862 char *type;
1863
1864 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07001865 size_t i;
1866
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001867 if (wpa_s->current_ssid->parent_cred != cred)
1868 continue;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001869
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001870 if (cred->provisioning_sp) {
Dmitry Shmidt051af732013-10-22 13:52:46 -07001871 ret = os_snprintf(pos, end - pos,
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001872 "provisioning_sp=%s\n",
1873 cred->provisioning_sp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001874 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt051af732013-10-22 13:52:46 -07001875 return pos - buf;
1876 pos += ret;
1877 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001878
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001879 if (!cred->domain)
1880 goto no_domain;
1881
1882 i = 0;
1883 if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
1884 struct wpabuf *names =
1885 wpa_s->current_bss->anqp->domain_name;
1886 for (i = 0; names && i < cred->num_domain; i++)
1887 {
1888 if (domain_name_list_contains(
1889 names, cred->domain[i], 1))
1890 break;
1891 }
1892 if (i == cred->num_domain)
1893 i = 0; /* show first entry by default */
1894 }
1895 ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
1896 cred->domain[i]);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001897 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001898 return pos - buf;
1899 pos += ret;
1900
1901 no_domain:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001902 if (wpa_s->current_bss == NULL ||
1903 wpa_s->current_bss->anqp == NULL)
1904 res = -1;
1905 else
1906 res = interworking_home_sp_cred(
1907 wpa_s, cred,
1908 wpa_s->current_bss->anqp->domain_name);
1909 if (res > 0)
1910 type = "home";
1911 else if (res == 0)
1912 type = "roaming";
1913 else
1914 type = "unknown";
1915
1916 ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001917 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001918 return pos - buf;
1919 pos += ret;
1920
1921 break;
1922 }
1923 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001924#endif /* CONFIG_HS20 */
1925
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001926 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
1927 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1928 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
1929 verbose);
1930 if (res >= 0)
1931 pos += res;
1932 }
1933
1934 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
1935 if (res >= 0)
1936 pos += res;
1937
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001938#ifdef CONFIG_WPS
1939 {
1940 char uuid_str[100];
1941 uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
1942 ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001943 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001944 return pos - buf;
1945 pos += ret;
1946 }
1947#endif /* CONFIG_WPS */
1948
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001949#ifdef ANDROID
vandwalleffc70182014-09-11 11:40:14 -07001950 /*
1951 * Allow using the STATUS command with default behavior, say for debug,
1952 * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
1953 * events with STATUS-NO_EVENTS.
1954 */
1955 if (os_strcmp(params, "-NO_EVENTS")) {
1956 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
1957 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
1958 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
1959 wpa_s->wpa_state,
1960 MAC2STR(wpa_s->bssid),
1961 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
1962 wpa_ssid_txt(wpa_s->current_ssid->ssid,
1963 wpa_s->current_ssid->ssid_len) : "");
1964 if (wpa_s->wpa_state == WPA_COMPLETED) {
1965 struct wpa_ssid *ssid = wpa_s->current_ssid;
1966 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
1967 "- connection to " MACSTR
1968 " completed %s [id=%d id_str=%s]",
1969 MAC2STR(wpa_s->bssid), "(auth)",
1970 ssid ? ssid->id : -1,
1971 ssid && ssid->id_str ? ssid->id_str : "");
1972 }
Irfan Sheriffbf5edf42012-01-11 16:54:57 -08001973 }
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001974#endif /* ANDROID */
1975
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001976 return pos - buf;
1977}
1978
1979
1980static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
1981 char *cmd)
1982{
1983 char *pos;
1984 int id;
1985 struct wpa_ssid *ssid;
1986 u8 bssid[ETH_ALEN];
1987
1988 /* cmd: "<network id> <BSSID>" */
1989 pos = os_strchr(cmd, ' ');
1990 if (pos == NULL)
1991 return -1;
1992 *pos++ = '\0';
1993 id = atoi(cmd);
1994 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
1995 if (hwaddr_aton(pos, bssid)) {
1996 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
1997 return -1;
1998 }
1999
2000 ssid = wpa_config_get_network(wpa_s->conf, id);
2001 if (ssid == NULL) {
2002 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2003 "to update", id);
2004 return -1;
2005 }
2006
2007 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
2008 ssid->bssid_set = !is_zero_ether_addr(bssid);
2009
2010 return 0;
2011}
2012
2013
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002014static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002015 char *cmd, char *buf,
2016 size_t buflen)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002017{
2018 u8 bssid[ETH_ALEN];
2019 struct wpa_blacklist *e;
2020 char *pos, *end;
2021 int ret;
2022
2023 /* cmd: "BLACKLIST [<BSSID>]" */
2024 if (*cmd == '\0') {
2025 pos = buf;
2026 end = buf + buflen;
2027 e = wpa_s->blacklist;
2028 while (e) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002029 ret = os_snprintf(pos, end - pos, MACSTR "\n",
2030 MAC2STR(e->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002031 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002032 return pos - buf;
2033 pos += ret;
2034 e = e->next;
2035 }
2036 return pos - buf;
2037 }
2038
2039 cmd++;
2040 if (os_strncmp(cmd, "clear", 5) == 0) {
2041 wpa_blacklist_clear(wpa_s);
2042 os_memcpy(buf, "OK\n", 3);
2043 return 3;
2044 }
2045
2046 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
2047 if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002048 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002049 return -1;
2050 }
2051
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002052 /*
2053 * Add the BSSID twice, so its count will be 2, causing it to be
2054 * skipped when processing scan results.
2055 */
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002056 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002057 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002058 return -1;
2059 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07002060 if (ret < 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07002061 return -1;
2062 os_memcpy(buf, "OK\n", 3);
2063 return 3;
2064}
2065
2066
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002067static const char * debug_level_str(int level)
2068{
2069 switch (level) {
2070 case MSG_EXCESSIVE:
2071 return "EXCESSIVE";
2072 case MSG_MSGDUMP:
2073 return "MSGDUMP";
2074 case MSG_DEBUG:
2075 return "DEBUG";
2076 case MSG_INFO:
2077 return "INFO";
2078 case MSG_WARNING:
2079 return "WARNING";
2080 case MSG_ERROR:
2081 return "ERROR";
2082 default:
2083 return "?";
2084 }
2085}
2086
2087
2088static int str_to_debug_level(const char *s)
2089{
2090 if (os_strcasecmp(s, "EXCESSIVE") == 0)
2091 return MSG_EXCESSIVE;
2092 if (os_strcasecmp(s, "MSGDUMP") == 0)
2093 return MSG_MSGDUMP;
2094 if (os_strcasecmp(s, "DEBUG") == 0)
2095 return MSG_DEBUG;
2096 if (os_strcasecmp(s, "INFO") == 0)
2097 return MSG_INFO;
2098 if (os_strcasecmp(s, "WARNING") == 0)
2099 return MSG_WARNING;
2100 if (os_strcasecmp(s, "ERROR") == 0)
2101 return MSG_ERROR;
2102 return -1;
2103}
2104
2105
2106static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
2107 char *cmd, char *buf,
2108 size_t buflen)
2109{
2110 char *pos, *end, *stamp;
2111 int ret;
2112
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002113 /* cmd: "LOG_LEVEL [<level>]" */
2114 if (*cmd == '\0') {
2115 pos = buf;
2116 end = buf + buflen;
2117 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2118 "Timestamp: %d\n",
2119 debug_level_str(wpa_debug_level),
2120 wpa_debug_timestamp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002121 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002122 ret = 0;
2123
2124 return ret;
2125 }
2126
2127 while (*cmd == ' ')
2128 cmd++;
2129
2130 stamp = os_strchr(cmd, ' ');
2131 if (stamp) {
2132 *stamp++ = '\0';
2133 while (*stamp == ' ') {
2134 stamp++;
2135 }
2136 }
2137
2138 if (cmd && os_strlen(cmd)) {
2139 int level = str_to_debug_level(cmd);
2140 if (level < 0)
2141 return -1;
2142 wpa_debug_level = level;
2143 }
2144
2145 if (stamp && os_strlen(stamp))
2146 wpa_debug_timestamp = atoi(stamp);
2147
2148 os_memcpy(buf, "OK\n", 3);
2149 return 3;
2150}
2151
2152
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002153static int wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002154 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002155{
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002156 char *pos, *end, *prev;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002157 struct wpa_ssid *ssid;
2158 int ret;
2159
2160 pos = buf;
2161 end = buf + buflen;
2162 ret = os_snprintf(pos, end - pos,
2163 "network id / ssid / bssid / flags\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002164 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002165 return pos - buf;
2166 pos += ret;
2167
2168 ssid = wpa_s->conf->ssid;
Vinit Deshpandeda134e92014-12-02 10:59:29 -08002169
2170 /* skip over ssids until we find next one */
2171 if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
2172 int last_id = atoi(cmd + 8);
2173 if (last_id != -1) {
2174 while (ssid != NULL && ssid->id <= last_id) {
2175 ssid = ssid->next;
2176 }
2177 }
2178 }
2179
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002180 while (ssid) {
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002181 prev = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002182 ret = os_snprintf(pos, end - pos, "%d\t%s",
2183 ssid->id,
2184 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002185 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002186 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002187 pos += ret;
2188 if (ssid->bssid_set) {
2189 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
2190 MAC2STR(ssid->bssid));
2191 } else {
2192 ret = os_snprintf(pos, end - pos, "\tany");
2193 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002194 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002195 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002196 pos += ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002197 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002198 ssid == wpa_s->current_ssid ?
2199 "[CURRENT]" : "",
2200 ssid->disabled ? "[DISABLED]" : "",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002201 ssid->disabled_until.sec ?
2202 "[TEMP-DISABLED]" : "",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002203 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
2204 "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002205 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002206 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002207 pos += ret;
2208 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002209 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt9e37fc22014-12-03 11:48:46 -08002210 return prev - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002211 pos += ret;
2212
2213 ssid = ssid->next;
2214 }
2215
2216 return pos - buf;
2217}
2218
2219
2220static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
2221{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002222 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002223 ret = os_snprintf(pos, end - pos, "-");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002224 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002225 return pos;
2226 pos += ret;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002227 ret = wpa_write_ciphers(pos, end, cipher, "+");
2228 if (ret < 0)
2229 return pos;
2230 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002231 return pos;
2232}
2233
2234
2235static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
2236 const u8 *ie, size_t ie_len)
2237{
2238 struct wpa_ie_data data;
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002239 char *start;
2240 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002241
2242 ret = os_snprintf(pos, end - pos, "[%s-", proto);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002243 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002244 return pos;
2245 pos += ret;
2246
2247 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
2248 ret = os_snprintf(pos, end - pos, "?]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002249 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002250 return pos;
2251 pos += ret;
2252 return pos;
2253 }
2254
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002255 start = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002256 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002257 ret = os_snprintf(pos, end - pos, "%sEAP",
2258 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002259 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002260 return pos;
2261 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002262 }
2263 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002264 ret = os_snprintf(pos, end - pos, "%sPSK",
2265 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002266 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002267 return pos;
2268 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002269 }
2270 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002271 ret = os_snprintf(pos, end - pos, "%sNone",
2272 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002273 if (os_snprintf_error(end - pos, ret))
2274 return pos;
2275 pos += ret;
2276 }
2277 if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
2278 ret = os_snprintf(pos, end - pos, "%sSAE",
2279 pos == start ? "" : "+");
2280 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002281 return pos;
2282 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002283 }
2284#ifdef CONFIG_IEEE80211R
2285 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
2286 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002287 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002288 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002289 return pos;
2290 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291 }
2292 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
2293 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002294 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002295 if (os_snprintf_error(end - pos, ret))
2296 return pos;
2297 pos += ret;
2298 }
2299 if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
2300 ret = os_snprintf(pos, end - pos, "%sFT/SAE",
2301 pos == start ? "" : "+");
2302 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002303 return pos;
2304 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002305 }
2306#endif /* CONFIG_IEEE80211R */
2307#ifdef CONFIG_IEEE80211W
2308 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2309 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002310 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002311 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002312 return pos;
2313 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002314 }
2315 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
2316 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002317 pos == start ? "" : "+");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002318 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002319 return pos;
2320 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002321 }
2322#endif /* CONFIG_IEEE80211W */
2323
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002324 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2325 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
2326 pos == start ? "" : "+");
2327 if (os_snprintf_error(end - pos, ret))
2328 return pos;
2329 pos += ret;
2330 }
2331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002332 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
2333
2334 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
2335 ret = os_snprintf(pos, end - pos, "-preauth");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002336 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002337 return pos;
2338 pos += ret;
2339 }
2340
2341 ret = os_snprintf(pos, end - pos, "]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002342 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002343 return pos;
2344 pos += ret;
2345
2346 return pos;
2347}
2348
2349
2350#ifdef CONFIG_WPS
2351static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
2352 char *pos, char *end,
2353 struct wpabuf *wps_ie)
2354{
2355 int ret;
2356 const char *txt;
2357
2358 if (wps_ie == NULL)
2359 return pos;
2360 if (wps_is_selected_pbc_registrar(wps_ie))
2361 txt = "[WPS-PBC]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002362 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
2363 txt = "[WPS-AUTH]";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002364 else if (wps_is_selected_pin_registrar(wps_ie))
2365 txt = "[WPS-PIN]";
2366 else
2367 txt = "[WPS]";
2368
2369 ret = os_snprintf(pos, end - pos, "%s", txt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002370 if (!os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002371 pos += ret;
2372 wpabuf_free(wps_ie);
2373 return pos;
2374}
2375#endif /* CONFIG_WPS */
2376
2377
2378static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
2379 char *pos, char *end,
2380 const struct wpa_bss *bss)
2381{
2382#ifdef CONFIG_WPS
2383 struct wpabuf *wps_ie;
2384 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
2385 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
2386#else /* CONFIG_WPS */
2387 return pos;
2388#endif /* CONFIG_WPS */
2389}
2390
2391
2392/* Format one result on one text line into a buffer. */
2393static int wpa_supplicant_ctrl_iface_scan_result(
2394 struct wpa_supplicant *wpa_s,
2395 const struct wpa_bss *bss, char *buf, size_t buflen)
2396{
2397 char *pos, *end;
2398 int ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002399 const u8 *ie, *ie2, *p2p, *mesh;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002400
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002401 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt96571392013-10-14 12:54:46 -07002403 if (!p2p)
2404 p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002405 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
2406 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
2407 0)
2408 return 0; /* Do not show P2P listen discovery results here */
2409
2410 pos = buf;
2411 end = buf + buflen;
2412
2413 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
2414 MAC2STR(bss->bssid), bss->freq, bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002415 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002416 return -1;
2417 pos += ret;
2418 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2419 if (ie)
2420 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
2421 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002422 if (ie2) {
2423 pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
2424 ie2, 2 + ie2[1]);
2425 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
2427 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
2428 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002429 if (os_snprintf_error(end - pos, ret))
2430 return -1;
2431 pos += ret;
2432 }
2433 if (mesh) {
2434 ret = os_snprintf(pos, end - pos, "[MESH]");
2435 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002436 return -1;
2437 pos += ret;
2438 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002439 if (bss_is_dmg(bss)) {
2440 const char *s;
2441 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002442 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002443 return -1;
2444 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002445 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
2446 case IEEE80211_CAP_DMG_IBSS:
2447 s = "[IBSS]";
2448 break;
2449 case IEEE80211_CAP_DMG_AP:
2450 s = "[ESS]";
2451 break;
2452 case IEEE80211_CAP_DMG_PBSS:
2453 s = "[PBSS]";
2454 break;
2455 default:
2456 s = "";
2457 break;
2458 }
2459 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002460 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002461 return -1;
2462 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002463 } else {
2464 if (bss->caps & IEEE80211_CAP_IBSS) {
2465 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002466 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002467 return -1;
2468 pos += ret;
2469 }
2470 if (bss->caps & IEEE80211_CAP_ESS) {
2471 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002472 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07002473 return -1;
2474 pos += ret;
2475 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002476 }
2477 if (p2p) {
2478 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002479 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002480 return -1;
2481 pos += ret;
2482 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002483#ifdef CONFIG_HS20
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002484 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002485 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002486 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07002487 return -1;
2488 pos += ret;
2489 }
2490#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002491
2492 ret = os_snprintf(pos, end - pos, "\t%s",
2493 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002494 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002495 return -1;
2496 pos += ret;
2497
2498 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002499 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002500 return -1;
2501 pos += ret;
2502
2503 return pos - buf;
2504}
2505
2506
2507static int wpa_supplicant_ctrl_iface_scan_results(
2508 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2509{
2510 char *pos, *end;
2511 struct wpa_bss *bss;
2512 int ret;
2513
2514 pos = buf;
2515 end = buf + buflen;
2516 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
2517 "flags / ssid\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002518 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002519 return pos - buf;
2520 pos += ret;
2521
2522 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2523 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
2524 end - pos);
2525 if (ret < 0 || ret >= end - pos)
2526 return pos - buf;
2527 pos += ret;
2528 }
2529
2530 return pos - buf;
2531}
2532
2533
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002534#ifdef CONFIG_MESH
2535
2536static int wpa_supplicant_ctrl_iface_mesh_interface_add(
2537 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
2538{
2539 char *pos, ifname[IFNAMSIZ + 1];
2540
2541 ifname[0] = '\0';
2542
2543 pos = os_strstr(cmd, "ifname=");
2544 if (pos) {
2545 pos += 7;
2546 os_strlcpy(ifname, pos, sizeof(ifname));
2547 }
2548
2549 if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
2550 return -1;
2551
2552 os_strlcpy(reply, ifname, max_len);
2553 return os_strlen(ifname);
2554}
2555
2556
2557static int wpa_supplicant_ctrl_iface_mesh_group_add(
2558 struct wpa_supplicant *wpa_s, char *cmd)
2559{
2560 int id;
2561 struct wpa_ssid *ssid;
2562
2563 id = atoi(cmd);
2564 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
2565
2566 ssid = wpa_config_get_network(wpa_s->conf, id);
2567 if (ssid == NULL) {
2568 wpa_printf(MSG_DEBUG,
2569 "CTRL_IFACE: Could not find network id=%d", id);
2570 return -1;
2571 }
2572 if (ssid->mode != WPAS_MODE_MESH) {
2573 wpa_printf(MSG_DEBUG,
2574 "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
2575 return -1;
2576 }
2577 if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
2578 ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
2579 wpa_printf(MSG_ERROR,
2580 "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
2581 return -1;
2582 }
2583
2584 /*
2585 * TODO: If necessary write our own group_add function,
2586 * for now we can reuse select_network
2587 */
2588 wpa_supplicant_select_network(wpa_s, ssid);
2589
2590 return 0;
2591}
2592
2593
2594static int wpa_supplicant_ctrl_iface_mesh_group_remove(
2595 struct wpa_supplicant *wpa_s, char *cmd)
2596{
2597 struct wpa_supplicant *orig;
2598 struct wpa_global *global;
2599 int found = 0;
2600
2601 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
2602
2603 global = wpa_s->global;
2604 orig = wpa_s;
2605
2606 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2607 if (os_strcmp(wpa_s->ifname, cmd) == 0) {
2608 found = 1;
2609 break;
2610 }
2611 }
2612 if (!found) {
2613 wpa_printf(MSG_ERROR,
2614 "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
2615 cmd);
2616 return -1;
2617 }
2618 if (wpa_s->mesh_if_created && wpa_s == orig) {
2619 wpa_printf(MSG_ERROR,
2620 "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
2621 return -1;
2622 }
2623
2624 wpa_s->reassociate = 0;
2625 wpa_s->disconnected = 1;
2626 wpa_supplicant_cancel_sched_scan(wpa_s);
2627 wpa_supplicant_cancel_scan(wpa_s);
2628
2629 /*
2630 * TODO: If necessary write our own group_remove function,
2631 * for now we can reuse deauthenticate
2632 */
2633 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2634
2635 if (wpa_s->mesh_if_created)
2636 wpa_supplicant_remove_iface(global, wpa_s, 0);
2637
2638 return 0;
2639}
2640
2641#endif /* CONFIG_MESH */
2642
2643
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002644static int wpa_supplicant_ctrl_iface_select_network(
2645 struct wpa_supplicant *wpa_s, char *cmd)
2646{
2647 int id;
2648 struct wpa_ssid *ssid;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002649 char *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002650
2651 /* cmd: "<network id>" or "any" */
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002652 if (os_strncmp(cmd, "any", 3) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002653 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
2654 ssid = NULL;
2655 } else {
2656 id = atoi(cmd);
2657 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
2658
2659 ssid = wpa_config_get_network(wpa_s->conf, id);
2660 if (ssid == NULL) {
2661 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2662 "network id=%d", id);
2663 return -1;
2664 }
2665 if (ssid->disabled == 2) {
2666 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2667 "SELECT_NETWORK with persistent P2P group");
2668 return -1;
2669 }
2670 }
2671
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07002672 pos = os_strstr(cmd, " freq=");
2673 if (pos) {
2674 int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
2675 if (freqs) {
2676 wpa_s->scan_req = MANUAL_SCAN_REQ;
2677 os_free(wpa_s->manual_scan_freqs);
2678 wpa_s->manual_scan_freqs = freqs;
2679 }
2680 }
2681
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002682 wpa_supplicant_select_network(wpa_s, ssid);
2683
2684 return 0;
2685}
2686
2687
2688static int wpa_supplicant_ctrl_iface_enable_network(
2689 struct wpa_supplicant *wpa_s, char *cmd)
2690{
2691 int id;
2692 struct wpa_ssid *ssid;
2693
2694 /* cmd: "<network id>" or "all" */
2695 if (os_strcmp(cmd, "all") == 0) {
2696 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
2697 ssid = NULL;
2698 } else {
2699 id = atoi(cmd);
2700 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
2701
2702 ssid = wpa_config_get_network(wpa_s->conf, id);
2703 if (ssid == NULL) {
2704 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2705 "network id=%d", id);
2706 return -1;
2707 }
2708 if (ssid->disabled == 2) {
2709 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2710 "ENABLE_NETWORK with persistent P2P group");
2711 return -1;
2712 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002713
2714 if (os_strstr(cmd, " no-connect")) {
2715 ssid->disabled = 0;
2716 return 0;
2717 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002718 }
2719 wpa_supplicant_enable_network(wpa_s, ssid);
2720
2721 return 0;
2722}
2723
2724
2725static int wpa_supplicant_ctrl_iface_disable_network(
2726 struct wpa_supplicant *wpa_s, char *cmd)
2727{
2728 int id;
2729 struct wpa_ssid *ssid;
2730
2731 /* cmd: "<network id>" or "all" */
2732 if (os_strcmp(cmd, "all") == 0) {
2733 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
2734 ssid = NULL;
2735 } else {
2736 id = atoi(cmd);
2737 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
2738
2739 ssid = wpa_config_get_network(wpa_s->conf, id);
2740 if (ssid == NULL) {
2741 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2742 "network id=%d", id);
2743 return -1;
2744 }
2745 if (ssid->disabled == 2) {
2746 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2747 "DISABLE_NETWORK with persistent P2P "
2748 "group");
2749 return -1;
2750 }
2751 }
2752 wpa_supplicant_disable_network(wpa_s, ssid);
2753
2754 return 0;
2755}
2756
2757
2758static int wpa_supplicant_ctrl_iface_add_network(
2759 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2760{
2761 struct wpa_ssid *ssid;
2762 int ret;
2763
2764 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
2765
2766 ssid = wpa_config_add_network(wpa_s->conf);
2767 if (ssid == NULL)
2768 return -1;
2769
2770 wpas_notify_network_added(wpa_s, ssid);
2771
2772 ssid->disabled = 1;
2773 wpa_config_set_network_defaults(ssid);
2774
2775 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002776 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002777 return -1;
2778 return ret;
2779}
2780
2781
2782static int wpa_supplicant_ctrl_iface_remove_network(
2783 struct wpa_supplicant *wpa_s, char *cmd)
2784{
2785 int id;
2786 struct wpa_ssid *ssid;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002787 int was_disabled;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002788
2789 /* cmd: "<network id>" or "all" */
2790 if (os_strcmp(cmd, "all") == 0) {
2791 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002792 if (wpa_s->sched_scanning)
2793 wpa_supplicant_cancel_sched_scan(wpa_s);
2794
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002795 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002796 if (wpa_s->current_ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002797#ifdef CONFIG_SME
2798 wpa_s->sme.prev_bssid_set = 0;
2799#endif /* CONFIG_SME */
Jouni Malinen75ecf522011-06-27 15:19:46 -07002800 wpa_sm_set_config(wpa_s->wpa, NULL);
2801 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002802 wpa_supplicant_deauthenticate(
2803 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002804 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002805 ssid = wpa_s->conf->ssid;
2806 while (ssid) {
2807 struct wpa_ssid *remove_ssid = ssid;
2808 id = ssid->id;
2809 ssid = ssid->next;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002810 if (wpa_s->last_ssid == remove_ssid)
2811 wpa_s->last_ssid = NULL;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002812 wpas_notify_network_removed(wpa_s, remove_ssid);
2813 wpa_config_remove_network(wpa_s->conf, id);
2814 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002815 return 0;
2816 }
2817
2818 id = atoi(cmd);
2819 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
2820
2821 ssid = wpa_config_get_network(wpa_s->conf, id);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002822 if (ssid)
2823 wpas_notify_network_removed(wpa_s, ssid);
Deepthi Gowria831d782012-09-03 11:55:38 +03002824 if (ssid == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002825 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2826 "id=%d", id);
2827 return -1;
2828 }
2829
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002830 if (wpa_s->last_ssid == ssid)
2831 wpa_s->last_ssid = NULL;
2832
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002833 if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002834#ifdef CONFIG_SME
2835 wpa_s->sme.prev_bssid_set = 0;
2836#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002837 /*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002838 * Invalidate the EAP session cache if the current or
2839 * previously used network is removed.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002840 */
2841 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002842 }
2843
2844 if (ssid == wpa_s->current_ssid) {
Jouni Malinen75ecf522011-06-27 15:19:46 -07002845 wpa_sm_set_config(wpa_s->wpa, NULL);
2846 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002847
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002848 wpa_supplicant_deauthenticate(wpa_s,
2849 WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002850 }
2851
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002852 was_disabled = ssid->disabled;
2853
Deepthi Gowria831d782012-09-03 11:55:38 +03002854 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
2855 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
2856 "network id=%d", id);
2857 return -1;
2858 }
2859
Dmitry Shmidt2f023192013-03-12 12:44:17 -07002860 if (!was_disabled && wpa_s->sched_scanning) {
2861 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
2862 "network from filters");
2863 wpa_supplicant_cancel_sched_scan(wpa_s);
2864 wpa_supplicant_req_scan(wpa_s, 0, 0);
2865 }
2866
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002867 return 0;
2868}
2869
2870
Dmitry Shmidt684785c2014-05-12 13:34:29 -07002871static int wpa_supplicant_ctrl_iface_update_network(
2872 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
2873 char *name, char *value)
2874{
2875 if (wpa_config_set(ssid, name, value, 0) < 0) {
2876 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
2877 "variable '%s'", name);
2878 return -1;
2879 }
2880
2881 if (os_strcmp(name, "bssid") != 0 &&
2882 os_strcmp(name, "priority") != 0)
2883 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
2884
2885 if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
2886 /*
2887 * Invalidate the EAP session cache if anything in the current
2888 * or previously used configuration changes.
2889 */
2890 eapol_sm_invalidate_cached_session(wpa_s->eapol);
2891 }
2892
2893 if ((os_strcmp(name, "psk") == 0 &&
2894 value[0] == '"' && ssid->ssid_len) ||
2895 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
2896 wpa_config_update_psk(ssid);
2897 else if (os_strcmp(name, "priority") == 0)
2898 wpa_config_update_prio_list(wpa_s->conf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002899 else if (os_strcmp(name, "no_auto_peer") == 0)
2900 ssid->no_auto_peer = atoi(value);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07002901
2902 return 0;
2903}
2904
2905
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002906static int wpa_supplicant_ctrl_iface_set_network(
2907 struct wpa_supplicant *wpa_s, char *cmd)
2908{
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002909 int id, ret, prev_bssid_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910 struct wpa_ssid *ssid;
2911 char *name, *value;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002912 u8 prev_bssid[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002913
2914 /* cmd: "<network id> <variable name> <value>" */
2915 name = os_strchr(cmd, ' ');
2916 if (name == NULL)
2917 return -1;
2918 *name++ = '\0';
2919
2920 value = os_strchr(name, ' ');
2921 if (value == NULL)
2922 return -1;
2923 *value++ = '\0';
2924
2925 id = atoi(cmd);
2926 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
2927 id, name);
2928 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2929 (u8 *) value, os_strlen(value));
2930
2931 ssid = wpa_config_get_network(wpa_s->conf, id);
2932 if (ssid == NULL) {
2933 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2934 "id=%d", id);
2935 return -1;
2936 }
2937
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002938 prev_bssid_set = ssid->bssid_set;
2939 os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
2940 ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
2941 value);
2942 if (ret == 0 &&
2943 (ssid->bssid_set != prev_bssid_set ||
2944 os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
2945 wpas_notify_network_bssid_set_changed(wpa_s, ssid);
2946 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002947}
2948
2949
2950static int wpa_supplicant_ctrl_iface_get_network(
2951 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
2952{
2953 int id;
2954 size_t res;
2955 struct wpa_ssid *ssid;
2956 char *name, *value;
2957
2958 /* cmd: "<network id> <variable name>" */
2959 name = os_strchr(cmd, ' ');
2960 if (name == NULL || buflen == 0)
2961 return -1;
2962 *name++ = '\0';
2963
2964 id = atoi(cmd);
2965 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
2966 id, name);
2967
2968 ssid = wpa_config_get_network(wpa_s->conf, id);
2969 if (ssid == NULL) {
2970 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2971 "id=%d", id);
2972 return -1;
2973 }
2974
2975 value = wpa_config_get_no_key(ssid, name);
2976 if (value == NULL) {
2977 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
2978 "variable '%s'", name);
2979 return -1;
2980 }
2981
2982 res = os_strlcpy(buf, value, buflen);
2983 if (res >= buflen) {
2984 os_free(value);
2985 return -1;
2986 }
2987
2988 os_free(value);
2989
2990 return res;
2991}
2992
2993
Dmitry Shmidt684785c2014-05-12 13:34:29 -07002994static int wpa_supplicant_ctrl_iface_dup_network(
2995 struct wpa_supplicant *wpa_s, char *cmd)
2996{
2997 struct wpa_ssid *ssid_s, *ssid_d;
2998 char *name, *id, *value;
2999 int id_s, id_d, ret;
3000
3001 /* cmd: "<src network id> <dst network id> <variable name>" */
3002 id = os_strchr(cmd, ' ');
3003 if (id == NULL)
3004 return -1;
3005 *id++ = '\0';
3006
3007 name = os_strchr(id, ' ');
3008 if (name == NULL)
3009 return -1;
3010 *name++ = '\0';
3011
3012 id_s = atoi(cmd);
3013 id_d = atoi(id);
3014 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'",
3015 id_s, id_d, name);
3016
3017 ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
3018 if (ssid_s == NULL) {
3019 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3020 "network id=%d", id_s);
3021 return -1;
3022 }
3023
3024 ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
3025 if (ssid_d == NULL) {
3026 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003027 "network id=%d", id_d);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07003028 return -1;
3029 }
3030
3031 value = wpa_config_get(ssid_s, name);
3032 if (value == NULL) {
3033 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
3034 "variable '%s'", name);
3035 return -1;
3036 }
3037
3038 ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name,
3039 value);
3040
3041 os_free(value);
3042
3043 return ret;
3044}
3045
3046
Dmitry Shmidt04949592012-07-19 12:16:46 -07003047static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
3048 char *buf, size_t buflen)
3049{
3050 char *pos, *end;
3051 struct wpa_cred *cred;
3052 int ret;
3053
3054 pos = buf;
3055 end = buf + buflen;
3056 ret = os_snprintf(pos, end - pos,
3057 "cred id / realm / username / domain / imsi\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003058 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003059 return pos - buf;
3060 pos += ret;
3061
3062 cred = wpa_s->conf->cred;
3063 while (cred) {
3064 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
3065 cred->id, cred->realm ? cred->realm : "",
3066 cred->username ? cred->username : "",
Dmitry Shmidt051af732013-10-22 13:52:46 -07003067 cred->domain ? cred->domain[0] : "",
Dmitry Shmidt04949592012-07-19 12:16:46 -07003068 cred->imsi ? cred->imsi : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003069 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003070 return pos - buf;
3071 pos += ret;
3072
3073 cred = cred->next;
3074 }
3075
3076 return pos - buf;
3077}
3078
3079
3080static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
3081 char *buf, size_t buflen)
3082{
3083 struct wpa_cred *cred;
3084 int ret;
3085
3086 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
3087
3088 cred = wpa_config_add_cred(wpa_s->conf);
3089 if (cred == NULL)
3090 return -1;
3091
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003092 wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
3093
Dmitry Shmidt04949592012-07-19 12:16:46 -07003094 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003095 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt04949592012-07-19 12:16:46 -07003096 return -1;
3097 return ret;
3098}
3099
3100
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003101static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
3102 struct wpa_cred *cred)
3103{
3104 struct wpa_ssid *ssid;
3105 char str[20];
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003106 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003107
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003108 if (cred == NULL) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003109 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3110 return -1;
3111 }
3112
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003113 id = cred->id;
3114 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
3115 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3116 return -1;
3117 }
3118
3119 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
3120
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003121 /* Remove any network entry created based on the removed credential */
3122 ssid = wpa_s->conf->ssid;
3123 while (ssid) {
3124 if (ssid->parent_cred == cred) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003125 int res;
3126
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003127 wpa_printf(MSG_DEBUG, "Remove network id %d since it "
3128 "used the removed credential", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003129 res = os_snprintf(str, sizeof(str), "%d", ssid->id);
3130 if (os_snprintf_error(sizeof(str), res))
3131 str[sizeof(str) - 1] = '\0';
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003132 ssid = ssid->next;
3133 wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
3134 } else
3135 ssid = ssid->next;
3136 }
3137
3138 return 0;
3139}
3140
3141
Dmitry Shmidt04949592012-07-19 12:16:46 -07003142static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
3143 char *cmd)
3144{
3145 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003146 struct wpa_cred *cred, *prev;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003147
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003148 /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
3149 * "provisioning_sp=<FQDN> */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003150 if (os_strcmp(cmd, "all") == 0) {
3151 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
3152 cred = wpa_s->conf->cred;
3153 while (cred) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003154 prev = cred;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003155 cred = cred->next;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003156 wpas_ctrl_remove_cred(wpa_s, prev);
3157 }
3158 return 0;
3159 }
3160
3161 if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
3162 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
3163 cmd + 8);
3164 cred = wpa_s->conf->cred;
3165 while (cred) {
3166 prev = cred;
3167 cred = cred->next;
Dmitry Shmidt051af732013-10-22 13:52:46 -07003168 if (prev->domain) {
3169 size_t i;
3170 for (i = 0; i < prev->num_domain; i++) {
3171 if (os_strcmp(prev->domain[i], cmd + 8)
3172 != 0)
3173 continue;
3174 wpas_ctrl_remove_cred(wpa_s, prev);
3175 break;
3176 }
3177 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003178 }
3179 return 0;
3180 }
3181
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003182 if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
3183 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
3184 cmd + 16);
3185 cred = wpa_s->conf->cred;
3186 while (cred) {
3187 prev = cred;
3188 cred = cred->next;
3189 if (prev->provisioning_sp &&
3190 os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
3191 wpas_ctrl_remove_cred(wpa_s, prev);
3192 }
3193 return 0;
3194 }
3195
Dmitry Shmidt04949592012-07-19 12:16:46 -07003196 id = atoi(cmd);
3197 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
3198
3199 cred = wpa_config_get_cred(wpa_s->conf, id);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003200 return wpas_ctrl_remove_cred(wpa_s, cred);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003201}
3202
3203
3204static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
3205 char *cmd)
3206{
3207 int id;
3208 struct wpa_cred *cred;
3209 char *name, *value;
3210
3211 /* cmd: "<cred id> <variable name> <value>" */
3212 name = os_strchr(cmd, ' ');
3213 if (name == NULL)
3214 return -1;
3215 *name++ = '\0';
3216
3217 value = os_strchr(name, ' ');
3218 if (value == NULL)
3219 return -1;
3220 *value++ = '\0';
3221
3222 id = atoi(cmd);
3223 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
3224 id, name);
3225 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3226 (u8 *) value, os_strlen(value));
3227
3228 cred = wpa_config_get_cred(wpa_s->conf, id);
3229 if (cred == NULL) {
3230 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3231 id);
3232 return -1;
3233 }
3234
3235 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
3236 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
3237 "variable '%s'", name);
3238 return -1;
3239 }
3240
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003241 wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
3242
Dmitry Shmidt04949592012-07-19 12:16:46 -07003243 return 0;
3244}
3245
3246
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07003247static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
3248 char *cmd, char *buf,
3249 size_t buflen)
3250{
3251 int id;
3252 size_t res;
3253 struct wpa_cred *cred;
3254 char *name, *value;
3255
3256 /* cmd: "<cred id> <variable name>" */
3257 name = os_strchr(cmd, ' ');
3258 if (name == NULL)
3259 return -1;
3260 *name++ = '\0';
3261
3262 id = atoi(cmd);
3263 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
3264 id, name);
3265
3266 cred = wpa_config_get_cred(wpa_s->conf, id);
3267 if (cred == NULL) {
3268 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3269 id);
3270 return -1;
3271 }
3272
3273 value = wpa_config_get_cred_no_key(cred, name);
3274 if (value == NULL) {
3275 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
3276 name);
3277 return -1;
3278 }
3279
3280 res = os_strlcpy(buf, value, buflen);
3281 if (res >= buflen) {
3282 os_free(value);
3283 return -1;
3284 }
3285
3286 os_free(value);
3287
3288 return res;
3289}
3290
3291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003292#ifndef CONFIG_NO_CONFIG_WRITE
3293static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
3294{
3295 int ret;
3296
3297 if (!wpa_s->conf->update_config) {
3298 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
3299 "to update configuration (update_config=0)");
3300 return -1;
3301 }
3302
3303 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3304 if (ret) {
3305 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
3306 "update configuration");
3307 } else {
3308 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
3309 " updated");
3310 }
3311
3312 return ret;
3313}
3314#endif /* CONFIG_NO_CONFIG_WRITE */
3315
3316
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003317struct cipher_info {
3318 unsigned int capa;
3319 const char *name;
3320 int group_only;
3321};
3322
3323static const struct cipher_info ciphers[] = {
3324 { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
3325 { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
3326 { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
3327 { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
3328 { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
3329 { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
3330 { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
3331 { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
3332};
3333
3334
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003335static int ctrl_iface_get_capability_pairwise(int res, char *strict,
3336 struct wpa_driver_capa *capa,
3337 char *buf, size_t buflen)
3338{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003339 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003340 char *pos, *end;
3341 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003342 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003343
3344 pos = buf;
3345 end = pos + buflen;
3346
3347 if (res < 0) {
3348 if (strict)
3349 return 0;
3350 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
3351 if (len >= buflen)
3352 return -1;
3353 return len;
3354 }
3355
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003356 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3357 if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
3358 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003359 pos == buf ? "" : " ",
3360 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003361 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003362 return pos - buf;
3363 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003364 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003365 }
3366
3367 return pos - buf;
3368}
3369
3370
3371static int ctrl_iface_get_capability_group(int res, char *strict,
3372 struct wpa_driver_capa *capa,
3373 char *buf, size_t buflen)
3374{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003375 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003376 char *pos, *end;
3377 size_t len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003378 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003379
3380 pos = buf;
3381 end = pos + buflen;
3382
3383 if (res < 0) {
3384 if (strict)
3385 return 0;
3386 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
3387 if (len >= buflen)
3388 return -1;
3389 return len;
3390 }
3391
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003392 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3393 if (capa->enc & ciphers[i].capa) {
3394 ret = os_snprintf(pos, end - pos, "%s%s",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003395 pos == buf ? "" : " ",
3396 ciphers[i].name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003397 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003398 return pos - buf;
3399 pos += ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003400 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003401 }
3402
3403 return pos - buf;
3404}
3405
3406
3407static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
3408 struct wpa_driver_capa *capa,
3409 char *buf, size_t buflen)
3410{
3411 int ret;
3412 char *pos, *end;
3413 size_t len;
3414
3415 pos = buf;
3416 end = pos + buflen;
3417
3418 if (res < 0) {
3419 if (strict)
3420 return 0;
3421 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
3422 "NONE", buflen);
3423 if (len >= buflen)
3424 return -1;
3425 return len;
3426 }
3427
3428 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003429 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003430 return pos - buf;
3431 pos += ret;
3432
3433 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3434 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3435 ret = os_snprintf(pos, end - pos, " WPA-EAP");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003436 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003437 return pos - buf;
3438 pos += ret;
3439 }
3440
3441 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3442 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3443 ret = os_snprintf(pos, end - pos, " WPA-PSK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003444 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003445 return pos - buf;
3446 pos += ret;
3447 }
3448
3449 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
3450 ret = os_snprintf(pos, end - pos, " WPA-NONE");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003451 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003452 return pos - buf;
3453 pos += ret;
3454 }
3455
3456 return pos - buf;
3457}
3458
3459
3460static int ctrl_iface_get_capability_proto(int res, char *strict,
3461 struct wpa_driver_capa *capa,
3462 char *buf, size_t buflen)
3463{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003464 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003465 char *pos, *end;
3466 size_t len;
3467
3468 pos = buf;
3469 end = pos + buflen;
3470
3471 if (res < 0) {
3472 if (strict)
3473 return 0;
3474 len = os_strlcpy(buf, "RSN WPA", buflen);
3475 if (len >= buflen)
3476 return -1;
3477 return len;
3478 }
3479
3480 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3481 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003482 ret = os_snprintf(pos, end - pos, "%sRSN",
3483 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003484 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003485 return pos - buf;
3486 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003487 }
3488
3489 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3490 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003491 ret = os_snprintf(pos, end - pos, "%sWPA",
3492 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003493 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003494 return pos - buf;
3495 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003496 }
3497
3498 return pos - buf;
3499}
3500
3501
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003502static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
3503 int res, char *strict,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003504 struct wpa_driver_capa *capa,
3505 char *buf, size_t buflen)
3506{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003507 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003508 char *pos, *end;
3509 size_t len;
3510
3511 pos = buf;
3512 end = pos + buflen;
3513
3514 if (res < 0) {
3515 if (strict)
3516 return 0;
3517 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
3518 if (len >= buflen)
3519 return -1;
3520 return len;
3521 }
3522
3523 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003524 ret = os_snprintf(pos, end - pos, "%sOPEN",
3525 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003526 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003527 return pos - buf;
3528 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003529 }
3530
3531 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
3532 ret = os_snprintf(pos, end - pos, "%sSHARED",
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003533 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003534 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003535 return pos - buf;
3536 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003537 }
3538
3539 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003540 ret = os_snprintf(pos, end - pos, "%sLEAP",
3541 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003542 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003543 return pos - buf;
3544 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003545 }
3546
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003547#ifdef CONFIG_SAE
3548 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
3549 ret = os_snprintf(pos, end - pos, "%sSAE",
3550 pos == buf ? "" : " ");
3551 if (os_snprintf_error(end - pos, ret))
3552 return pos - buf;
3553 pos += ret;
3554 }
3555#endif /* CONFIG_SAE */
3556
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557 return pos - buf;
3558}
3559
3560
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003561static int ctrl_iface_get_capability_modes(int res, char *strict,
3562 struct wpa_driver_capa *capa,
3563 char *buf, size_t buflen)
3564{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003565 int ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003566 char *pos, *end;
3567 size_t len;
3568
3569 pos = buf;
3570 end = pos + buflen;
3571
3572 if (res < 0) {
3573 if (strict)
3574 return 0;
3575 len = os_strlcpy(buf, "IBSS AP", buflen);
3576 if (len >= buflen)
3577 return -1;
3578 return len;
3579 }
3580
3581 if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003582 ret = os_snprintf(pos, end - pos, "%sIBSS",
3583 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003584 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003585 return pos - buf;
3586 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003587 }
3588
3589 if (capa->flags & WPA_DRIVER_FLAGS_AP) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08003590 ret = os_snprintf(pos, end - pos, "%sAP",
3591 pos == buf ? "" : " ");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003592 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003593 return pos - buf;
3594 pos += ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003595 }
3596
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003597#ifdef CONFIG_MESH
3598 if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
3599 ret = os_snprintf(pos, end - pos, "%sMESH",
3600 pos == buf ? "" : " ");
3601 if (os_snprintf_error(end - pos, ret))
3602 return pos - buf;
3603 pos += ret;
3604 }
3605#endif /* CONFIG_MESH */
3606
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003607 return pos - buf;
3608}
3609
3610
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003611static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
3612 char *buf, size_t buflen)
3613{
3614 struct hostapd_channel_data *chnl;
3615 int ret, i, j;
3616 char *pos, *end, *hmode;
3617
3618 pos = buf;
3619 end = pos + buflen;
3620
3621 for (j = 0; j < wpa_s->hw.num_modes; j++) {
3622 switch (wpa_s->hw.modes[j].mode) {
3623 case HOSTAPD_MODE_IEEE80211B:
3624 hmode = "B";
3625 break;
3626 case HOSTAPD_MODE_IEEE80211G:
3627 hmode = "G";
3628 break;
3629 case HOSTAPD_MODE_IEEE80211A:
3630 hmode = "A";
3631 break;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003632 case HOSTAPD_MODE_IEEE80211AD:
3633 hmode = "AD";
3634 break;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003635 default:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003636 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003637 }
3638 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003639 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003640 return pos - buf;
3641 pos += ret;
3642 chnl = wpa_s->hw.modes[j].channels;
3643 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003644 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3645 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003646 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003647 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003648 return pos - buf;
3649 pos += ret;
3650 }
3651 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003652 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003653 return pos - buf;
3654 pos += ret;
3655 }
3656
3657 return pos - buf;
3658}
3659
3660
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003661static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
3662 char *buf, size_t buflen)
3663{
3664 struct hostapd_channel_data *chnl;
3665 int ret, i, j;
3666 char *pos, *end, *hmode;
3667
3668 pos = buf;
3669 end = pos + buflen;
3670
3671 for (j = 0; j < wpa_s->hw.num_modes; j++) {
3672 switch (wpa_s->hw.modes[j].mode) {
3673 case HOSTAPD_MODE_IEEE80211B:
3674 hmode = "B";
3675 break;
3676 case HOSTAPD_MODE_IEEE80211G:
3677 hmode = "G";
3678 break;
3679 case HOSTAPD_MODE_IEEE80211A:
3680 hmode = "A";
3681 break;
3682 case HOSTAPD_MODE_IEEE80211AD:
3683 hmode = "AD";
3684 break;
3685 default:
3686 continue;
3687 }
3688 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
3689 hmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003690 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003691 return pos - buf;
3692 pos += ret;
3693 chnl = wpa_s->hw.modes[j].channels;
3694 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
3695 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3696 continue;
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08003697 ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003698 chnl[i].chan, chnl[i].freq,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003699 chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
3700 " (NO_IR)" : "",
Dmitry Shmidt5da5e352014-02-03 13:30:46 -08003701 chnl[i].flag & HOSTAPD_CHAN_RADAR ?
3702 " (DFS)" : "");
3703
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003704 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003705 return pos - buf;
3706 pos += ret;
3707 }
3708 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003709 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003710 return pos - buf;
3711 pos += ret;
3712 }
3713
3714 return pos - buf;
3715}
3716
3717
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003718static int wpa_supplicant_ctrl_iface_get_capability(
3719 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
3720 size_t buflen)
3721{
3722 struct wpa_driver_capa capa;
3723 int res;
3724 char *strict;
3725 char field[30];
3726 size_t len;
3727
3728 /* Determine whether or not strict checking was requested */
3729 len = os_strlcpy(field, _field, sizeof(field));
3730 if (len >= sizeof(field))
3731 return -1;
3732 strict = os_strchr(field, ' ');
3733 if (strict != NULL) {
3734 *strict++ = '\0';
3735 if (os_strcmp(strict, "strict") != 0)
3736 return -1;
3737 }
3738
3739 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
3740 field, strict ? strict : "");
3741
3742 if (os_strcmp(field, "eap") == 0) {
3743 return eap_get_names(buf, buflen);
3744 }
3745
3746 res = wpa_drv_get_capa(wpa_s, &capa);
3747
3748 if (os_strcmp(field, "pairwise") == 0)
3749 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
3750 buf, buflen);
3751
3752 if (os_strcmp(field, "group") == 0)
3753 return ctrl_iface_get_capability_group(res, strict, &capa,
3754 buf, buflen);
3755
3756 if (os_strcmp(field, "key_mgmt") == 0)
3757 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
3758 buf, buflen);
3759
3760 if (os_strcmp(field, "proto") == 0)
3761 return ctrl_iface_get_capability_proto(res, strict, &capa,
3762 buf, buflen);
3763
3764 if (os_strcmp(field, "auth_alg") == 0)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08003765 return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
3766 &capa, buf, buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003767
Dmitry Shmidt700a1372013-03-15 14:14:44 -07003768 if (os_strcmp(field, "modes") == 0)
3769 return ctrl_iface_get_capability_modes(res, strict, &capa,
3770 buf, buflen);
3771
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07003772 if (os_strcmp(field, "channels") == 0)
3773 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
3774
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003775 if (os_strcmp(field, "freq") == 0)
3776 return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
3777
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07003778#ifdef CONFIG_TDLS
3779 if (os_strcmp(field, "tdls") == 0)
3780 return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
3781#endif /* CONFIG_TDLS */
3782
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003783#ifdef CONFIG_ERP
3784 if (os_strcmp(field, "erp") == 0) {
3785 res = os_snprintf(buf, buflen, "ERP");
3786 if (os_snprintf_error(buflen, res))
3787 return -1;
3788 return res;
3789 }
3790#endif /* CONFIG_EPR */
3791
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003792 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
3793 field);
3794
3795 return -1;
3796}
3797
3798
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003799#ifdef CONFIG_INTERWORKING
3800static char * anqp_add_hex(char *pos, char *end, const char *title,
3801 struct wpabuf *data)
3802{
3803 char *start = pos;
3804 size_t i;
3805 int ret;
3806 const u8 *d;
3807
3808 if (data == NULL)
3809 return start;
3810
3811 ret = os_snprintf(pos, end - pos, "%s=", title);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003812 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003813 return start;
3814 pos += ret;
3815
3816 d = wpabuf_head_u8(data);
3817 for (i = 0; i < wpabuf_len(data); i++) {
3818 ret = os_snprintf(pos, end - pos, "%02x", *d++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003819 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003820 return start;
3821 pos += ret;
3822 }
3823
3824 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003825 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003826 return start;
3827 pos += ret;
3828
3829 return pos;
3830}
3831#endif /* CONFIG_INTERWORKING */
3832
3833
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003834static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
3835 unsigned long mask, char *buf, size_t buflen)
3836{
3837 size_t i;
3838 int ret;
3839 char *pos, *end;
3840 const u8 *ie, *ie2;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003841
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003842 pos = buf;
3843 end = buf + buflen;
3844
3845 if (mask & WPA_BSS_MASK_ID) {
3846 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003847 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003848 return 0;
3849 pos += ret;
3850 }
3851
3852 if (mask & WPA_BSS_MASK_BSSID) {
3853 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
3854 MAC2STR(bss->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003855 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003856 return 0;
3857 pos += ret;
3858 }
3859
3860 if (mask & WPA_BSS_MASK_FREQ) {
3861 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003862 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003863 return 0;
3864 pos += ret;
3865 }
3866
3867 if (mask & WPA_BSS_MASK_BEACON_INT) {
3868 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
3869 bss->beacon_int);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003870 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003871 return 0;
3872 pos += ret;
3873 }
3874
3875 if (mask & WPA_BSS_MASK_CAPABILITIES) {
3876 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
3877 bss->caps);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003878 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003879 return 0;
3880 pos += ret;
3881 }
3882
3883 if (mask & WPA_BSS_MASK_QUAL) {
3884 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003885 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003886 return 0;
3887 pos += ret;
3888 }
3889
3890 if (mask & WPA_BSS_MASK_NOISE) {
3891 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003892 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003893 return 0;
3894 pos += ret;
3895 }
3896
3897 if (mask & WPA_BSS_MASK_LEVEL) {
3898 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003899 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003900 return 0;
3901 pos += ret;
3902 }
3903
3904 if (mask & WPA_BSS_MASK_TSF) {
3905 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
3906 (unsigned long long) bss->tsf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003907 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003908 return 0;
3909 pos += ret;
3910 }
3911
3912 if (mask & WPA_BSS_MASK_AGE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003913 struct os_reltime now;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003914
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003915 os_get_reltime(&now);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003916 ret = os_snprintf(pos, end - pos, "age=%d\n",
3917 (int) (now.sec - bss->last_update.sec));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003918 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003919 return 0;
3920 pos += ret;
3921 }
3922
3923 if (mask & WPA_BSS_MASK_IE) {
3924 ret = os_snprintf(pos, end - pos, "ie=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003925 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003926 return 0;
3927 pos += ret;
3928
3929 ie = (const u8 *) (bss + 1);
3930 for (i = 0; i < bss->ie_len; i++) {
3931 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003932 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003933 return 0;
3934 pos += ret;
3935 }
3936
3937 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003938 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003939 return 0;
3940 pos += ret;
3941 }
3942
3943 if (mask & WPA_BSS_MASK_FLAGS) {
3944 ret = os_snprintf(pos, end - pos, "flags=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003945 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003946 return 0;
3947 pos += ret;
3948
3949 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
3950 if (ie)
3951 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
3952 2 + ie[1]);
3953 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
3954 if (ie2)
3955 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
3956 2 + ie2[1]);
3957 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
3958 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
3959 ret = os_snprintf(pos, end - pos, "[WEP]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003960 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003961 return 0;
3962 pos += ret;
3963 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07003964 if (bss_is_dmg(bss)) {
3965 const char *s;
3966 ret = os_snprintf(pos, end - pos, "[DMG]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003967 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003968 return 0;
3969 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07003970 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
3971 case IEEE80211_CAP_DMG_IBSS:
3972 s = "[IBSS]";
3973 break;
3974 case IEEE80211_CAP_DMG_AP:
3975 s = "[ESS]";
3976 break;
3977 case IEEE80211_CAP_DMG_PBSS:
3978 s = "[PBSS]";
3979 break;
3980 default:
3981 s = "";
3982 break;
3983 }
3984 ret = os_snprintf(pos, end - pos, "%s", s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003985 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003986 return 0;
3987 pos += ret;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07003988 } else {
3989 if (bss->caps & IEEE80211_CAP_IBSS) {
3990 ret = os_snprintf(pos, end - pos, "[IBSS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003991 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07003992 return 0;
3993 pos += ret;
3994 }
3995 if (bss->caps & IEEE80211_CAP_ESS) {
3996 ret = os_snprintf(pos, end - pos, "[ESS]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003997 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07003998 return 0;
3999 pos += ret;
4000 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004001 }
Dmitry Shmidt96571392013-10-14 12:54:46 -07004002 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
4003 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004004 ret = os_snprintf(pos, end - pos, "[P2P]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004005 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004006 return 0;
4007 pos += ret;
4008 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004009#ifdef CONFIG_HS20
4010 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
4011 ret = os_snprintf(pos, end - pos, "[HS20]");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004012 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004013 return 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004014 pos += ret;
4015 }
4016#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004017
4018 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004019 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004020 return 0;
4021 pos += ret;
4022 }
4023
4024 if (mask & WPA_BSS_MASK_SSID) {
4025 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
4026 wpa_ssid_txt(bss->ssid, bss->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004027 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004028 return 0;
4029 pos += ret;
4030 }
4031
4032#ifdef CONFIG_WPS
4033 if (mask & WPA_BSS_MASK_WPS_SCAN) {
4034 ie = (const u8 *) (bss + 1);
4035 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
4036 if (ret < 0 || ret >= end - pos)
4037 return 0;
4038 pos += ret;
4039 }
4040#endif /* CONFIG_WPS */
4041
4042#ifdef CONFIG_P2P
4043 if (mask & WPA_BSS_MASK_P2P_SCAN) {
4044 ie = (const u8 *) (bss + 1);
4045 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
4046 if (ret < 0 || ret >= end - pos)
4047 return 0;
4048 pos += ret;
4049 }
4050#endif /* CONFIG_P2P */
4051
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004052#ifdef CONFIG_WIFI_DISPLAY
4053 if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
4054 struct wpabuf *wfd;
4055 ie = (const u8 *) (bss + 1);
4056 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
4057 WFD_IE_VENDOR_TYPE);
4058 if (wfd) {
4059 ret = os_snprintf(pos, end - pos, "wfd_subelems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004060 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004061 wpabuf_free(wfd);
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004062 return 0;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004063 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004064 pos += ret;
4065
4066 pos += wpa_snprintf_hex(pos, end - pos,
4067 wpabuf_head(wfd),
4068 wpabuf_len(wfd));
4069 wpabuf_free(wfd);
4070
4071 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004072 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004073 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004074 pos += ret;
4075 }
4076 }
4077#endif /* CONFIG_WIFI_DISPLAY */
4078
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004079#ifdef CONFIG_INTERWORKING
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004080 if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
4081 struct wpa_bss_anqp *anqp = bss->anqp;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004082 pos = anqp_add_hex(pos, end, "anqp_venue_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004083 anqp->venue_name);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004084 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004085 anqp->network_auth_type);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004086 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004087 anqp->roaming_consortium);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004088 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004089 anqp->ip_addr_type_availability);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004090 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004091 anqp->nai_realm);
4092 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004093 pos = anqp_add_hex(pos, end, "anqp_domain_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004094 anqp->domain_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004095#ifdef CONFIG_HS20
4096 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004097 anqp->hs20_operator_friendly_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004098 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004099 anqp->hs20_wan_metrics);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004100 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004101 anqp->hs20_connection_capability);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004102 pos = anqp_add_hex(pos, end, "hs20_operating_class",
4103 anqp->hs20_operating_class);
4104 pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
4105 anqp->hs20_osu_providers_list);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004106#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004107 }
4108#endif /* CONFIG_INTERWORKING */
4109
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004110#ifdef CONFIG_MESH
4111 if (mask & WPA_BSS_MASK_MESH_SCAN) {
4112 ie = (const u8 *) (bss + 1);
4113 ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
4114 if (ret < 0 || ret >= end - pos)
4115 return 0;
4116 pos += ret;
4117 }
4118#endif /* CONFIG_MESH */
4119
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004120 if (mask & WPA_BSS_MASK_DELIM) {
4121 ret = os_snprintf(pos, end - pos, "====\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004122 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004123 return 0;
4124 pos += ret;
4125 }
Irfan Sheriffe2ea0082012-08-13 10:56:16 -07004126
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004127 return pos - buf;
4128}
4129
Dmitry Shmidt04949592012-07-19 12:16:46 -07004130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004131static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
4132 const char *cmd, char *buf,
4133 size_t buflen)
4134{
4135 u8 bssid[ETH_ALEN];
4136 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004137 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004138 struct wpa_bss *bsslast = NULL;
4139 struct dl_list *next;
4140 int ret = 0;
4141 int len;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004142 char *ctmp, *end = buf + buflen;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004143 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004144
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004145 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
4146 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
4147 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004148 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004149 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
4150 list_id);
4151 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004152 unsigned int id1, id2;
4153
4154 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
4155 wpa_printf(MSG_INFO, "Wrong BSS range "
4156 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004157 return 0;
4158 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004159
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004160 if (*(cmd + 6) == '-')
4161 id1 = 0;
4162 else
4163 id1 = atoi(cmd + 6);
4164 ctmp++;
4165 if (*ctmp >= '0' && *ctmp <= '9')
4166 id2 = atoi(ctmp);
4167 else
4168 id2 = (unsigned int) -1;
4169 bss = wpa_bss_get_id_range(wpa_s, id1, id2);
4170 if (id2 == (unsigned int) -1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004171 bsslast = dl_list_last(&wpa_s->bss_id,
4172 struct wpa_bss,
4173 list_id);
4174 else {
4175 bsslast = wpa_bss_get_id(wpa_s, id2);
4176 if (bsslast == NULL && bss && id2 > id1) {
4177 struct wpa_bss *tmp = bss;
4178 for (;;) {
4179 next = tmp->list_id.next;
4180 if (next == &wpa_s->bss_id)
4181 break;
4182 tmp = dl_list_entry(
4183 next, struct wpa_bss,
4184 list_id);
4185 if (tmp->id > id2)
4186 break;
4187 bsslast = tmp;
4188 }
4189 }
4190 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004191 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004192 } else if (os_strncmp(cmd, "FIRST", 5) == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07004193 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004194 else if (os_strncmp(cmd, "LAST", 4) == 0)
4195 bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004196 else if (os_strncmp(cmd, "ID-", 3) == 0) {
4197 i = atoi(cmd + 3);
4198 bss = wpa_bss_get_id(wpa_s, i);
4199 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4200 i = atoi(cmd + 5);
4201 bss = wpa_bss_get_id(wpa_s, i);
4202 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004203 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004204 if (next == &wpa_s->bss_id)
4205 bss = NULL;
4206 else
4207 bss = dl_list_entry(next, struct wpa_bss,
4208 list_id);
4209 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004210#ifdef CONFIG_P2P
4211 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
4212 if (hwaddr_aton(cmd + 13, bssid) == 0)
4213 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
4214 else
4215 bss = NULL;
4216#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004217 } else if (hwaddr_aton(cmd, bssid) == 0)
4218 bss = wpa_bss_get_bssid(wpa_s, bssid);
4219 else {
4220 struct wpa_bss *tmp;
4221 i = atoi(cmd);
4222 bss = NULL;
4223 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
4224 {
4225 if (i-- == 0) {
4226 bss = tmp;
4227 break;
4228 }
4229 }
4230 }
4231
Dmitry Shmidt04949592012-07-19 12:16:46 -07004232 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
4233 mask = strtoul(ctmp + 5, NULL, 0x10);
4234 if (mask == 0)
4235 mask = WPA_BSS_MASK_ALL;
4236 }
4237
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004238 if (bss == NULL)
4239 return 0;
4240
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004241 if (bsslast == NULL)
4242 bsslast = bss;
4243 do {
4244 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
4245 ret += len;
4246 buf += len;
4247 buflen -= len;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004248 if (bss == bsslast) {
4249 if ((mask & WPA_BSS_MASK_DELIM) && len &&
4250 (bss == dl_list_last(&wpa_s->bss_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004251 struct wpa_bss, list_id))) {
4252 int res;
4253
4254 res = os_snprintf(buf - 5, end - buf + 5,
4255 "####\n");
4256 if (os_snprintf_error(end - buf + 5, res)) {
4257 wpa_printf(MSG_DEBUG,
4258 "Could not add end delim");
4259 }
4260 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004261 break;
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08004262 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004263 next = bss->list_id.next;
4264 if (next == &wpa_s->bss_id)
4265 break;
4266 bss = dl_list_entry(next, struct wpa_bss, list_id);
4267 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004268
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07004269 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004270}
4271
4272
4273static int wpa_supplicant_ctrl_iface_ap_scan(
4274 struct wpa_supplicant *wpa_s, char *cmd)
4275{
4276 int ap_scan = atoi(cmd);
4277 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
4278}
4279
4280
4281static int wpa_supplicant_ctrl_iface_scan_interval(
4282 struct wpa_supplicant *wpa_s, char *cmd)
4283{
4284 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004285 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004286}
4287
4288
4289static int wpa_supplicant_ctrl_iface_bss_expire_age(
4290 struct wpa_supplicant *wpa_s, char *cmd)
4291{
4292 int expire_age = atoi(cmd);
4293 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
4294}
4295
4296
4297static int wpa_supplicant_ctrl_iface_bss_expire_count(
4298 struct wpa_supplicant *wpa_s, char *cmd)
4299{
4300 int expire_count = atoi(cmd);
4301 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
4302}
4303
4304
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004305static void wpa_supplicant_ctrl_iface_bss_flush(
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07004306 struct wpa_supplicant *wpa_s, char *cmd)
4307{
4308 int flush_age = atoi(cmd);
4309
4310 if (flush_age == 0)
4311 wpa_bss_flush(wpa_s);
4312 else
4313 wpa_bss_flush_by_age(wpa_s, flush_age);
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07004314}
4315
4316
Dmitry Shmidt21de2142014-04-08 10:50:52 -07004317#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004318static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
4319{
4320 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
4321 /* MLME-DELETEKEYS.request */
4322 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
4323 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
4324 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
4325 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
4326#ifdef CONFIG_IEEE80211W
4327 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
4328 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
4329#endif /* CONFIG_IEEE80211W */
4330
4331 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
4332 0);
4333 /* MLME-SETPROTECTION.request(None) */
4334 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
4335 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
4336 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
4337 wpa_sm_drop_sa(wpa_s->wpa);
4338}
Dmitry Shmidt21de2142014-04-08 10:50:52 -07004339#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340
4341
4342static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
4343 char *addr)
4344{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004345#ifdef CONFIG_NO_SCAN_PROCESSING
4346 return -1;
4347#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004348 u8 bssid[ETH_ALEN];
4349 struct wpa_bss *bss;
4350 struct wpa_ssid *ssid = wpa_s->current_ssid;
4351
4352 if (hwaddr_aton(addr, bssid)) {
4353 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
4354 "address '%s'", addr);
4355 return -1;
4356 }
4357
4358 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
4359
Dmitry Shmidt444d5672013-04-01 13:08:44 -07004360 if (!ssid) {
4361 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
4362 "configuration known for the target AP");
4363 return -1;
4364 }
4365
4366 bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004367 if (!bss) {
4368 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
4369 "from BSS table");
4370 return -1;
4371 }
4372
4373 /*
4374 * TODO: Find best network configuration block from configuration to
4375 * allow roaming to other networks
4376 */
4377
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004378 wpa_s->reassociate = 1;
4379 wpa_supplicant_connect(wpa_s, bss, ssid);
4380
4381 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004382#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004383}
4384
4385
4386#ifdef CONFIG_P2P
4387static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
4388{
4389 unsigned int timeout = atoi(cmd);
4390 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004391 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004392 u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004393 char *pos;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004394 unsigned int search_delay;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004395
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07004396 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
4397 wpa_dbg(wpa_s, MSG_INFO,
4398 "Reject P2P_FIND since interface is disabled");
4399 return -1;
4400 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004401 if (os_strstr(cmd, "type=social"))
4402 type = P2P_FIND_ONLY_SOCIAL;
4403 else if (os_strstr(cmd, "type=progressive"))
4404 type = P2P_FIND_PROGRESSIVE;
4405
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004406 pos = os_strstr(cmd, "dev_id=");
4407 if (pos) {
4408 pos += 7;
4409 if (hwaddr_aton(pos, dev_id))
4410 return -1;
4411 _dev_id = dev_id;
4412 }
4413
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004414 pos = os_strstr(cmd, "dev_type=");
4415 if (pos) {
4416 pos += 9;
4417 if (wps_dev_type_str2bin(pos, dev_type) < 0)
4418 return -1;
4419 _dev_type = dev_type;
4420 }
4421
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004422 pos = os_strstr(cmd, "delay=");
4423 if (pos) {
4424 pos += 6;
4425 search_delay = atoi(pos);
4426 } else
4427 search_delay = wpas_p2p_search_delay(wpa_s);
4428
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004429 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
4430 _dev_id, search_delay);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004431}
4432
4433
4434static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
4435 char *buf, size_t buflen)
4436{
4437 u8 addr[ETH_ALEN];
4438 char *pos, *pos2;
4439 char *pin = NULL;
4440 enum p2p_wps_method wps_method;
4441 int new_pin;
4442 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004443 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004444 int join;
4445 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004446 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004447 int go_intent = -1;
4448 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004449 int pd;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004450 int ht40, vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004451
Dmitry Shmidt04949592012-07-19 12:16:46 -07004452 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
4453 * [persistent|persistent=<network id>]
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004454 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004455 * [ht40] [vht] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004456
4457 if (hwaddr_aton(cmd, addr))
4458 return -1;
4459
4460 pos = cmd + 17;
4461 if (*pos != ' ')
4462 return -1;
4463 pos++;
4464
4465 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004466 pos2 = os_strstr(pos, " persistent=");
4467 if (pos2) {
4468 struct wpa_ssid *ssid;
4469 persistent_id = atoi(pos2 + 12);
4470 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
4471 if (ssid == NULL || ssid->disabled != 2 ||
4472 ssid->mode != WPAS_MODE_P2P_GO) {
4473 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
4474 "SSID id=%d for persistent P2P group (GO)",
4475 persistent_id);
4476 return -1;
4477 }
4478 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004479 join = os_strstr(pos, " join") != NULL;
4480 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004481 automatic = os_strstr(pos, " auto") != NULL;
4482 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004483 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
4484 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
4485 vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004486
4487 pos2 = os_strstr(pos, " go_intent=");
4488 if (pos2) {
4489 pos2 += 11;
4490 go_intent = atoi(pos2);
4491 if (go_intent < 0 || go_intent > 15)
4492 return -1;
4493 }
4494
4495 pos2 = os_strstr(pos, " freq=");
4496 if (pos2) {
4497 pos2 += 6;
4498 freq = atoi(pos2);
4499 if (freq <= 0)
4500 return -1;
4501 }
4502
4503 if (os_strncmp(pos, "pin", 3) == 0) {
4504 /* Request random PIN (to be displayed) and enable the PIN */
4505 wps_method = WPS_PIN_DISPLAY;
4506 } else if (os_strncmp(pos, "pbc", 3) == 0) {
4507 wps_method = WPS_PBC;
4508 } else {
4509 pin = pos;
4510 pos = os_strchr(pin, ' ');
4511 wps_method = WPS_PIN_KEYPAD;
4512 if (pos) {
4513 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004514 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004515 wps_method = WPS_PIN_DISPLAY;
4516 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004517 if (!wps_pin_str_valid(pin)) {
4518 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
4519 return 17;
4520 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004521 }
4522
4523 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07004524 persistent_group, automatic, join,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004525 auth, go_intent, freq, persistent_id, pd,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004526 ht40, vht);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004527 if (new_pin == -2) {
4528 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
4529 return 25;
4530 }
4531 if (new_pin == -3) {
4532 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
4533 return 25;
4534 }
4535 if (new_pin < 0)
4536 return -1;
4537 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
4538 ret = os_snprintf(buf, buflen, "%08d", new_pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004539 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004540 return -1;
4541 return ret;
4542 }
4543
4544 os_memcpy(buf, "OK\n", 3);
4545 return 3;
4546}
4547
4548
4549static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
4550{
4551 unsigned int timeout = atoi(cmd);
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07004552 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
4553 wpa_dbg(wpa_s, MSG_INFO,
4554 "Reject P2P_LISTEN since interface is disabled");
4555 return -1;
4556 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004557 return wpas_p2p_listen(wpa_s, timeout);
4558}
4559
4560
4561static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
4562{
4563 u8 addr[ETH_ALEN];
4564 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004565 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004566
Dmitry Shmidt04949592012-07-19 12:16:46 -07004567 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004568
4569 if (hwaddr_aton(cmd, addr))
4570 return -1;
4571
4572 pos = cmd + 17;
4573 if (*pos != ' ')
4574 return -1;
4575 pos++;
4576
Dmitry Shmidt04949592012-07-19 12:16:46 -07004577 if (os_strstr(pos, " join") != NULL)
4578 use = WPAS_P2P_PD_FOR_JOIN;
4579 else if (os_strstr(pos, " auto") != NULL)
4580 use = WPAS_P2P_PD_AUTO;
4581
4582 return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004583}
4584
4585
4586static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
4587 size_t buflen)
4588{
4589 struct wpa_ssid *ssid = wpa_s->current_ssid;
4590
4591 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
4592 ssid->passphrase == NULL)
4593 return -1;
4594
4595 os_strlcpy(buf, ssid->passphrase, buflen);
4596 return os_strlen(buf);
4597}
4598
4599
4600static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
4601 char *buf, size_t buflen)
4602{
4603 u64 ref;
4604 int res;
4605 u8 dst_buf[ETH_ALEN], *dst;
4606 struct wpabuf *tlvs;
4607 char *pos;
4608 size_t len;
4609
4610 if (hwaddr_aton(cmd, dst_buf))
4611 return -1;
4612 dst = dst_buf;
4613 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
4614 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
4615 dst = NULL;
4616 pos = cmd + 17;
4617 if (*pos != ' ')
4618 return -1;
4619 pos++;
4620
4621 if (os_strncmp(pos, "upnp ", 5) == 0) {
4622 u8 version;
4623 pos += 5;
4624 if (hexstr2bin(pos, &version, 1) < 0)
4625 return -1;
4626 pos += 2;
4627 if (*pos != ' ')
4628 return -1;
4629 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004630 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004631#ifdef CONFIG_WIFI_DISPLAY
4632 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
4633 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
4634#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004635 } else {
4636 len = os_strlen(pos);
4637 if (len & 1)
4638 return -1;
4639 len /= 2;
4640 tlvs = wpabuf_alloc(len);
4641 if (tlvs == NULL)
4642 return -1;
4643 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
4644 wpabuf_free(tlvs);
4645 return -1;
4646 }
4647
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004648 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004649 wpabuf_free(tlvs);
4650 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004651 if (ref == 0)
4652 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004653 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004654 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004655 return -1;
4656 return res;
4657}
4658
4659
4660static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
4661 char *cmd)
4662{
4663 long long unsigned val;
4664 u64 req;
4665 if (sscanf(cmd, "%llx", &val) != 1)
4666 return -1;
4667 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004668 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004669}
4670
4671
4672static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
4673{
4674 int freq;
4675 u8 dst[ETH_ALEN];
4676 u8 dialog_token;
4677 struct wpabuf *resp_tlvs;
4678 char *pos, *pos2;
4679 size_t len;
4680
4681 pos = os_strchr(cmd, ' ');
4682 if (pos == NULL)
4683 return -1;
4684 *pos++ = '\0';
4685 freq = atoi(cmd);
4686 if (freq == 0)
4687 return -1;
4688
4689 if (hwaddr_aton(pos, dst))
4690 return -1;
4691 pos += 17;
4692 if (*pos != ' ')
4693 return -1;
4694 pos++;
4695
4696 pos2 = os_strchr(pos, ' ');
4697 if (pos2 == NULL)
4698 return -1;
4699 *pos2++ = '\0';
4700 dialog_token = atoi(pos);
4701
4702 len = os_strlen(pos2);
4703 if (len & 1)
4704 return -1;
4705 len /= 2;
4706 resp_tlvs = wpabuf_alloc(len);
4707 if (resp_tlvs == NULL)
4708 return -1;
4709 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
4710 wpabuf_free(resp_tlvs);
4711 return -1;
4712 }
4713
4714 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
4715 wpabuf_free(resp_tlvs);
4716 return 0;
4717}
4718
4719
4720static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
4721 char *cmd)
4722{
Dmitry Shmidt04949592012-07-19 12:16:46 -07004723 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
4724 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004725 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
4726 return 0;
4727}
4728
4729
4730static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
4731 char *cmd)
4732{
4733 char *pos;
4734 size_t len;
4735 struct wpabuf *query, *resp;
4736
4737 pos = os_strchr(cmd, ' ');
4738 if (pos == NULL)
4739 return -1;
4740 *pos++ = '\0';
4741
4742 len = os_strlen(cmd);
4743 if (len & 1)
4744 return -1;
4745 len /= 2;
4746 query = wpabuf_alloc(len);
4747 if (query == NULL)
4748 return -1;
4749 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
4750 wpabuf_free(query);
4751 return -1;
4752 }
4753
4754 len = os_strlen(pos);
4755 if (len & 1) {
4756 wpabuf_free(query);
4757 return -1;
4758 }
4759 len /= 2;
4760 resp = wpabuf_alloc(len);
4761 if (resp == NULL) {
4762 wpabuf_free(query);
4763 return -1;
4764 }
4765 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
4766 wpabuf_free(query);
4767 wpabuf_free(resp);
4768 return -1;
4769 }
4770
4771 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
4772 wpabuf_free(query);
4773 wpabuf_free(resp);
4774 return -1;
4775 }
4776 return 0;
4777}
4778
4779
4780static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
4781{
4782 char *pos;
4783 u8 version;
4784
4785 pos = os_strchr(cmd, ' ');
4786 if (pos == NULL)
4787 return -1;
4788 *pos++ = '\0';
4789
4790 if (hexstr2bin(cmd, &version, 1) < 0)
4791 return -1;
4792
4793 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
4794}
4795
4796
4797static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
4798{
4799 char *pos;
4800
4801 pos = os_strchr(cmd, ' ');
4802 if (pos == NULL)
4803 return -1;
4804 *pos++ = '\0';
4805
4806 if (os_strcmp(cmd, "bonjour") == 0)
4807 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
4808 if (os_strcmp(cmd, "upnp") == 0)
4809 return p2p_ctrl_service_add_upnp(wpa_s, pos);
4810 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
4811 return -1;
4812}
4813
4814
4815static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
4816 char *cmd)
4817{
4818 size_t len;
4819 struct wpabuf *query;
4820 int ret;
4821
4822 len = os_strlen(cmd);
4823 if (len & 1)
4824 return -1;
4825 len /= 2;
4826 query = wpabuf_alloc(len);
4827 if (query == NULL)
4828 return -1;
4829 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
4830 wpabuf_free(query);
4831 return -1;
4832 }
4833
4834 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
4835 wpabuf_free(query);
4836 return ret;
4837}
4838
4839
4840static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
4841{
4842 char *pos;
4843 u8 version;
4844
4845 pos = os_strchr(cmd, ' ');
4846 if (pos == NULL)
4847 return -1;
4848 *pos++ = '\0';
4849
4850 if (hexstr2bin(cmd, &version, 1) < 0)
4851 return -1;
4852
4853 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
4854}
4855
4856
4857static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
4858{
4859 char *pos;
4860
4861 pos = os_strchr(cmd, ' ');
4862 if (pos == NULL)
4863 return -1;
4864 *pos++ = '\0';
4865
4866 if (os_strcmp(cmd, "bonjour") == 0)
4867 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
4868 if (os_strcmp(cmd, "upnp") == 0)
4869 return p2p_ctrl_service_del_upnp(wpa_s, pos);
4870 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
4871 return -1;
4872}
4873
4874
4875static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
4876{
4877 u8 addr[ETH_ALEN];
4878
4879 /* <addr> */
4880
4881 if (hwaddr_aton(cmd, addr))
4882 return -1;
4883
4884 return wpas_p2p_reject(wpa_s, addr);
4885}
4886
4887
4888static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
4889{
4890 char *pos;
4891 int id;
4892 struct wpa_ssid *ssid;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004893 u8 *_peer = NULL, peer[ETH_ALEN];
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004894 int freq = 0, pref_freq = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004895 int ht40, vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004896
4897 id = atoi(cmd);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004898 pos = os_strstr(cmd, " peer=");
4899 if (pos) {
4900 pos += 6;
4901 if (hwaddr_aton(pos, peer))
4902 return -1;
4903 _peer = peer;
4904 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004905 ssid = wpa_config_get_network(wpa_s->conf, id);
4906 if (ssid == NULL || ssid->disabled != 2) {
4907 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
4908 "for persistent P2P group",
4909 id);
4910 return -1;
4911 }
4912
Jouni Malinen31be0a42012-08-31 21:20:51 +03004913 pos = os_strstr(cmd, " freq=");
4914 if (pos) {
4915 pos += 6;
4916 freq = atoi(pos);
4917 if (freq <= 0)
4918 return -1;
4919 }
4920
Dmitry Shmidt7a5e50a2013-03-05 12:37:16 -08004921 pos = os_strstr(cmd, " pref=");
4922 if (pos) {
4923 pos += 6;
4924 pref_freq = atoi(pos);
4925 if (pref_freq <= 0)
4926 return -1;
4927 }
4928
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004929 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
4930 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
4931 vht;
Jouni Malinen31be0a42012-08-31 21:20:51 +03004932
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004933 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
4934 pref_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004935}
4936
4937
4938static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
4939{
4940 char *pos;
4941 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
4942
4943 pos = os_strstr(cmd, " peer=");
4944 if (!pos)
4945 return -1;
4946
4947 *pos = '\0';
4948 pos += 6;
4949 if (hwaddr_aton(pos, peer)) {
4950 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
4951 return -1;
4952 }
4953
4954 pos = os_strstr(pos, " go_dev_addr=");
4955 if (pos) {
4956 pos += 13;
4957 if (hwaddr_aton(pos, go_dev_addr)) {
4958 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
4959 pos);
4960 return -1;
4961 }
4962 go_dev = go_dev_addr;
4963 }
4964
4965 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
4966}
4967
4968
4969static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
4970{
4971 if (os_strncmp(cmd, "persistent=", 11) == 0)
4972 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
4973 if (os_strncmp(cmd, "group=", 6) == 0)
4974 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
4975
4976 return -1;
4977}
4978
4979
4980static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004981 char *cmd, int freq, int ht40,
4982 int vht)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004983{
4984 int id;
4985 struct wpa_ssid *ssid;
4986
4987 id = atoi(cmd);
4988 ssid = wpa_config_get_network(wpa_s->conf, id);
4989 if (ssid == NULL || ssid->disabled != 2) {
4990 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
4991 "for persistent P2P group",
4992 id);
4993 return -1;
4994 }
4995
Dmitry Shmidt96be6222014-02-13 10:16:51 -08004996 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004997 NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004998}
4999
5000
5001static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
5002{
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005003 int freq = 0, ht40, vht;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005004 char *pos;
5005
5006 pos = os_strstr(cmd, "freq=");
5007 if (pos)
5008 freq = atoi(pos + 5);
5009
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005010 vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
5011 ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5012 vht;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005013
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005014 if (os_strncmp(cmd, "persistent=", 11) == 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005015 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005016 ht40, vht);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005017 if (os_strcmp(cmd, "persistent") == 0 ||
5018 os_strncmp(cmd, "persistent ", 11) == 0)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005019 return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005020 if (os_strncmp(cmd, "freq=", 5) == 0)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005021 return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005022 if (ht40)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005023 return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005024
5025 wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
5026 cmd);
5027 return -1;
5028}
5029
5030
5031static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
5032 char *buf, size_t buflen)
5033{
5034 u8 addr[ETH_ALEN], *addr_ptr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005035 int next, res;
5036 const struct p2p_peer_info *info;
5037 char *pos, *end;
5038 char devtype[WPS_DEV_TYPE_BUFSIZE];
5039 struct wpa_ssid *ssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005040 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005041
5042 if (!wpa_s->global->p2p)
5043 return -1;
5044
5045 if (os_strcmp(cmd, "FIRST") == 0) {
5046 addr_ptr = NULL;
5047 next = 0;
5048 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
5049 if (hwaddr_aton(cmd + 5, addr) < 0)
5050 return -1;
5051 addr_ptr = addr;
5052 next = 1;
5053 } else {
5054 if (hwaddr_aton(cmd, addr) < 0)
5055 return -1;
5056 addr_ptr = addr;
5057 next = 0;
5058 }
5059
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005060 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
5061 if (info == NULL)
5062 return -1;
5063
5064 pos = buf;
5065 end = buf + buflen;
5066
5067 res = os_snprintf(pos, end - pos, MACSTR "\n"
5068 "pri_dev_type=%s\n"
5069 "device_name=%s\n"
5070 "manufacturer=%s\n"
5071 "model_name=%s\n"
5072 "model_number=%s\n"
5073 "serial_number=%s\n"
5074 "config_methods=0x%x\n"
5075 "dev_capab=0x%x\n"
5076 "group_capab=0x%x\n"
5077 "level=%d\n",
5078 MAC2STR(info->p2p_device_addr),
5079 wps_dev_type_bin2str(info->pri_dev_type,
5080 devtype, sizeof(devtype)),
5081 info->device_name,
5082 info->manufacturer,
5083 info->model_name,
5084 info->model_number,
5085 info->serial_number,
5086 info->config_methods,
5087 info->dev_capab,
5088 info->group_capab,
5089 info->level);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005090 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005091 return pos - buf;
5092 pos += res;
5093
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005094 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
5095 {
5096 const u8 *t;
5097 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
5098 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
5099 wps_dev_type_bin2str(t, devtype,
5100 sizeof(devtype)));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005101 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005102 return pos - buf;
5103 pos += res;
5104 }
5105
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005106 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005107 if (ssid) {
5108 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005109 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005110 return pos - buf;
5111 pos += res;
5112 }
5113
5114 res = p2p_get_peer_info_txt(info, pos, end - pos);
5115 if (res < 0)
5116 return pos - buf;
5117 pos += res;
5118
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005119 if (info->vendor_elems) {
5120 res = os_snprintf(pos, end - pos, "vendor_elems=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005121 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005122 return pos - buf;
5123 pos += res;
5124
5125 pos += wpa_snprintf_hex(pos, end - pos,
5126 wpabuf_head(info->vendor_elems),
5127 wpabuf_len(info->vendor_elems));
5128
5129 res = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005130 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07005131 return pos - buf;
5132 pos += res;
5133 }
5134
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005135 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005136}
5137
5138
Dmitry Shmidt04949592012-07-19 12:16:46 -07005139static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
5140 const char *param)
5141{
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005142 unsigned int i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005143
5144 if (wpa_s->global->p2p == NULL)
5145 return -1;
5146
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005147 if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
5148 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005149
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005150 for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
5151 struct wpa_freq_range *freq;
5152 freq = &wpa_s->global->p2p_disallow_freq.range[i];
Dmitry Shmidt04949592012-07-19 12:16:46 -07005153 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
Dmitry Shmidt4ce9c872013-10-24 11:08:13 -07005154 freq->min, freq->max);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005155 }
5156
Dmitry Shmidt04949592012-07-19 12:16:46 -07005157 wpas_p2p_update_channel_list(wpa_s);
5158 return 0;
5159}
5160
5161
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005162static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
5163{
5164 char *param;
5165
5166 if (wpa_s->global->p2p == NULL)
5167 return -1;
5168
5169 param = os_strchr(cmd, ' ');
5170 if (param == NULL)
5171 return -1;
5172 *param++ = '\0';
5173
5174 if (os_strcmp(cmd, "discoverability") == 0) {
5175 p2p_set_client_discoverability(wpa_s->global->p2p,
5176 atoi(param));
5177 return 0;
5178 }
5179
5180 if (os_strcmp(cmd, "managed") == 0) {
5181 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
5182 return 0;
5183 }
5184
5185 if (os_strcmp(cmd, "listen_channel") == 0) {
5186 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07005187 atoi(param), 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005188 }
5189
5190 if (os_strcmp(cmd, "ssid_postfix") == 0) {
5191 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
5192 os_strlen(param));
5193 }
5194
5195 if (os_strcmp(cmd, "noa") == 0) {
5196 char *pos;
5197 int count, start, duration;
5198 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
5199 count = atoi(param);
5200 pos = os_strchr(param, ',');
5201 if (pos == NULL)
5202 return -1;
5203 pos++;
5204 start = atoi(pos);
5205 pos = os_strchr(pos, ',');
5206 if (pos == NULL)
5207 return -1;
5208 pos++;
5209 duration = atoi(pos);
5210 if (count < 0 || count > 255 || start < 0 || duration < 0)
5211 return -1;
5212 if (count == 0 && duration > 0)
5213 return -1;
5214 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
5215 "start=%d duration=%d", count, start, duration);
5216 return wpas_p2p_set_noa(wpa_s, count, start, duration);
5217 }
5218
5219 if (os_strcmp(cmd, "ps") == 0)
5220 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
5221
5222 if (os_strcmp(cmd, "oppps") == 0)
5223 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
5224
5225 if (os_strcmp(cmd, "ctwindow") == 0)
5226 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
5227
5228 if (os_strcmp(cmd, "disabled") == 0) {
5229 wpa_s->global->p2p_disabled = atoi(param);
5230 wpa_printf(MSG_DEBUG, "P2P functionality %s",
5231 wpa_s->global->p2p_disabled ?
5232 "disabled" : "enabled");
5233 if (wpa_s->global->p2p_disabled) {
5234 wpas_p2p_stop_find(wpa_s);
5235 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
5236 p2p_flush(wpa_s->global->p2p);
5237 }
5238 return 0;
5239 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07005240
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07005241 if (os_strcmp(cmd, "conc_pref") == 0) {
5242 if (os_strcmp(param, "sta") == 0)
5243 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
5244 else if (os_strcmp(param, "p2p") == 0)
5245 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07005246 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07005247 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07005248 return -1;
5249 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07005250 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07005251 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07005252 return 0;
5253 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07005254
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005255 if (os_strcmp(cmd, "force_long_sd") == 0) {
5256 wpa_s->force_long_sd = atoi(param);
5257 return 0;
5258 }
5259
5260 if (os_strcmp(cmd, "peer_filter") == 0) {
5261 u8 addr[ETH_ALEN];
5262 if (hwaddr_aton(param, addr))
5263 return -1;
5264 p2p_set_peer_filter(wpa_s->global->p2p, addr);
5265 return 0;
5266 }
5267
5268 if (os_strcmp(cmd, "cross_connect") == 0)
5269 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
5270
5271 if (os_strcmp(cmd, "go_apsd") == 0) {
5272 if (os_strcmp(param, "disable") == 0)
5273 wpa_s->set_ap_uapsd = 0;
5274 else {
5275 wpa_s->set_ap_uapsd = 1;
5276 wpa_s->ap_uapsd = atoi(param);
5277 }
5278 return 0;
5279 }
5280
5281 if (os_strcmp(cmd, "client_apsd") == 0) {
5282 if (os_strcmp(param, "disable") == 0)
5283 wpa_s->set_sta_uapsd = 0;
5284 else {
5285 int be, bk, vi, vo;
5286 char *pos;
5287 /* format: BE,BK,VI,VO;max SP Length */
5288 be = atoi(param);
5289 pos = os_strchr(param, ',');
5290 if (pos == NULL)
5291 return -1;
5292 pos++;
5293 bk = atoi(pos);
5294 pos = os_strchr(pos, ',');
5295 if (pos == NULL)
5296 return -1;
5297 pos++;
5298 vi = atoi(pos);
5299 pos = os_strchr(pos, ',');
5300 if (pos == NULL)
5301 return -1;
5302 pos++;
5303 vo = atoi(pos);
5304 /* ignore max SP Length for now */
5305
5306 wpa_s->set_sta_uapsd = 1;
5307 wpa_s->sta_uapsd = 0;
5308 if (be)
5309 wpa_s->sta_uapsd |= BIT(0);
5310 if (bk)
5311 wpa_s->sta_uapsd |= BIT(1);
5312 if (vi)
5313 wpa_s->sta_uapsd |= BIT(2);
5314 if (vo)
5315 wpa_s->sta_uapsd |= BIT(3);
5316 }
5317 return 0;
5318 }
5319
Dmitry Shmidt04949592012-07-19 12:16:46 -07005320 if (os_strcmp(cmd, "disallow_freq") == 0)
5321 return p2p_ctrl_disallow_freq(wpa_s, param);
5322
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005323 if (os_strcmp(cmd, "disc_int") == 0) {
5324 int min_disc_int, max_disc_int, max_disc_tu;
5325 char *pos;
5326
5327 pos = param;
5328
5329 min_disc_int = atoi(pos);
5330 pos = os_strchr(pos, ' ');
5331 if (pos == NULL)
5332 return -1;
5333 *pos++ = '\0';
5334
5335 max_disc_int = atoi(pos);
5336 pos = os_strchr(pos, ' ');
5337 if (pos == NULL)
5338 return -1;
5339 *pos++ = '\0';
5340
5341 max_disc_tu = atoi(pos);
5342
5343 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
5344 max_disc_int, max_disc_tu);
5345 }
5346
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07005347 if (os_strcmp(cmd, "per_sta_psk") == 0) {
5348 wpa_s->global->p2p_per_sta_psk = !!atoi(param);
5349 return 0;
5350 }
5351
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005352#ifdef CONFIG_WPS_NFC
5353 if (os_strcmp(cmd, "nfc_tag") == 0)
5354 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
5355#endif /* CONFIG_WPS_NFC */
5356
5357 if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
5358 wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
5359 return 0;
5360 }
5361
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005362 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
5363 cmd);
5364
5365 return -1;
5366}
5367
5368
Dmitry Shmidt444d5672013-04-01 13:08:44 -07005369static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
5370{
5371 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
5372 wpa_s->force_long_sd = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005373 wpas_p2p_stop_find(wpa_s);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07005374 if (wpa_s->global->p2p)
5375 p2p_flush(wpa_s->global->p2p);
5376}
5377
5378
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005379static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
5380{
5381 char *pos, *pos2;
5382 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
5383
5384 if (cmd[0]) {
5385 pos = os_strchr(cmd, ' ');
5386 if (pos == NULL)
5387 return -1;
5388 *pos++ = '\0';
5389 dur1 = atoi(cmd);
5390
5391 pos2 = os_strchr(pos, ' ');
5392 if (pos2)
5393 *pos2++ = '\0';
5394 int1 = atoi(pos);
5395 } else
5396 pos2 = NULL;
5397
5398 if (pos2) {
5399 pos = os_strchr(pos2, ' ');
5400 if (pos == NULL)
5401 return -1;
5402 *pos++ = '\0';
5403 dur2 = atoi(pos2);
5404 int2 = atoi(pos);
5405 }
5406
5407 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
5408}
5409
5410
5411static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
5412{
5413 char *pos;
5414 unsigned int period = 0, interval = 0;
5415
5416 if (cmd[0]) {
5417 pos = os_strchr(cmd, ' ');
5418 if (pos == NULL)
5419 return -1;
5420 *pos++ = '\0';
5421 period = atoi(cmd);
5422 interval = atoi(pos);
5423 }
5424
5425 return wpas_p2p_ext_listen(wpa_s, period, interval);
5426}
5427
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07005428
5429static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
5430{
5431 const char *pos;
5432 u8 peer[ETH_ALEN];
5433 int iface_addr = 0;
5434
5435 pos = cmd;
5436 if (os_strncmp(pos, "iface=", 6) == 0) {
5437 iface_addr = 1;
5438 pos += 6;
5439 }
5440 if (hwaddr_aton(pos, peer))
5441 return -1;
5442
5443 wpas_p2p_remove_client(wpa_s, peer, iface_addr);
5444 return 0;
5445}
5446
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005447#endif /* CONFIG_P2P */
5448
5449
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005450static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
5451{
5452 struct wpa_freq_range_list ranges;
5453 int *freqs = NULL;
5454 struct hostapd_hw_modes *mode;
5455 u16 i;
5456
5457 if (wpa_s->hw.modes == NULL)
5458 return NULL;
5459
5460 os_memset(&ranges, 0, sizeof(ranges));
5461 if (freq_range_list_parse(&ranges, val) < 0)
5462 return NULL;
5463
5464 for (i = 0; i < wpa_s->hw.num_modes; i++) {
5465 int j;
5466
5467 mode = &wpa_s->hw.modes[i];
5468 for (j = 0; j < mode->num_channels; j++) {
5469 unsigned int freq;
5470
5471 if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
5472 continue;
5473
5474 freq = mode->channels[j].freq;
5475 if (!freq_range_list_includes(&ranges, freq))
5476 continue;
5477
5478 int_array_add_unique(&freqs, freq);
5479 }
5480 }
5481
5482 os_free(ranges.range);
5483 return freqs;
5484}
5485
5486
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005487#ifdef CONFIG_INTERWORKING
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005488
5489static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
5490{
5491 int auto_sel = 0;
5492 int *freqs = NULL;
5493
5494 if (param) {
5495 char *pos;
5496
5497 auto_sel = os_strstr(param, "auto") != NULL;
5498
5499 pos = os_strstr(param, "freq=");
5500 if (pos) {
5501 freqs = freq_range_to_channel_list(wpa_s, pos + 5);
5502 if (freqs == NULL)
5503 return -1;
5504 }
5505
5506 }
5507
5508 return interworking_select(wpa_s, auto_sel, freqs);
5509}
5510
5511
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005512static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
5513{
5514 u8 bssid[ETH_ALEN];
5515 struct wpa_bss *bss;
5516
5517 if (hwaddr_aton(dst, bssid)) {
5518 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
5519 return -1;
5520 }
5521
5522 bss = wpa_bss_get_bssid(wpa_s, bssid);
5523 if (bss == NULL) {
5524 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
5525 MAC2STR(bssid));
5526 return -1;
5527 }
5528
5529 return interworking_connect(wpa_s, bss);
5530}
5531
5532
5533static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
5534{
5535 u8 dst_addr[ETH_ALEN];
5536 int used;
5537 char *pos;
5538#define MAX_ANQP_INFO_ID 100
5539 u16 id[MAX_ANQP_INFO_ID];
5540 size_t num_id = 0;
Dmitry Shmidt15907092014-03-25 10:42:57 -07005541 u32 subtypes = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005542
5543 used = hwaddr_aton2(dst, dst_addr);
5544 if (used < 0)
5545 return -1;
5546 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005547 if (*pos == ' ')
5548 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005549 while (num_id < MAX_ANQP_INFO_ID) {
Dmitry Shmidt15907092014-03-25 10:42:57 -07005550 if (os_strncmp(pos, "hs20:", 5) == 0) {
5551#ifdef CONFIG_HS20
5552 int num = atoi(pos + 5);
5553 if (num <= 0 || num > 31)
5554 return -1;
5555 subtypes |= BIT(num);
5556#else /* CONFIG_HS20 */
5557 return -1;
5558#endif /* CONFIG_HS20 */
5559 } else {
5560 id[num_id] = atoi(pos);
5561 if (id[num_id])
5562 num_id++;
5563 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005564 pos = os_strchr(pos + 1, ',');
5565 if (pos == NULL)
5566 break;
5567 pos++;
5568 }
5569
5570 if (num_id == 0)
5571 return -1;
5572
Dmitry Shmidt15907092014-03-25 10:42:57 -07005573 return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005574}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005575
5576
5577static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
5578{
5579 u8 dst_addr[ETH_ALEN];
5580 struct wpabuf *advproto, *query = NULL;
5581 int used, ret = -1;
5582 char *pos, *end;
5583 size_t len;
5584
5585 used = hwaddr_aton2(cmd, dst_addr);
5586 if (used < 0)
5587 return -1;
5588
5589 pos = cmd + used;
5590 while (*pos == ' ')
5591 pos++;
5592
5593 /* Advertisement Protocol ID */
5594 end = os_strchr(pos, ' ');
5595 if (end)
5596 len = end - pos;
5597 else
5598 len = os_strlen(pos);
5599 if (len & 0x01)
5600 return -1;
5601 len /= 2;
5602 if (len == 0)
5603 return -1;
5604 advproto = wpabuf_alloc(len);
5605 if (advproto == NULL)
5606 return -1;
5607 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
5608 goto fail;
5609
5610 if (end) {
5611 /* Optional Query Request */
5612 pos = end + 1;
5613 while (*pos == ' ')
5614 pos++;
5615
5616 len = os_strlen(pos);
5617 if (len) {
5618 if (len & 0x01)
5619 goto fail;
5620 len /= 2;
5621 if (len == 0)
5622 goto fail;
5623 query = wpabuf_alloc(len);
5624 if (query == NULL)
5625 goto fail;
5626 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
5627 goto fail;
5628 }
5629 }
5630
5631 ret = gas_send_request(wpa_s, dst_addr, advproto, query);
5632
5633fail:
5634 wpabuf_free(advproto);
5635 wpabuf_free(query);
5636
5637 return ret;
5638}
5639
5640
5641static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
5642 size_t buflen)
5643{
5644 u8 addr[ETH_ALEN];
5645 int dialog_token;
5646 int used;
5647 char *pos;
5648 size_t resp_len, start, requested_len;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005649 struct wpabuf *resp;
5650 int ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005651
5652 used = hwaddr_aton2(cmd, addr);
5653 if (used < 0)
5654 return -1;
5655
5656 pos = cmd + used;
5657 while (*pos == ' ')
5658 pos++;
5659 dialog_token = atoi(pos);
5660
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005661 if (wpa_s->last_gas_resp &&
5662 os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
5663 dialog_token == wpa_s->last_gas_dialog_token)
5664 resp = wpa_s->last_gas_resp;
5665 else if (wpa_s->prev_gas_resp &&
5666 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
5667 dialog_token == wpa_s->prev_gas_dialog_token)
5668 resp = wpa_s->prev_gas_resp;
5669 else
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005670 return -1;
5671
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005672 resp_len = wpabuf_len(resp);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005673 start = 0;
5674 requested_len = resp_len;
5675
5676 pos = os_strchr(pos, ' ');
5677 if (pos) {
5678 start = atoi(pos);
5679 if (start > resp_len)
5680 return os_snprintf(buf, buflen, "FAIL-Invalid range");
5681 pos = os_strchr(pos, ',');
5682 if (pos == NULL)
5683 return -1;
5684 pos++;
5685 requested_len = atoi(pos);
5686 if (start + requested_len > resp_len)
5687 return os_snprintf(buf, buflen, "FAIL-Invalid range");
5688 }
5689
5690 if (requested_len * 2 + 1 > buflen)
5691 return os_snprintf(buf, buflen, "FAIL-Too long response");
5692
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005693 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
5694 requested_len);
5695
5696 if (start + requested_len == resp_len) {
5697 /*
5698 * Free memory by dropping the response after it has been
5699 * fetched.
5700 */
5701 if (resp == wpa_s->prev_gas_resp) {
5702 wpabuf_free(wpa_s->prev_gas_resp);
5703 wpa_s->prev_gas_resp = NULL;
5704 } else {
5705 wpabuf_free(wpa_s->last_gas_resp);
5706 wpa_s->last_gas_resp = NULL;
5707 }
5708 }
5709
5710 return ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005711}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005712#endif /* CONFIG_INTERWORKING */
5713
5714
Dmitry Shmidt04949592012-07-19 12:16:46 -07005715#ifdef CONFIG_HS20
5716
5717static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
5718{
5719 u8 dst_addr[ETH_ALEN];
5720 int used;
5721 char *pos;
5722 u32 subtypes = 0;
5723
5724 used = hwaddr_aton2(dst, dst_addr);
5725 if (used < 0)
5726 return -1;
5727 pos = dst + used;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005728 if (*pos == ' ')
5729 pos++;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005730 for (;;) {
5731 int num = atoi(pos);
5732 if (num <= 0 || num > 31)
5733 return -1;
5734 subtypes |= BIT(num);
5735 pos = os_strchr(pos + 1, ',');
5736 if (pos == NULL)
5737 break;
5738 pos++;
5739 }
5740
5741 if (subtypes == 0)
5742 return -1;
5743
5744 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
5745}
5746
5747
5748static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
5749 const u8 *addr, const char *realm)
5750{
5751 u8 *buf;
5752 size_t rlen, len;
5753 int ret;
5754
5755 rlen = os_strlen(realm);
5756 len = 3 + rlen;
5757 buf = os_malloc(len);
5758 if (buf == NULL)
5759 return -1;
5760 buf[0] = 1; /* NAI Home Realm Count */
5761 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
5762 buf[2] = rlen;
5763 os_memcpy(buf + 3, realm, rlen);
5764
5765 ret = hs20_anqp_send_req(wpa_s, addr,
5766 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
5767 buf, len);
5768
5769 os_free(buf);
5770
5771 return ret;
5772}
5773
5774
5775static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
5776 char *dst)
5777{
5778 struct wpa_cred *cred = wpa_s->conf->cred;
5779 u8 dst_addr[ETH_ALEN];
5780 int used;
5781 u8 *buf;
5782 size_t len;
5783 int ret;
5784
5785 used = hwaddr_aton2(dst, dst_addr);
5786 if (used < 0)
5787 return -1;
5788
5789 while (dst[used] == ' ')
5790 used++;
5791 if (os_strncmp(dst + used, "realm=", 6) == 0)
5792 return hs20_nai_home_realm_list(wpa_s, dst_addr,
5793 dst + used + 6);
5794
5795 len = os_strlen(dst + used);
5796
5797 if (len == 0 && cred && cred->realm)
5798 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
5799
Dmitry Shmidt623d63a2014-06-13 11:05:14 -07005800 if (len & 1)
Dmitry Shmidt04949592012-07-19 12:16:46 -07005801 return -1;
5802 len /= 2;
5803 buf = os_malloc(len);
5804 if (buf == NULL)
5805 return -1;
5806 if (hexstr2bin(dst + used, buf, len) < 0) {
5807 os_free(buf);
5808 return -1;
5809 }
5810
5811 ret = hs20_anqp_send_req(wpa_s, dst_addr,
5812 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
5813 buf, len);
5814 os_free(buf);
5815
5816 return ret;
5817}
5818
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08005819
5820static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
5821{
5822 u8 dst_addr[ETH_ALEN];
5823 int used;
5824 char *icon;
5825
5826 used = hwaddr_aton2(cmd, dst_addr);
5827 if (used < 0)
5828 return -1;
5829
5830 while (cmd[used] == ' ')
5831 used++;
5832 icon = &cmd[used];
5833
5834 wpa_s->fetch_osu_icon_in_progress = 0;
5835 return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
5836 (u8 *) icon, os_strlen(icon));
5837}
5838
Dmitry Shmidt04949592012-07-19 12:16:46 -07005839#endif /* CONFIG_HS20 */
5840
5841
Dmitry Shmidt04949592012-07-19 12:16:46 -07005842#ifdef CONFIG_AUTOSCAN
5843
5844static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
5845 char *cmd)
5846{
5847 enum wpa_states state = wpa_s->wpa_state;
5848 char *new_params = NULL;
5849
5850 if (os_strlen(cmd) > 0) {
5851 new_params = os_strdup(cmd);
5852 if (new_params == NULL)
5853 return -1;
5854 }
5855
5856 os_free(wpa_s->conf->autoscan);
5857 wpa_s->conf->autoscan = new_params;
5858
5859 if (wpa_s->conf->autoscan == NULL)
5860 autoscan_deinit(wpa_s);
5861 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
5862 autoscan_init(wpa_s, 1);
5863 else if (state == WPA_SCANNING)
5864 wpa_supplicant_reinit_autoscan(wpa_s);
5865
5866 return 0;
5867}
5868
5869#endif /* CONFIG_AUTOSCAN */
5870
5871
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005872#ifdef CONFIG_WNM
5873
5874static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
5875{
5876 int enter;
5877 int intval = 0;
5878 char *pos;
5879 int ret;
5880 struct wpabuf *tfs_req = NULL;
5881
5882 if (os_strncmp(cmd, "enter", 5) == 0)
5883 enter = 1;
5884 else if (os_strncmp(cmd, "exit", 4) == 0)
5885 enter = 0;
5886 else
5887 return -1;
5888
5889 pos = os_strstr(cmd, " interval=");
5890 if (pos)
5891 intval = atoi(pos + 10);
5892
5893 pos = os_strstr(cmd, " tfs_req=");
5894 if (pos) {
5895 char *end;
5896 size_t len;
5897 pos += 9;
5898 end = os_strchr(pos, ' ');
5899 if (end)
5900 len = end - pos;
5901 else
5902 len = os_strlen(pos);
5903 if (len & 1)
5904 return -1;
5905 len /= 2;
5906 tfs_req = wpabuf_alloc(len);
5907 if (tfs_req == NULL)
5908 return -1;
5909 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
5910 wpabuf_free(tfs_req);
5911 return -1;
5912 }
5913 }
5914
5915 ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
5916 WNM_SLEEP_MODE_EXIT, intval,
5917 tfs_req);
5918 wpabuf_free(tfs_req);
5919
5920 return ret;
5921}
5922
Dmitry Shmidt44c95782013-05-17 09:51:35 -07005923
5924static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
5925{
5926 int query_reason;
5927
5928 query_reason = atoi(cmd);
5929
5930 wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
5931 query_reason);
5932
5933 return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
5934}
5935
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005936#endif /* CONFIG_WNM */
5937
5938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005939static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
5940 size_t buflen)
5941{
5942 struct wpa_signal_info si;
5943 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005944 char *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005945
5946 ret = wpa_drv_signal_poll(wpa_s, &si);
5947 if (ret)
5948 return -1;
5949
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005950 pos = buf;
5951 end = buf + buflen;
5952
5953 ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005954 "NOISE=%d\nFREQUENCY=%u\n",
5955 si.current_signal, si.current_txrate / 1000,
5956 si.current_noise, si.frequency);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005957 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005958 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005959 pos += ret;
5960
5961 if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
5962 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005963 channel_width_to_string(si.chanwidth));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005964 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005965 return -1;
5966 pos += ret;
5967 }
5968
5969 if (si.center_frq1 > 0 && si.center_frq2 > 0) {
5970 ret = os_snprintf(pos, end - pos,
5971 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
5972 si.center_frq1, si.center_frq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005973 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005974 return -1;
5975 pos += ret;
5976 }
5977
5978 if (si.avg_signal) {
5979 ret = os_snprintf(pos, end - pos,
5980 "AVG_RSSI=%d\n", si.avg_signal);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005981 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005982 return -1;
5983 pos += ret;
5984 }
5985
5986 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005987}
5988
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03005989
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07005990static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
5991 size_t buflen)
5992{
5993 struct hostap_sta_driver_data sta;
5994 int ret;
5995
5996 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
5997 if (ret)
5998 return -1;
5999
6000 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03006001 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006002 if (os_snprintf_error(buflen, ret))
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07006003 return -1;
6004 return ret;
6005}
6006
6007
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006008#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07006009static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
6010 char *buf, size_t buflen)
6011{
6012 int ret;
6013
6014 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
Dmitry Shmidt9432e122013-09-12 12:39:30 -07006015 if (ret == 0) {
6016 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
6017 struct p2p_data *p2p = wpa_s->global->p2p;
6018 if (p2p) {
6019 char country[3];
6020 country[0] = cmd[8];
6021 country[1] = cmd[9];
6022 country[2] = 0x04;
6023 p2p_set_country(p2p, country);
6024 }
6025 }
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08006026 ret = os_snprintf(buf, buflen, "%s\n", "OK");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006027 if (os_snprintf_error(buflen, ret))
6028 ret = -1;
Dmitry Shmidt9432e122013-09-12 12:39:30 -07006029 }
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07006030 return ret;
6031}
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08006032#endif /* ANDROID */
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07006033
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07006034
Dmitry Shmidta38abf92014-03-06 13:38:44 -08006035static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
6036 char *buf, size_t buflen)
6037{
6038 int ret;
6039 char *pos;
6040 u8 *data = NULL;
6041 unsigned int vendor_id, subcmd;
6042 struct wpabuf *reply;
6043 size_t data_len = 0;
6044
6045 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
6046 vendor_id = strtoul(cmd, &pos, 16);
6047 if (!isblank(*pos))
6048 return -EINVAL;
6049
6050 subcmd = strtoul(pos, &pos, 10);
6051
6052 if (*pos != '\0') {
6053 if (!isblank(*pos++))
6054 return -EINVAL;
6055 data_len = os_strlen(pos);
6056 }
6057
6058 if (data_len) {
6059 data_len /= 2;
6060 data = os_malloc(data_len);
6061 if (!data)
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006062 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08006063
6064 if (hexstr2bin(pos, data, data_len)) {
6065 wpa_printf(MSG_DEBUG,
6066 "Vendor command: wrong parameter format");
6067 os_free(data);
6068 return -EINVAL;
6069 }
6070 }
6071
6072 reply = wpabuf_alloc((buflen - 1) / 2);
6073 if (!reply) {
6074 os_free(data);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006075 return -1;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08006076 }
6077
6078 ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
6079 reply);
6080
6081 if (ret == 0)
6082 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
6083 wpabuf_len(reply));
6084
6085 wpabuf_free(reply);
6086 os_free(data);
6087
6088 return ret;
6089}
6090
6091
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006092static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
6093{
6094 wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
6095
6096#ifdef CONFIG_P2P
Dmitry Shmidt21de2142014-04-08 10:50:52 -07006097 wpas_p2p_cancel(wpa_s);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006098 wpas_p2p_stop_find(wpa_s);
6099 p2p_ctrl_flush(wpa_s);
6100 wpas_p2p_group_remove(wpa_s, "*");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006101 wpas_p2p_service_flush(wpa_s);
6102 wpa_s->global->p2p_disabled = 0;
6103 wpa_s->global->p2p_per_sta_psk = 0;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08006104 wpa_s->conf->num_sec_device_types = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08006105 wpa_s->p2p_disable_ip_addr_req = 0;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006106 os_free(wpa_s->global->p2p_go_avoid_freq.range);
6107 wpa_s->global->p2p_go_avoid_freq.range = NULL;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006108#endif /* CONFIG_P2P */
6109
6110#ifdef CONFIG_WPS_TESTING
6111 wps_version_number = 0x20;
6112 wps_testing_dummy_cred = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08006113 wps_corrupt_pkhash = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006114#endif /* CONFIG_WPS_TESTING */
6115#ifdef CONFIG_WPS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006116 wpa_s->wps_fragment_size = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006117 wpas_wps_cancel(wpa_s);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006118 wps_registrar_flush(wpa_s->wps->registrar);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006119#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07006120 wpa_s->after_wps = 0;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07006121 wpa_s->known_wps_freq = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006122
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006123#ifdef CONFIG_TDLS
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006124#ifdef CONFIG_TDLS_TESTING
6125 extern unsigned int tdls_testing;
6126 tdls_testing = 0;
6127#endif /* CONFIG_TDLS_TESTING */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006128 wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
6129 wpa_tdls_enable(wpa_s->wpa, 1);
6130#endif /* CONFIG_TDLS */
6131
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006132 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
6133 wpa_supplicant_stop_countermeasures(wpa_s, NULL);
6134
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006135 wpa_s->no_keep_alive = 0;
6136
6137 os_free(wpa_s->disallow_aps_bssid);
6138 wpa_s->disallow_aps_bssid = NULL;
6139 wpa_s->disallow_aps_bssid_count = 0;
6140 os_free(wpa_s->disallow_aps_ssid);
6141 wpa_s->disallow_aps_ssid = NULL;
6142 wpa_s->disallow_aps_ssid_count = 0;
6143
6144 wpa_s->set_sta_uapsd = 0;
6145 wpa_s->sta_uapsd = 0;
6146
6147 wpa_drv_radio_disable(wpa_s, 0);
6148
6149 wpa_bss_flush(wpa_s);
6150 wpa_blacklist_clear(wpa_s);
Dmitry Shmidt4b060592013-04-29 16:42:49 -07006151 wpa_s->extra_blacklist_count = 0;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006152 wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
6153 wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
Dmitry Shmidt344abd32014-01-14 13:17:00 -08006154 wpa_config_flush_blobs(wpa_s->conf);
Dmitry Shmidt18463232014-01-24 12:29:41 -08006155 wpa_s->conf->auto_interworking = 0;
6156 wpa_s->conf->okc = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006157
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006158 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
6159 rsn_preauth_deinit(wpa_s->wpa);
6160
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006161 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
6162 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
6163 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
6164 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
6165
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08006166 radio_remove_works(wpa_s, NULL, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006167 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006168
6169 wpa_s->next_ssid = NULL;
6170
6171#ifdef CONFIG_INTERWORKING
6172 hs20_cancel_fetch_osu(wpa_s);
6173#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt818ea482014-03-10 13:15:21 -07006174
6175 wpa_s->ext_mgmt_frame_handling = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006176 wpa_s->ext_eapol_frame_io = 0;
6177#ifdef CONFIG_TESTING_OPTIONS
6178 wpa_s->extra_roc_dur = 0;
6179#endif /* CONFIG_TESTING_OPTIONS */
6180
6181 wpa_s->disconnected = 0;
6182 os_free(wpa_s->next_scan_freqs);
6183 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006184}
6185
6186
6187static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
6188 char *buf, size_t buflen)
6189{
6190 struct wpa_radio_work *work;
6191 char *pos, *end;
6192 struct os_reltime now, diff;
6193
6194 pos = buf;
6195 end = buf + buflen;
6196
6197 os_get_reltime(&now);
6198
6199 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
6200 {
6201 int ret;
6202
6203 os_reltime_sub(&now, &work->time, &diff);
6204 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
6205 work->type, work->wpa_s->ifname, work->freq,
6206 work->started, diff.sec, diff.usec);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006207 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006208 break;
6209 pos += ret;
6210 }
6211
6212 return pos - buf;
6213}
6214
6215
6216static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
6217{
6218 struct wpa_radio_work *work = eloop_ctx;
6219 struct wpa_external_work *ework = work->ctx;
6220
6221 wpa_dbg(work->wpa_s, MSG_DEBUG,
6222 "Timing out external radio work %u (%s)",
6223 ework->id, work->type);
6224 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006225 work->wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006226 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07006227 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006228}
6229
6230
6231static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
6232{
6233 struct wpa_external_work *ework = work->ctx;
6234
6235 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08006236 if (work->started)
6237 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
6238 work, NULL);
6239
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006240 os_free(ework);
6241 return;
6242 }
6243
6244 wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
6245 ework->id, ework->type);
6246 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006247 work->wpa_s->ext_work_in_progress = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006248 if (!ework->timeout)
6249 ework->timeout = 10;
6250 eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
6251 work, NULL);
6252}
6253
6254
6255static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
6256 char *buf, size_t buflen)
6257{
6258 struct wpa_external_work *ework;
6259 char *pos, *pos2;
6260 size_t type_len;
6261 int ret;
6262 unsigned int freq = 0;
6263
6264 /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
6265
6266 ework = os_zalloc(sizeof(*ework));
6267 if (ework == NULL)
6268 return -1;
6269
6270 pos = os_strchr(cmd, ' ');
6271 if (pos) {
6272 type_len = pos - cmd;
6273 pos++;
6274
6275 pos2 = os_strstr(pos, "freq=");
6276 if (pos2)
6277 freq = atoi(pos2 + 5);
6278
6279 pos2 = os_strstr(pos, "timeout=");
6280 if (pos2)
6281 ework->timeout = atoi(pos2 + 8);
6282 } else {
6283 type_len = os_strlen(cmd);
6284 }
6285 if (4 + type_len >= sizeof(ework->type))
6286 type_len = sizeof(ework->type) - 4 - 1;
6287 os_strlcpy(ework->type, "ext:", sizeof(ework->type));
6288 os_memcpy(ework->type + 4, cmd, type_len);
6289 ework->type[4 + type_len] = '\0';
6290
6291 wpa_s->ext_work_id++;
6292 if (wpa_s->ext_work_id == 0)
6293 wpa_s->ext_work_id++;
6294 ework->id = wpa_s->ext_work_id;
6295
6296 if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
6297 ework) < 0) {
6298 os_free(ework);
6299 return -1;
6300 }
6301
6302 ret = os_snprintf(buf, buflen, "%u", ework->id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006303 if (os_snprintf_error(buflen, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006304 return -1;
6305 return ret;
6306}
6307
6308
6309static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
6310{
6311 struct wpa_radio_work *work;
6312 unsigned int id = atoi(cmd);
6313
6314 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
6315 {
6316 struct wpa_external_work *ework;
6317
6318 if (os_strncmp(work->type, "ext:", 4) != 0)
6319 continue;
6320 ework = work->ctx;
6321 if (id && ework->id != id)
6322 continue;
6323 wpa_dbg(wpa_s, MSG_DEBUG,
6324 "Completed external radio work %u (%s)",
6325 ework->id, ework->type);
6326 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006327 wpa_s->ext_work_in_progress = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006328 radio_work_done(work);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006329 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006330 return 3; /* "OK\n" */
6331 }
6332
6333 return -1;
6334}
6335
6336
6337static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
6338 char *buf, size_t buflen)
6339{
6340 if (os_strcmp(cmd, "show") == 0)
6341 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
6342 if (os_strncmp(cmd, "add ", 4) == 0)
6343 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
6344 if (os_strncmp(cmd, "done ", 5) == 0)
6345 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
6346 return -1;
6347}
6348
6349
6350void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
6351{
6352 struct wpa_radio_work *work, *tmp;
6353
Dmitry Shmidt18463232014-01-24 12:29:41 -08006354 if (!wpa_s || !wpa_s->radio)
6355 return;
6356
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006357 dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
6358 struct wpa_radio_work, list) {
6359 struct wpa_external_work *ework;
6360
6361 if (os_strncmp(work->type, "ext:", 4) != 0)
6362 continue;
6363 ework = work->ctx;
6364 wpa_dbg(wpa_s, MSG_DEBUG,
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07006365 "Flushing%s external radio work %u (%s)",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006366 work->started ? " started" : "", ework->id,
6367 ework->type);
6368 if (work->started)
6369 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
6370 work, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006371 radio_work_done(work);
Dmitry Shmidt71757432014-06-02 13:50:35 -07006372 os_free(ework);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006373 }
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006374}
6375
6376
Dmitry Shmidt051af732013-10-22 13:52:46 -07006377static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
6378{
6379 struct wpa_supplicant *wpa_s = eloop_ctx;
6380 eapol_sm_notify_ctrl_response(wpa_s->eapol);
6381}
6382
6383
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006384static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
6385 unsigned int *scan_id_count, int scan_id[])
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006386{
6387 const char *pos = value;
6388
6389 while (pos) {
6390 if (*pos == ' ' || *pos == '\0')
6391 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006392 if (*scan_id_count == MAX_SCAN_ID)
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006393 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006394 scan_id[(*scan_id_count)++] = atoi(pos);
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006395 pos = os_strchr(pos, ',');
6396 if (pos)
6397 pos++;
6398 }
6399
6400 return 0;
6401}
6402
6403
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006404static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
6405 char *reply, int reply_size, int *reply_len)
6406{
6407 char *pos;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006408 unsigned int manual_scan_passive = 0;
6409 unsigned int manual_scan_use_id = 0;
6410 unsigned int manual_scan_only_new = 0;
6411 unsigned int scan_only = 0;
6412 unsigned int scan_id_count = 0;
6413 int scan_id[MAX_SCAN_ID];
6414 void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
6415 struct wpa_scan_results *scan_res);
6416 int *manual_scan_freqs = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006417
6418 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
6419 *reply_len = -1;
6420 return;
6421 }
6422
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006423 if (radio_work_pending(wpa_s, "scan")) {
6424 wpa_printf(MSG_DEBUG,
6425 "Pending scan scheduled - reject new request");
6426 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
6427 return;
6428 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006429
6430 if (params) {
6431 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006432 scan_only = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006433
6434 pos = os_strstr(params, "freq=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006435 if (pos) {
6436 manual_scan_freqs = freq_range_to_channel_list(wpa_s,
6437 pos + 5);
6438 if (manual_scan_freqs == NULL) {
6439 *reply_len = -1;
6440 goto done;
6441 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006442 }
6443
6444 pos = os_strstr(params, "passive=");
6445 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006446 manual_scan_passive = !!atoi(pos + 8);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006447
6448 pos = os_strstr(params, "use_id=");
6449 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006450 manual_scan_use_id = atoi(pos + 7);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006451
6452 pos = os_strstr(params, "only_new=1");
6453 if (pos)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006454 manual_scan_only_new = 1;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006455
6456 pos = os_strstr(params, "scan_id=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006457 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
6458 scan_id) < 0) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006459 *reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006460 goto done;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07006461 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006462 }
6463
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006464 if (scan_only)
6465 scan_res_handler = scan_only_handler;
6466 else if (wpa_s->scan_res_handler == scan_only_handler)
6467 scan_res_handler = NULL;
6468 else
6469 scan_res_handler = wpa_s->scan_res_handler;
6470
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006471 if (!wpa_s->sched_scanning && !wpa_s->scanning &&
6472 ((wpa_s->wpa_state <= WPA_SCANNING) ||
6473 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006474 wpa_s->manual_scan_passive = manual_scan_passive;
6475 wpa_s->manual_scan_use_id = manual_scan_use_id;
6476 wpa_s->manual_scan_only_new = manual_scan_only_new;
6477 wpa_s->scan_id_count = scan_id_count;
6478 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
6479 wpa_s->scan_res_handler = scan_res_handler;
6480 os_free(wpa_s->manual_scan_freqs);
6481 wpa_s->manual_scan_freqs = manual_scan_freqs;
6482 manual_scan_freqs = NULL;
6483
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006484 wpa_s->normal_scans = 0;
6485 wpa_s->scan_req = MANUAL_SCAN_REQ;
6486 wpa_s->after_wps = 0;
6487 wpa_s->known_wps_freq = 0;
6488 wpa_supplicant_req_scan(wpa_s, 0, 0);
6489 if (wpa_s->manual_scan_use_id) {
6490 wpa_s->manual_scan_id++;
6491 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
6492 wpa_s->manual_scan_id);
6493 *reply_len = os_snprintf(reply, reply_size, "%u\n",
6494 wpa_s->manual_scan_id);
6495 }
6496 } else if (wpa_s->sched_scanning) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006497 wpa_s->manual_scan_passive = manual_scan_passive;
6498 wpa_s->manual_scan_use_id = manual_scan_use_id;
6499 wpa_s->manual_scan_only_new = manual_scan_only_new;
6500 wpa_s->scan_id_count = scan_id_count;
6501 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
6502 wpa_s->scan_res_handler = scan_res_handler;
6503 os_free(wpa_s->manual_scan_freqs);
6504 wpa_s->manual_scan_freqs = manual_scan_freqs;
6505 manual_scan_freqs = NULL;
6506
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006507 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
6508 wpa_supplicant_cancel_sched_scan(wpa_s);
6509 wpa_s->scan_req = MANUAL_SCAN_REQ;
6510 wpa_supplicant_req_scan(wpa_s, 0, 0);
6511 if (wpa_s->manual_scan_use_id) {
6512 wpa_s->manual_scan_id++;
6513 *reply_len = os_snprintf(reply, reply_size, "%u\n",
6514 wpa_s->manual_scan_id);
6515 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
6516 wpa_s->manual_scan_id);
6517 }
6518 } else {
6519 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
6520 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
6521 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006522
6523done:
6524 os_free(manual_scan_freqs);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006525}
6526
6527
Dmitry Shmidt818ea482014-03-10 13:15:21 -07006528#ifdef CONFIG_TESTING_OPTIONS
6529
6530static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
6531 unsigned int freq, const u8 *dst,
6532 const u8 *src, const u8 *bssid,
6533 const u8 *data, size_t data_len,
6534 enum offchannel_send_action_result
6535 result)
6536{
6537 wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
6538 " src=" MACSTR " bssid=" MACSTR " result=%s",
6539 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
6540 result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
6541 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
6542 "NO_ACK" : "FAILED"));
6543}
6544
6545
6546static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
6547{
6548 char *pos, *param;
6549 size_t len;
6550 u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
6551 int res, used;
6552 int freq = 0, no_cck = 0, wait_time = 0;
6553
6554 /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
6555 * <action=Action frame payload> */
6556
6557 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
6558
6559 pos = cmd;
6560 used = hwaddr_aton2(pos, da);
6561 if (used < 0)
6562 return -1;
6563 pos += used;
6564 while (*pos == ' ')
6565 pos++;
6566 used = hwaddr_aton2(pos, bssid);
6567 if (used < 0)
6568 return -1;
6569 pos += used;
6570
6571 param = os_strstr(pos, " freq=");
6572 if (param) {
6573 param += 6;
6574 freq = atoi(param);
6575 }
6576
6577 param = os_strstr(pos, " no_cck=");
6578 if (param) {
6579 param += 8;
6580 no_cck = atoi(param);
6581 }
6582
6583 param = os_strstr(pos, " wait_time=");
6584 if (param) {
6585 param += 11;
6586 wait_time = atoi(param);
6587 }
6588
6589 param = os_strstr(pos, " action=");
6590 if (param == NULL)
6591 return -1;
6592 param += 8;
6593
6594 len = os_strlen(param);
6595 if (len & 1)
6596 return -1;
6597 len /= 2;
6598
6599 buf = os_malloc(len);
6600 if (buf == NULL)
6601 return -1;
6602
6603 if (hexstr2bin(param, buf, len) < 0) {
6604 os_free(buf);
6605 return -1;
6606 }
6607
6608 res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
6609 buf, len, wait_time,
6610 wpas_ctrl_iface_mgmt_tx_cb, no_cck);
6611 os_free(buf);
6612 return res;
6613}
6614
6615
6616static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
6617{
6618 wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
6619 offchannel_send_action_done(wpa_s);
6620}
6621
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07006622
6623static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
6624{
6625 char *pos, *param;
6626 union wpa_event_data event;
6627 enum wpa_event_type ev;
6628
6629 /* <event name> [parameters..] */
6630
6631 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
6632
6633 pos = cmd;
6634 param = os_strchr(pos, ' ');
6635 if (param)
6636 *param++ = '\0';
6637
6638 os_memset(&event, 0, sizeof(event));
6639
6640 if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
6641 ev = EVENT_INTERFACE_ENABLED;
6642 } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
6643 ev = EVENT_INTERFACE_DISABLED;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006644 } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
6645 ev = EVENT_AVOID_FREQUENCIES;
6646 if (param == NULL)
6647 param = "";
6648 if (freq_range_list_parse(&event.freq_range, param) < 0)
6649 return -1;
6650 wpa_supplicant_event(wpa_s, ev, &event);
6651 os_free(event.freq_range.range);
6652 return 0;
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07006653 } else {
6654 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
6655 cmd);
6656 return -1;
6657 }
6658
6659 wpa_supplicant_event(wpa_s, ev, &event);
6660
6661 return 0;
6662}
6663
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006664
6665static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
6666{
6667 char *pos;
6668 u8 src[ETH_ALEN], *buf;
6669 int used;
6670 size_t len;
6671
6672 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
6673
6674 pos = cmd;
6675 used = hwaddr_aton2(pos, src);
6676 if (used < 0)
6677 return -1;
6678 pos += used;
6679 while (*pos == ' ')
6680 pos++;
6681
6682 len = os_strlen(pos);
6683 if (len & 1)
6684 return -1;
6685 len /= 2;
6686
6687 buf = os_malloc(len);
6688 if (buf == NULL)
6689 return -1;
6690
6691 if (hexstr2bin(pos, buf, len) < 0) {
6692 os_free(buf);
6693 return -1;
6694 }
6695
6696 wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
6697 os_free(buf);
6698
6699 return 0;
6700}
6701
6702
6703static u16 ipv4_hdr_checksum(const void *buf, size_t len)
6704{
6705 size_t i;
6706 u32 sum = 0;
6707 const u16 *pos = buf;
6708
6709 for (i = 0; i < len / 2; i++)
6710 sum += *pos++;
6711
6712 while (sum >> 16)
6713 sum = (sum & 0xffff) + (sum >> 16);
6714
6715 return sum ^ 0xffff;
6716}
6717
6718
6719#define HWSIM_PACKETLEN 1500
6720#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
6721
6722void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
6723{
6724 struct wpa_supplicant *wpa_s = ctx;
6725 const struct ether_header *eth;
6726 const struct iphdr *ip;
6727 const u8 *pos;
6728 unsigned int i;
6729
6730 if (len != HWSIM_PACKETLEN)
6731 return;
6732
6733 eth = (const struct ether_header *) buf;
6734 ip = (const struct iphdr *) (eth + 1);
6735 pos = (const u8 *) (ip + 1);
6736
6737 if (ip->ihl != 5 || ip->version != 4 ||
6738 ntohs(ip->tot_len) != HWSIM_IP_LEN)
6739 return;
6740
6741 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
6742 if (*pos != (u8) i)
6743 return;
6744 pos++;
6745 }
6746
6747 wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
6748 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
6749}
6750
6751
6752static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
6753 char *cmd)
6754{
6755 int enabled = atoi(cmd);
6756
6757 if (!enabled) {
6758 if (wpa_s->l2_test) {
6759 l2_packet_deinit(wpa_s->l2_test);
6760 wpa_s->l2_test = NULL;
6761 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
6762 }
6763 return 0;
6764 }
6765
6766 if (wpa_s->l2_test)
6767 return 0;
6768
6769 wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
6770 ETHERTYPE_IP, wpas_data_test_rx,
6771 wpa_s, 1);
6772 if (wpa_s->l2_test == NULL)
6773 return -1;
6774
6775 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
6776
6777 return 0;
6778}
6779
6780
6781static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
6782{
6783 u8 dst[ETH_ALEN], src[ETH_ALEN];
6784 char *pos;
6785 int used;
6786 long int val;
6787 u8 tos;
6788 u8 buf[HWSIM_PACKETLEN];
6789 struct ether_header *eth;
6790 struct iphdr *ip;
6791 u8 *dpos;
6792 unsigned int i;
6793
6794 if (wpa_s->l2_test == NULL)
6795 return -1;
6796
6797 /* format: <dst> <src> <tos> */
6798
6799 pos = cmd;
6800 used = hwaddr_aton2(pos, dst);
6801 if (used < 0)
6802 return -1;
6803 pos += used;
6804 while (*pos == ' ')
6805 pos++;
6806 used = hwaddr_aton2(pos, src);
6807 if (used < 0)
6808 return -1;
6809 pos += used;
6810
6811 val = strtol(pos, NULL, 0);
6812 if (val < 0 || val > 0xff)
6813 return -1;
6814 tos = val;
6815
6816 eth = (struct ether_header *) buf;
6817 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
6818 os_memcpy(eth->ether_shost, src, ETH_ALEN);
6819 eth->ether_type = htons(ETHERTYPE_IP);
6820 ip = (struct iphdr *) (eth + 1);
6821 os_memset(ip, 0, sizeof(*ip));
6822 ip->ihl = 5;
6823 ip->version = 4;
6824 ip->ttl = 64;
6825 ip->tos = tos;
6826 ip->tot_len = htons(HWSIM_IP_LEN);
6827 ip->protocol = 1;
6828 ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
6829 ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
6830 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
6831 dpos = (u8 *) (ip + 1);
6832 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
6833 *dpos++ = i;
6834
6835 if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
6836 HWSIM_PACKETLEN) < 0)
6837 return -1;
6838
6839 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
6840 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
6841
6842 return 0;
6843}
6844
6845
6846static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
6847 char *cmd)
6848{
6849 u8 *buf;
6850 struct ether_header *eth;
6851 struct l2_packet_data *l2 = NULL;
6852 size_t len;
6853 u16 ethertype;
6854 int res = -1;
6855
6856 len = os_strlen(cmd);
6857 if (len & 1 || len < ETH_HLEN * 2)
6858 return -1;
6859 len /= 2;
6860
6861 buf = os_malloc(len);
6862 if (buf == NULL)
6863 return -1;
6864
6865 if (hexstr2bin(cmd, buf, len) < 0)
6866 goto done;
6867
6868 eth = (struct ether_header *) buf;
6869 ethertype = ntohs(eth->ether_type);
6870
6871 l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
6872 wpas_data_test_rx, wpa_s, 1);
6873 if (l2 == NULL)
6874 goto done;
6875
6876 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
6877 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
6878done:
6879 if (l2)
6880 l2_packet_deinit(l2);
6881 os_free(buf);
6882
6883 return res < 0 ? -1 : 0;
6884}
6885
Dmitry Shmidtff787d52015-01-12 13:01:47 -08006886
6887static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
6888{
6889#ifdef WPA_TRACE_BFD
6890 extern char wpa_trace_fail_func[256];
6891 extern unsigned int wpa_trace_fail_after;
6892 char *pos;
6893
6894 wpa_trace_fail_after = atoi(cmd);
6895 pos = os_strchr(cmd, ':');
6896 if (pos) {
6897 pos++;
6898 os_strlcpy(wpa_trace_fail_func, pos,
6899 sizeof(wpa_trace_fail_func));
6900 } else {
6901 wpa_trace_fail_after = 0;
6902 }
6903 return 0;
6904#else /* WPA_TRACE_BFD */
6905 return -1;
6906#endif /* WPA_TRACE_BFD */
6907}
6908
6909
6910static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
6911 char *buf, size_t buflen)
6912{
6913#ifdef WPA_TRACE_BFD
6914 extern char wpa_trace_fail_func[256];
6915 extern unsigned int wpa_trace_fail_after;
6916
6917 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
6918 wpa_trace_fail_func);
6919#else /* WPA_TRACE_BFD */
6920 return -1;
6921#endif /* WPA_TRACE_BFD */
6922}
6923
Dmitry Shmidt818ea482014-03-10 13:15:21 -07006924#endif /* CONFIG_TESTING_OPTIONS */
6925
6926
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07006927static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
6928{
6929 unsigned int i;
6930 char buf[30];
6931
6932 wpa_printf(MSG_DEBUG, "Update vendor elements");
6933
6934 for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
6935 if (wpa_s->vendor_elem[i]) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006936 int res;
6937
6938 res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
6939 if (!os_snprintf_error(sizeof(buf), res)) {
6940 wpa_hexdump_buf(MSG_DEBUG, buf,
6941 wpa_s->vendor_elem[i]);
6942 }
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07006943 }
6944 }
6945
6946#ifdef CONFIG_P2P
6947 if (wpa_s->parent == wpa_s &&
6948 wpa_s->global->p2p &&
6949 !wpa_s->global->p2p_disabled)
6950 p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
6951#endif /* CONFIG_P2P */
6952}
6953
6954
6955static struct wpa_supplicant *
6956wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
6957 enum wpa_vendor_elem_frame frame)
6958{
6959 switch (frame) {
6960#ifdef CONFIG_P2P
6961 case VENDOR_ELEM_PROBE_REQ_P2P:
6962 case VENDOR_ELEM_PROBE_RESP_P2P:
6963 case VENDOR_ELEM_PROBE_RESP_P2P_GO:
6964 case VENDOR_ELEM_BEACON_P2P_GO:
6965 case VENDOR_ELEM_P2P_PD_REQ:
6966 case VENDOR_ELEM_P2P_PD_RESP:
6967 case VENDOR_ELEM_P2P_GO_NEG_REQ:
6968 case VENDOR_ELEM_P2P_GO_NEG_RESP:
6969 case VENDOR_ELEM_P2P_GO_NEG_CONF:
6970 case VENDOR_ELEM_P2P_INV_REQ:
6971 case VENDOR_ELEM_P2P_INV_RESP:
6972 case VENDOR_ELEM_P2P_ASSOC_REQ:
6973 return wpa_s->parent;
6974#endif /* CONFIG_P2P */
6975 default:
6976 return wpa_s;
6977 }
6978}
6979
6980
6981static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
6982{
6983 char *pos = cmd;
6984 int frame;
6985 size_t len;
6986 struct wpabuf *buf;
6987 struct ieee802_11_elems elems;
6988
6989 frame = atoi(pos);
6990 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
6991 return -1;
6992 wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
6993
6994 pos = os_strchr(pos, ' ');
6995 if (pos == NULL)
6996 return -1;
6997 pos++;
6998
6999 len = os_strlen(pos);
7000 if (len == 0)
7001 return 0;
7002 if (len & 1)
7003 return -1;
7004 len /= 2;
7005
7006 buf = wpabuf_alloc(len);
7007 if (buf == NULL)
7008 return -1;
7009
7010 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
7011 wpabuf_free(buf);
7012 return -1;
7013 }
7014
7015 if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
7016 ParseFailed) {
7017 wpabuf_free(buf);
7018 return -1;
7019 }
7020
7021 if (wpa_s->vendor_elem[frame] == NULL) {
7022 wpa_s->vendor_elem[frame] = buf;
7023 wpas_ctrl_vendor_elem_update(wpa_s);
7024 return 0;
7025 }
7026
7027 if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
7028 wpabuf_free(buf);
7029 return -1;
7030 }
7031
7032 wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
7033 wpabuf_free(buf);
7034 wpas_ctrl_vendor_elem_update(wpa_s);
7035
7036 return 0;
7037}
7038
7039
7040static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
7041 char *buf, size_t buflen)
7042{
7043 int frame = atoi(cmd);
7044
7045 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
7046 return -1;
7047 wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
7048
7049 if (wpa_s->vendor_elem[frame] == NULL)
7050 return 0;
7051
7052 return wpa_snprintf_hex(buf, buflen,
7053 wpabuf_head_u8(wpa_s->vendor_elem[frame]),
7054 wpabuf_len(wpa_s->vendor_elem[frame]));
7055}
7056
7057
7058static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
7059{
7060 char *pos = cmd;
7061 int frame;
7062 size_t len;
7063 u8 *buf;
7064 struct ieee802_11_elems elems;
7065 u8 *ie, *end;
7066
7067 frame = atoi(pos);
7068 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
7069 return -1;
7070 wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
7071
7072 pos = os_strchr(pos, ' ');
7073 if (pos == NULL)
7074 return -1;
7075 pos++;
7076
7077 if (*pos == '*') {
7078 wpabuf_free(wpa_s->vendor_elem[frame]);
7079 wpa_s->vendor_elem[frame] = NULL;
7080 wpas_ctrl_vendor_elem_update(wpa_s);
7081 return 0;
7082 }
7083
7084 if (wpa_s->vendor_elem[frame] == NULL)
7085 return -1;
7086
7087 len = os_strlen(pos);
7088 if (len == 0)
7089 return 0;
7090 if (len & 1)
7091 return -1;
7092 len /= 2;
7093
7094 buf = os_malloc(len);
7095 if (buf == NULL)
7096 return -1;
7097
7098 if (hexstr2bin(pos, buf, len) < 0) {
7099 os_free(buf);
7100 return -1;
7101 }
7102
7103 if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
7104 os_free(buf);
7105 return -1;
7106 }
7107
7108 ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
7109 end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
7110
7111 for (; ie + 1 < end; ie += 2 + ie[1]) {
7112 if (ie + len > end)
7113 break;
7114 if (os_memcmp(ie, buf, len) != 0)
7115 continue;
7116
7117 if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
7118 wpabuf_free(wpa_s->vendor_elem[frame]);
7119 wpa_s->vendor_elem[frame] = NULL;
7120 } else {
7121 os_memmove(ie, ie + len,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07007122 end - (ie + len));
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07007123 wpa_s->vendor_elem[frame]->used -= len;
7124 }
7125 os_free(buf);
7126 wpas_ctrl_vendor_elem_update(wpa_s);
7127 return 0;
7128 }
7129
7130 os_free(buf);
7131
7132 return -1;
7133}
7134
7135
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007136static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
7137{
7138 struct wpa_supplicant *wpa_s = ctx;
7139
7140 if (neighbor_rep) {
7141 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
7142 "length=%u",
7143 (unsigned int) wpabuf_len(neighbor_rep));
7144 wpabuf_free(neighbor_rep);
7145 } else {
7146 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
7147 }
7148}
7149
7150
7151static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
7152 char *cmd)
7153{
7154 struct wpa_ssid ssid;
7155 struct wpa_ssid *ssid_p = NULL;
7156 int ret = 0;
7157
7158 if (os_strncmp(cmd, " ssid=", 6) == 0) {
7159 ssid.ssid_len = os_strlen(cmd + 6);
7160 if (ssid.ssid_len > 32)
7161 return -1;
7162 ssid.ssid = (u8 *) (cmd + 6);
7163 ssid_p = &ssid;
7164 }
7165
7166 ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
7167 wpas_ctrl_neighbor_rep_cb,
7168 wpa_s);
7169
7170 return ret;
7171}
7172
7173
7174static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
7175{
7176 eapol_sm_erp_flush(wpa_s->eapol);
7177 return 0;
7178}
7179
7180
7181static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
7182 char *cmd)
7183{
7184 char *token, *context = NULL;
7185 unsigned int enable = ~0, type = 0;
7186 u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
7187 u8 *addr = NULL, *mask = NULL;
7188
7189 while ((token = str_token(cmd, " ", &context))) {
7190 if (os_strcasecmp(token, "scan") == 0) {
7191 type |= MAC_ADDR_RAND_SCAN;
7192 } else if (os_strcasecmp(token, "sched") == 0) {
7193 type |= MAC_ADDR_RAND_SCHED_SCAN;
7194 } else if (os_strcasecmp(token, "pno") == 0) {
7195 type |= MAC_ADDR_RAND_PNO;
7196 } else if (os_strcasecmp(token, "all") == 0) {
7197 type = wpa_s->mac_addr_rand_supported;
7198 } else if (os_strncasecmp(token, "enable=", 7) == 0) {
7199 enable = atoi(token + 7);
7200 } else if (os_strncasecmp(token, "addr=", 5) == 0) {
7201 addr = _addr;
7202 if (hwaddr_aton(token + 5, addr)) {
7203 wpa_printf(MSG_INFO,
7204 "CTRL: Invalid MAC address: %s",
7205 token);
7206 return -1;
7207 }
7208 } else if (os_strncasecmp(token, "mask=", 5) == 0) {
7209 mask = _mask;
7210 if (hwaddr_aton(token + 5, mask)) {
7211 wpa_printf(MSG_INFO,
7212 "CTRL: Invalid MAC address mask: %s",
7213 token);
7214 return -1;
7215 }
7216 } else {
7217 wpa_printf(MSG_INFO,
7218 "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
7219 token);
7220 return -1;
7221 }
7222 }
7223
7224 if (!type) {
7225 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
7226 return -1;
7227 }
7228
7229 if ((wpa_s->mac_addr_rand_supported & type) != type) {
7230 wpa_printf(MSG_INFO,
7231 "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
7232 type, wpa_s->mac_addr_rand_supported);
7233 return -1;
7234 }
7235
7236 if (enable > 1) {
7237 wpa_printf(MSG_INFO,
7238 "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
7239 return -1;
7240 }
7241
7242 if (!enable) {
7243 wpas_mac_addr_rand_scan_clear(wpa_s, type);
7244 if (wpa_s->pno) {
7245 if (type & MAC_ADDR_RAND_PNO) {
7246 wpas_stop_pno(wpa_s);
7247 wpas_start_pno(wpa_s);
7248 }
7249 } else if (wpa_s->sched_scanning &&
7250 (type & MAC_ADDR_RAND_SCHED_SCAN)) {
7251 /* simulate timeout to restart the sched scan */
7252 wpa_s->sched_scan_timed_out = 1;
7253 wpa_s->prev_sched_ssid = NULL;
7254 wpa_supplicant_cancel_sched_scan(wpa_s);
7255 }
7256 return 0;
7257 }
7258
7259 if ((addr && !mask) || (!addr && mask)) {
7260 wpa_printf(MSG_INFO,
7261 "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
7262 return -1;
7263 }
7264
7265 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
7266 wpa_printf(MSG_INFO,
7267 "CTRL: MAC_RAND_SCAN cannot allow multicast address");
7268 return -1;
7269 }
7270
7271 if (type & MAC_ADDR_RAND_SCAN) {
7272 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
7273 addr, mask);
7274 }
7275
7276 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
7277 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
7278 addr, mask);
7279
7280 if (wpa_s->sched_scanning && !wpa_s->pno) {
7281 /* simulate timeout to restart the sched scan */
7282 wpa_s->sched_scan_timed_out = 1;
7283 wpa_s->prev_sched_ssid = NULL;
7284 wpa_supplicant_cancel_sched_scan(wpa_s);
7285 }
7286 }
7287
7288 if (type & MAC_ADDR_RAND_PNO) {
7289 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
7290 addr, mask);
7291 if (wpa_s->pno) {
7292 wpas_stop_pno(wpa_s);
7293 wpas_start_pno(wpa_s);
7294 }
7295 }
7296
7297 return 0;
7298}
7299
7300
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007301char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
7302 char *buf, size_t *resp_len)
7303{
7304 char *reply;
7305 const int reply_size = 4096;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007306 int reply_len;
7307
7308 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007309 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
7310 if (wpa_debug_show_keys)
7311 wpa_dbg(wpa_s, MSG_DEBUG,
7312 "Control interface command '%s'", buf);
7313 else
7314 wpa_dbg(wpa_s, MSG_DEBUG,
7315 "Control interface command '%s [REMOVED]'",
7316 os_strncmp(buf, WPA_CTRL_RSP,
7317 os_strlen(WPA_CTRL_RSP)) == 0 ?
7318 WPA_CTRL_RSP : "SET_NETWORK");
7319 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
Dmitry Shmidt21de2142014-04-08 10:50:52 -07007320 os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007321 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
7322 (const u8 *) buf, os_strlen(buf));
7323 } else {
7324 int level = MSG_DEBUG;
7325 if (os_strcmp(buf, "PING") == 0)
7326 level = MSG_EXCESSIVE;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007327 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007328 }
7329
7330 reply = os_malloc(reply_size);
7331 if (reply == NULL) {
7332 *resp_len = 1;
7333 return NULL;
7334 }
7335
7336 os_memcpy(reply, "OK\n", 3);
7337 reply_len = 3;
7338
7339 if (os_strcmp(buf, "PING") == 0) {
7340 os_memcpy(reply, "PONG\n", 5);
7341 reply_len = 5;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007342 } else if (os_strcmp(buf, "IFNAME") == 0) {
7343 reply_len = os_strlen(wpa_s->ifname);
7344 os_memcpy(reply, wpa_s->ifname, reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007345 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
7346 if (wpa_debug_reopen_file() < 0)
7347 reply_len = -1;
7348 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
7349 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
7350 } else if (os_strcmp(buf, "MIB") == 0) {
7351 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
7352 if (reply_len >= 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007353 reply_len += eapol_sm_get_mib(wpa_s->eapol,
7354 reply + reply_len,
7355 reply_size - reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007356 }
7357 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
7358 reply_len = wpa_supplicant_ctrl_iface_status(
7359 wpa_s, buf + 6, reply, reply_size);
7360 } else if (os_strcmp(buf, "PMKSA") == 0) {
7361 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
7362 reply_size);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007363 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
7364 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007365 } else if (os_strncmp(buf, "SET ", 4) == 0) {
7366 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
7367 reply_len = -1;
7368 } else if (os_strncmp(buf, "GET ", 4) == 0) {
7369 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
7370 reply, reply_size);
7371 } else if (os_strcmp(buf, "LOGON") == 0) {
7372 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
7373 } else if (os_strcmp(buf, "LOGOFF") == 0) {
7374 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
7375 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
7376 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
7377 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007378 else
7379 wpas_request_connection(wpa_s);
Dmitry Shmidt98660862014-03-11 17:26:21 -07007380 } else if (os_strcmp(buf, "REATTACH") == 0) {
7381 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
7382 !wpa_s->current_ssid)
7383 reply_len = -1;
7384 else {
7385 wpa_s->reattach = 1;
7386 wpas_request_connection(wpa_s);
7387 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007388 } else if (os_strcmp(buf, "RECONNECT") == 0) {
7389 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
7390 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007391 else if (wpa_s->disconnected)
7392 wpas_request_connection(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007393#ifdef IEEE8021X_EAPOL
7394 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
7395 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
7396 reply_len = -1;
7397#endif /* IEEE8021X_EAPOL */
7398#ifdef CONFIG_PEERKEY
7399 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
7400 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
7401 reply_len = -1;
7402#endif /* CONFIG_PEERKEY */
7403#ifdef CONFIG_IEEE80211R
7404 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
7405 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
7406 reply_len = -1;
7407#endif /* CONFIG_IEEE80211R */
7408#ifdef CONFIG_WPS
7409 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
7410 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
7411 if (res == -2) {
7412 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
7413 reply_len = 17;
7414 } else if (res)
7415 reply_len = -1;
7416 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
7417 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
7418 if (res == -2) {
7419 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
7420 reply_len = 17;
7421 } else if (res)
7422 reply_len = -1;
7423 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
7424 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
7425 reply,
7426 reply_size);
7427 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
7428 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
7429 wpa_s, buf + 14, reply, reply_size);
7430 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
7431 if (wpas_wps_cancel(wpa_s))
7432 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007433#ifdef CONFIG_WPS_NFC
7434 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
7435 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
7436 reply_len = -1;
7437 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
7438 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
7439 reply_len = -1;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08007440 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
7441 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
7442 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007443 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
7444 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
7445 wpa_s, buf + 14, reply, reply_size);
7446 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
7447 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
7448 buf + 17))
7449 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007450 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
7451 reply_len = wpas_ctrl_nfc_get_handover_req(
7452 wpa_s, buf + 21, reply, reply_size);
7453 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
7454 reply_len = wpas_ctrl_nfc_get_handover_sel(
7455 wpa_s, buf + 21, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08007456 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
7457 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
7458 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007459#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007460 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
7461 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
7462 reply_len = -1;
7463#ifdef CONFIG_AP
7464 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
7465 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
7466 wpa_s, buf + 11, reply, reply_size);
7467#endif /* CONFIG_AP */
7468#ifdef CONFIG_WPS_ER
7469 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
7470 if (wpas_wps_er_start(wpa_s, NULL))
7471 reply_len = -1;
7472 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
7473 if (wpas_wps_er_start(wpa_s, buf + 13))
7474 reply_len = -1;
7475 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007476 wpas_wps_er_stop(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007477 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
7478 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
7479 reply_len = -1;
7480 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
7481 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
7482 if (ret == -2) {
7483 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
7484 reply_len = 17;
7485 } else if (ret == -3) {
7486 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
7487 reply_len = 18;
7488 } else if (ret == -4) {
7489 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
7490 reply_len = 20;
7491 } else if (ret)
7492 reply_len = -1;
7493 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
7494 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
7495 reply_len = -1;
7496 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
7497 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
7498 buf + 18))
7499 reply_len = -1;
7500 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
7501 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
7502 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007503#ifdef CONFIG_WPS_NFC
7504 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
7505 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
7506 wpa_s, buf + 24, reply, reply_size);
7507#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007508#endif /* CONFIG_WPS_ER */
7509#endif /* CONFIG_WPS */
7510#ifdef CONFIG_IBSS_RSN
7511 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
7512 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
7513 reply_len = -1;
7514#endif /* CONFIG_IBSS_RSN */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007515#ifdef CONFIG_MESH
7516 } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
7517 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
7518 wpa_s, buf + 19, reply, reply_size);
7519 } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
7520 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
7521 wpa_s, "", reply, reply_size);
7522 } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
7523 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
7524 reply_len = -1;
7525 } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
7526 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
7527 buf + 18))
7528 reply_len = -1;
7529#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007530#ifdef CONFIG_P2P
7531 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
7532 if (p2p_ctrl_find(wpa_s, buf + 9))
7533 reply_len = -1;
7534 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
7535 if (p2p_ctrl_find(wpa_s, ""))
7536 reply_len = -1;
7537 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
7538 wpas_p2p_stop_find(wpa_s);
7539 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
7540 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
7541 reply_size);
7542 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
7543 if (p2p_ctrl_listen(wpa_s, buf + 11))
7544 reply_len = -1;
7545 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
7546 if (p2p_ctrl_listen(wpa_s, ""))
7547 reply_len = -1;
7548 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
7549 if (wpas_p2p_group_remove(wpa_s, buf + 17))
7550 reply_len = -1;
7551 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007552 if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007553 reply_len = -1;
7554 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
7555 if (p2p_ctrl_group_add(wpa_s, buf + 14))
7556 reply_len = -1;
7557 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
7558 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
7559 reply_len = -1;
7560 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
7561 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
7562 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
7563 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
7564 reply_size);
7565 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
7566 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
7567 reply_len = -1;
7568 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
7569 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
7570 reply_len = -1;
7571 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
7572 wpas_p2p_sd_service_update(wpa_s);
7573 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
7574 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
7575 reply_len = -1;
7576 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
7577 wpas_p2p_service_flush(wpa_s);
7578 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
7579 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
7580 reply_len = -1;
7581 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
7582 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
7583 reply_len = -1;
7584 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
7585 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
7586 reply_len = -1;
7587 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
7588 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
7589 reply_len = -1;
7590 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
7591 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
7592 reply_size);
7593 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
7594 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
7595 reply_len = -1;
7596 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007597 p2p_ctrl_flush(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007598 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
7599 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
7600 reply_len = -1;
7601 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
7602 if (wpas_p2p_cancel(wpa_s))
7603 reply_len = -1;
7604 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
7605 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
7606 reply_len = -1;
7607 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
7608 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
7609 reply_len = -1;
7610 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
7611 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
7612 reply_len = -1;
7613 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
7614 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
7615 reply_len = -1;
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07007616 } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
7617 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
7618 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007619#endif /* CONFIG_P2P */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007620#ifdef CONFIG_WIFI_DISPLAY
7621 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
7622 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
7623 reply_len = -1;
7624 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
7625 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
7626 reply, reply_size);
7627#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007628#ifdef CONFIG_INTERWORKING
7629 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
7630 if (interworking_fetch_anqp(wpa_s) < 0)
7631 reply_len = -1;
7632 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
7633 interworking_stop_fetch_anqp(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007634 } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
7635 if (ctrl_interworking_select(wpa_s, NULL) < 0)
7636 reply_len = -1;
7637 } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
7638 if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007639 reply_len = -1;
7640 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
7641 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
7642 reply_len = -1;
7643 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
7644 if (get_anqp(wpa_s, buf + 9) < 0)
7645 reply_len = -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007646 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
7647 if (gas_request(wpa_s, buf + 12) < 0)
7648 reply_len = -1;
7649 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
7650 reply_len = gas_response_get(wpa_s, buf + 17, reply,
7651 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007652#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07007653#ifdef CONFIG_HS20
7654 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
7655 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
7656 reply_len = -1;
7657 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
7658 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
7659 reply_len = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08007660 } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
7661 if (hs20_icon_request(wpa_s, buf + 18) < 0)
7662 reply_len = -1;
7663 } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
7664 if (hs20_fetch_osu(wpa_s) < 0)
7665 reply_len = -1;
7666 } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
7667 hs20_cancel_fetch_osu(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007668#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007669 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
7670 {
7671 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
7672 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
7673 reply_len = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07007674 else {
7675 /*
7676 * Notify response from timeout to allow the control
7677 * interface response to be sent first.
7678 */
7679 eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
7680 wpa_s, NULL);
7681 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007682 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
7683 if (wpa_supplicant_reload_configuration(wpa_s))
7684 reply_len = -1;
7685 } else if (os_strcmp(buf, "TERMINATE") == 0) {
7686 wpa_supplicant_terminate_proc(wpa_s->global);
7687 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
7688 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
7689 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -07007690 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007691 reply_len = wpa_supplicant_ctrl_iface_blacklist(
7692 wpa_s, buf + 9, reply, reply_size);
7693 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
7694 reply_len = wpa_supplicant_ctrl_iface_log_level(
7695 wpa_s, buf + 9, reply, reply_size);
Vinit Deshpandeda134e92014-12-02 10:59:29 -08007696 } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
7697 reply_len = wpa_supplicant_ctrl_iface_list_networks(
7698 wpa_s, buf + 14, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007699 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
7700 reply_len = wpa_supplicant_ctrl_iface_list_networks(
Vinit Deshpandeda134e92014-12-02 10:59:29 -08007701 wpa_s, NULL, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007702 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07007703#ifdef CONFIG_SME
7704 wpa_s->sme.prev_bssid_set = 0;
7705#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007706 wpa_s->reassociate = 0;
7707 wpa_s->disconnected = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007708 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007709 wpa_supplicant_cancel_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007710 wpa_supplicant_deauthenticate(wpa_s,
7711 WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007712 } else if (os_strcmp(buf, "SCAN") == 0) {
7713 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
7714 } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
7715 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007716 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
7717 reply_len = wpa_supplicant_ctrl_iface_scan_results(
7718 wpa_s, reply, reply_size);
7719 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
7720 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
7721 reply_len = -1;
7722 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
7723 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
7724 reply_len = -1;
7725 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
7726 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
7727 reply_len = -1;
7728 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
7729 reply_len = wpa_supplicant_ctrl_iface_add_network(
7730 wpa_s, reply, reply_size);
7731 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
7732 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
7733 reply_len = -1;
7734 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
7735 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
7736 reply_len = -1;
7737 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
7738 reply_len = wpa_supplicant_ctrl_iface_get_network(
7739 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt684785c2014-05-12 13:34:29 -07007740 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
7741 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12))
7742 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007743 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
7744 reply_len = wpa_supplicant_ctrl_iface_list_creds(
7745 wpa_s, reply, reply_size);
7746 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
7747 reply_len = wpa_supplicant_ctrl_iface_add_cred(
7748 wpa_s, reply, reply_size);
7749 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
7750 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
7751 reply_len = -1;
7752 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
7753 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
7754 reply_len = -1;
Dmitry Shmidt0cfd5f72014-04-04 14:48:05 -07007755 } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
7756 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
7757 reply,
7758 reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007759#ifndef CONFIG_NO_CONFIG_WRITE
7760 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
7761 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
7762 reply_len = -1;
7763#endif /* CONFIG_NO_CONFIG_WRITE */
7764 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
7765 reply_len = wpa_supplicant_ctrl_iface_get_capability(
7766 wpa_s, buf + 15, reply, reply_size);
7767 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
7768 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
7769 reply_len = -1;
7770 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
7771 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
7772 reply_len = -1;
7773 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
7774 reply_len = wpa_supplicant_global_iface_list(
7775 wpa_s->global, reply, reply_size);
7776 } else if (os_strcmp(buf, "INTERFACES") == 0) {
7777 reply_len = wpa_supplicant_global_iface_interfaces(
7778 wpa_s->global, reply, reply_size);
7779 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
7780 reply_len = wpa_supplicant_ctrl_iface_bss(
7781 wpa_s, buf + 4, reply, reply_size);
7782#ifdef CONFIG_AP
7783 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
7784 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
7785 } else if (os_strncmp(buf, "STA ", 4) == 0) {
7786 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
7787 reply_size);
7788 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
7789 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
7790 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007791 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
7792 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
7793 reply_len = -1;
7794 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
7795 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
7796 reply_len = -1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08007797 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
7798 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
7799 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007800#endif /* CONFIG_AP */
7801 } else if (os_strcmp(buf, "SUSPEND") == 0) {
7802 wpas_notify_suspend(wpa_s->global);
7803 } else if (os_strcmp(buf, "RESUME") == 0) {
7804 wpas_notify_resume(wpa_s->global);
Dmitry Shmidt21de2142014-04-08 10:50:52 -07007805#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007806 } else if (os_strcmp(buf, "DROP_SA") == 0) {
7807 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
Dmitry Shmidt21de2142014-04-08 10:50:52 -07007808#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007809 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
7810 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
7811 reply_len = -1;
7812 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007813 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007814 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
7815 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
7816 reply_len = -1;
7817 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
7818 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
7819 buf + 17))
7820 reply_len = -1;
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07007821 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007822 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007823#ifdef CONFIG_TDLS
7824 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
7825 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
7826 reply_len = -1;
7827 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
7828 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
7829 reply_len = -1;
7830 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
7831 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
7832 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007833 } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
7834 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
7835 buf + 17))
7836 reply_len = -1;
7837 } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
7838 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
7839 buf + 24))
7840 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007841#endif /* CONFIG_TDLS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007842 } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
7843 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
7844 } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
7845 if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
7846 reply_len = -1;
7847 } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
7848 if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
7849 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007850 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
7851 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
7852 reply_size);
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07007853 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
7854 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
7855 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007856#ifdef CONFIG_AUTOSCAN
7857 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
7858 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
7859 reply_len = -1;
7860#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007861#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07007862 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
7863 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
7864 reply_size);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08007865#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007866 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
7867 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
7868 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007869 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007870 pmksa_cache_clear_current(wpa_s->wpa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007871 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007872#ifdef CONFIG_WNM
7873 } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
7874 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
7875 reply_len = -1;
Dmitry Shmidt44c95782013-05-17 09:51:35 -07007876 } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
7877 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
7878 reply_len = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007879#endif /* CONFIG_WNM */
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007880 } else if (os_strcmp(buf, "FLUSH") == 0) {
7881 wpa_supplicant_ctrl_iface_flush(wpa_s);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007882 } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
7883 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
7884 reply_size);
Dmitry Shmidt818ea482014-03-10 13:15:21 -07007885#ifdef CONFIG_TESTING_OPTIONS
7886 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
7887 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
7888 reply_len = -1;
7889 } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
7890 wpas_ctrl_iface_mgmt_tx_done(wpa_s);
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07007891 } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
7892 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
7893 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007894 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
7895 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
7896 reply_len = -1;
7897 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
7898 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
7899 reply_len = -1;
7900 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
7901 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
7902 reply_len = -1;
7903 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
7904 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
7905 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08007906 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
7907 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
7908 reply_len = -1;
7909 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
7910 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
Dmitry Shmidt818ea482014-03-10 13:15:21 -07007911#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt2e67f062014-07-16 09:55:28 -07007912 } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
7913 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
7914 reply_len = -1;
7915 } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
7916 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
7917 reply_size);
7918 } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
7919 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
7920 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007921 } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
7922 if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
7923 reply_len = -1;
7924 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
7925 wpas_ctrl_iface_erp_flush(wpa_s);
7926 } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
7927 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
7928 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007929 } else {
7930 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
7931 reply_len = 16;
7932 }
7933
7934 if (reply_len < 0) {
7935 os_memcpy(reply, "FAIL\n", 5);
7936 reply_len = 5;
7937 }
7938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007939 *resp_len = reply_len;
7940 return reply;
7941}
7942
7943
7944static int wpa_supplicant_global_iface_add(struct wpa_global *global,
7945 char *cmd)
7946{
7947 struct wpa_interface iface;
7948 char *pos;
7949
7950 /*
7951 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
7952 * TAB<bridge_ifname>
7953 */
7954 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
7955
7956 os_memset(&iface, 0, sizeof(iface));
7957
7958 do {
7959 iface.ifname = pos = cmd;
7960 pos = os_strchr(pos, '\t');
7961 if (pos)
7962 *pos++ = '\0';
7963 if (iface.ifname[0] == '\0')
7964 return -1;
7965 if (pos == NULL)
7966 break;
7967
7968 iface.confname = pos;
7969 pos = os_strchr(pos, '\t');
7970 if (pos)
7971 *pos++ = '\0';
7972 if (iface.confname[0] == '\0')
7973 iface.confname = NULL;
7974 if (pos == NULL)
7975 break;
7976
7977 iface.driver = pos;
7978 pos = os_strchr(pos, '\t');
7979 if (pos)
7980 *pos++ = '\0';
7981 if (iface.driver[0] == '\0')
7982 iface.driver = NULL;
7983 if (pos == NULL)
7984 break;
7985
7986 iface.ctrl_interface = pos;
7987 pos = os_strchr(pos, '\t');
7988 if (pos)
7989 *pos++ = '\0';
7990 if (iface.ctrl_interface[0] == '\0')
7991 iface.ctrl_interface = NULL;
7992 if (pos == NULL)
7993 break;
7994
7995 iface.driver_param = pos;
7996 pos = os_strchr(pos, '\t');
7997 if (pos)
7998 *pos++ = '\0';
7999 if (iface.driver_param[0] == '\0')
8000 iface.driver_param = NULL;
8001 if (pos == NULL)
8002 break;
8003
8004 iface.bridge_ifname = pos;
8005 pos = os_strchr(pos, '\t');
8006 if (pos)
8007 *pos++ = '\0';
8008 if (iface.bridge_ifname[0] == '\0')
8009 iface.bridge_ifname = NULL;
8010 if (pos == NULL)
8011 break;
8012 } while (0);
8013
8014 if (wpa_supplicant_get_iface(global, iface.ifname))
8015 return -1;
8016
8017 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
8018}
8019
8020
8021static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
8022 char *cmd)
8023{
8024 struct wpa_supplicant *wpa_s;
8025
8026 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
8027
8028 wpa_s = wpa_supplicant_get_iface(global, cmd);
8029 if (wpa_s == NULL)
8030 return -1;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07008031 return wpa_supplicant_remove_iface(global, wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008032}
8033
8034
8035static void wpa_free_iface_info(struct wpa_interface_info *iface)
8036{
8037 struct wpa_interface_info *prev;
8038
8039 while (iface) {
8040 prev = iface;
8041 iface = iface->next;
8042
8043 os_free(prev->ifname);
8044 os_free(prev->desc);
8045 os_free(prev);
8046 }
8047}
8048
8049
8050static int wpa_supplicant_global_iface_list(struct wpa_global *global,
8051 char *buf, int len)
8052{
8053 int i, res;
8054 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
8055 char *pos, *end;
8056
8057 for (i = 0; wpa_drivers[i]; i++) {
8058 struct wpa_driver_ops *drv = wpa_drivers[i];
8059 if (drv->get_interfaces == NULL)
8060 continue;
8061 tmp = drv->get_interfaces(global->drv_priv[i]);
8062 if (tmp == NULL)
8063 continue;
8064
8065 if (last == NULL)
8066 iface = last = tmp;
8067 else
8068 last->next = tmp;
8069 while (last->next)
8070 last = last->next;
8071 }
8072
8073 pos = buf;
8074 end = buf + len;
8075 for (tmp = iface; tmp; tmp = tmp->next) {
8076 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
8077 tmp->drv_name, tmp->ifname,
8078 tmp->desc ? tmp->desc : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008079 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008080 *pos = '\0';
8081 break;
8082 }
8083 pos += res;
8084 }
8085
8086 wpa_free_iface_info(iface);
8087
8088 return pos - buf;
8089}
8090
8091
8092static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
8093 char *buf, int len)
8094{
8095 int res;
8096 char *pos, *end;
8097 struct wpa_supplicant *wpa_s;
8098
8099 wpa_s = global->ifaces;
8100 pos = buf;
8101 end = buf + len;
8102
8103 while (wpa_s) {
8104 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008105 if (os_snprintf_error(end - pos, res)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008106 *pos = '\0';
8107 break;
8108 }
8109 pos += res;
8110 wpa_s = wpa_s->next;
8111 }
8112 return pos - buf;
8113}
8114
8115
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008116static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
8117 const char *ifname,
8118 char *cmd, size_t *resp_len)
8119{
8120 struct wpa_supplicant *wpa_s;
8121
8122 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8123 if (os_strcmp(ifname, wpa_s->ifname) == 0)
8124 break;
8125 }
8126
8127 if (wpa_s == NULL) {
8128 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
8129 if (resp)
8130 *resp_len = os_strlen(resp);
8131 else
8132 *resp_len = 1;
8133 return resp;
8134 }
8135
8136 return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
8137}
8138
8139
8140static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
8141 char *buf, size_t *resp_len)
8142{
8143#ifdef CONFIG_P2P
8144 static const char * cmd[] = {
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07008145 "LIST_NETWORKS",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008146 "P2P_FIND",
8147 "P2P_STOP_FIND",
8148 "P2P_LISTEN",
8149 "P2P_GROUP_ADD",
8150 "P2P_GET_PASSPHRASE",
8151 "P2P_SERVICE_UPDATE",
8152 "P2P_SERVICE_FLUSH",
8153 "P2P_FLUSH",
8154 "P2P_CANCEL",
8155 "P2P_PRESENCE_REQ",
8156 "P2P_EXT_LISTEN",
8157 NULL
8158 };
8159 static const char * prefix[] = {
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08008160#ifdef ANDROID
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07008161 "DRIVER ",
Dmitry Shmidt9e3f8ee2014-01-17 10:52:01 -08008162#endif /* ANDROID */
Dmitry Shmidt0c18dcd2013-08-16 15:29:47 -07008163 "GET_NETWORK ",
8164 "REMOVE_NETWORK ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008165 "P2P_FIND ",
8166 "P2P_CONNECT ",
8167 "P2P_LISTEN ",
8168 "P2P_GROUP_REMOVE ",
8169 "P2P_GROUP_ADD ",
8170 "P2P_PROV_DISC ",
8171 "P2P_SERV_DISC_REQ ",
8172 "P2P_SERV_DISC_CANCEL_REQ ",
8173 "P2P_SERV_DISC_RESP ",
8174 "P2P_SERV_DISC_EXTERNAL ",
8175 "P2P_SERVICE_ADD ",
8176 "P2P_SERVICE_DEL ",
8177 "P2P_REJECT ",
8178 "P2P_INVITE ",
8179 "P2P_PEER ",
8180 "P2P_SET ",
8181 "P2P_UNAUTHORIZE ",
8182 "P2P_PRESENCE_REQ ",
8183 "P2P_EXT_LISTEN ",
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07008184 "P2P_REMOVE_CLIENT ",
Dmitry Shmidt413dde72014-04-11 10:23:22 -07008185 "NFC_GET_HANDOVER_SEL ",
8186 "NFC_GET_HANDOVER_REQ ",
8187 "NFC_REPORT_HANDOVER ",
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008188 NULL
8189 };
8190 int found = 0;
8191 int i;
8192
8193 if (global->p2p_init_wpa_s == NULL)
8194 return NULL;
8195
8196 for (i = 0; !found && cmd[i]; i++) {
8197 if (os_strcmp(buf, cmd[i]) == 0)
8198 found = 1;
8199 }
8200
8201 for (i = 0; !found && prefix[i]; i++) {
8202 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
8203 found = 1;
8204 }
8205
8206 if (found)
8207 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
8208 buf, resp_len);
8209#endif /* CONFIG_P2P */
8210 return NULL;
8211}
8212
8213
8214static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
8215 char *buf, size_t *resp_len)
8216{
8217#ifdef CONFIG_WIFI_DISPLAY
8218 if (global->p2p_init_wpa_s == NULL)
8219 return NULL;
8220 if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
8221 os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
8222 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
8223 buf, resp_len);
8224#endif /* CONFIG_WIFI_DISPLAY */
8225 return NULL;
8226}
8227
8228
8229static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
8230 char *buf, size_t *resp_len)
8231{
8232 char *ret;
8233
8234 ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
8235 if (ret)
8236 return ret;
8237
8238 ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
8239 if (ret)
8240 return ret;
8241
8242 return NULL;
8243}
8244
8245
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008246static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
8247{
8248 char *value;
8249
8250 value = os_strchr(cmd, ' ');
8251 if (value == NULL)
8252 return -1;
8253 *value++ = '\0';
8254
8255 wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
8256
8257#ifdef CONFIG_WIFI_DISPLAY
8258 if (os_strcasecmp(cmd, "wifi_display") == 0) {
8259 wifi_display_enable(global, !!atoi(value));
8260 return 0;
8261 }
8262#endif /* CONFIG_WIFI_DISPLAY */
8263
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008264 /* Restore cmd to its original value to allow redirection */
8265 value[-1] = ' ';
8266
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008267 return -1;
8268}
8269
8270
8271#ifndef CONFIG_NO_CONFIG_WRITE
8272static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
8273{
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008274 int ret = 0, saved = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008275 struct wpa_supplicant *wpa_s;
8276
8277 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8278 if (!wpa_s->conf->update_config) {
8279 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
8280 continue;
8281 }
8282
8283 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
8284 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
8285 ret = 1;
8286 } else {
8287 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008288 saved++;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008289 }
8290 }
8291
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008292 if (!saved && !ret) {
8293 wpa_dbg(wpa_s, MSG_DEBUG,
8294 "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
8295 ret = 1;
8296 }
8297
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008298 return ret;
8299}
8300#endif /* CONFIG_NO_CONFIG_WRITE */
8301
8302
8303static int wpas_global_ctrl_iface_status(struct wpa_global *global,
8304 char *buf, size_t buflen)
8305{
8306 char *pos, *end;
8307 int ret;
8308 struct wpa_supplicant *wpa_s;
8309
8310 pos = buf;
8311 end = buf + buflen;
8312
8313#ifdef CONFIG_P2P
8314 if (global->p2p && !global->p2p_disabled) {
8315 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
8316 "\n"
8317 "p2p_state=%s\n",
8318 MAC2STR(global->p2p_dev_addr),
8319 p2p_get_state_txt(global->p2p));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008320 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008321 return pos - buf;
8322 pos += ret;
8323 } else if (global->p2p) {
8324 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008325 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008326 return pos - buf;
8327 pos += ret;
8328 }
8329#endif /* CONFIG_P2P */
8330
8331#ifdef CONFIG_WIFI_DISPLAY
8332 ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
8333 !!global->wifi_display);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008334 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008335 return pos - buf;
8336 pos += ret;
8337#endif /* CONFIG_WIFI_DISPLAY */
8338
8339 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
8340 ret = os_snprintf(pos, end - pos, "ifname=%s\n"
8341 "address=" MACSTR "\n",
8342 wpa_s->ifname, MAC2STR(wpa_s->own_addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008343 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008344 return pos - buf;
8345 pos += ret;
8346 }
8347
8348 return pos - buf;
8349}
8350
8351
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008352char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
8353 char *buf, size_t *resp_len)
8354{
8355 char *reply;
8356 const int reply_size = 2048;
8357 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008358 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008359
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07008360 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
8361 char *pos = os_strchr(buf + 7, ' ');
8362 if (pos) {
8363 *pos++ = '\0';
8364 return wpas_global_ctrl_iface_ifname(global,
8365 buf + 7, pos,
8366 resp_len);
8367 }
8368 }
8369
8370 reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
8371 if (reply)
8372 return reply;
8373
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008374 if (os_strcmp(buf, "PING") == 0)
8375 level = MSG_EXCESSIVE;
8376 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008377 (const u8 *) buf, os_strlen(buf));
8378
8379 reply = os_malloc(reply_size);
8380 if (reply == NULL) {
8381 *resp_len = 1;
8382 return NULL;
8383 }
8384
8385 os_memcpy(reply, "OK\n", 3);
8386 reply_len = 3;
8387
8388 if (os_strcmp(buf, "PING") == 0) {
8389 os_memcpy(reply, "PONG\n", 5);
8390 reply_len = 5;
8391 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
8392 if (wpa_supplicant_global_iface_add(global, buf + 14))
8393 reply_len = -1;
8394 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
8395 if (wpa_supplicant_global_iface_remove(global, buf + 17))
8396 reply_len = -1;
8397 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
8398 reply_len = wpa_supplicant_global_iface_list(
8399 global, reply, reply_size);
8400 } else if (os_strcmp(buf, "INTERFACES") == 0) {
8401 reply_len = wpa_supplicant_global_iface_interfaces(
8402 global, reply, reply_size);
8403 } else if (os_strcmp(buf, "TERMINATE") == 0) {
8404 wpa_supplicant_terminate_proc(global);
8405 } else if (os_strcmp(buf, "SUSPEND") == 0) {
8406 wpas_notify_suspend(global);
8407 } else if (os_strcmp(buf, "RESUME") == 0) {
8408 wpas_notify_resume(global);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008409 } else if (os_strncmp(buf, "SET ", 4) == 0) {
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008410 if (wpas_global_ctrl_iface_set(global, buf + 4)) {
8411#ifdef CONFIG_P2P
8412 if (global->p2p_init_wpa_s) {
8413 os_free(reply);
8414 /* Check if P2P redirection would work for this
8415 * command. */
8416 return wpa_supplicant_ctrl_iface_process(
8417 global->p2p_init_wpa_s,
8418 buf, resp_len);
8419 }
8420#endif /* CONFIG_P2P */
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008421 reply_len = -1;
Dmitry Shmidt61593f02014-04-21 16:27:35 -07008422 }
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008423#ifndef CONFIG_NO_CONFIG_WRITE
8424 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
8425 if (wpas_global_ctrl_iface_save_config(global))
8426 reply_len = -1;
8427#endif /* CONFIG_NO_CONFIG_WRITE */
8428 } else if (os_strcmp(buf, "STATUS") == 0) {
8429 reply_len = wpas_global_ctrl_iface_status(global, reply,
8430 reply_size);
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -08008431#ifdef CONFIG_MODULE_TESTS
8432 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
8433 int wpas_module_tests(void);
8434 if (wpas_module_tests() < 0)
8435 reply_len = -1;
8436#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008437 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
8438 if (wpa_debug_reopen_file() < 0)
8439 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008440 } else {
8441 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
8442 reply_len = 16;
8443 }
8444
8445 if (reply_len < 0) {
8446 os_memcpy(reply, "FAIL\n", 5);
8447 reply_len = 5;
8448 }
8449
8450 *resp_len = reply_len;
8451 return reply;
8452}