blob: 564c91ed599a6dd555d2a33182e32e4f37fb0523 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / Control interface (shared code for all backends)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003 * Copyright (c) 2004-2012, 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"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/version.h"
14#include "common/ieee802_11_defs.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070015#include "common/ieee802_11_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include "common/wpa_ctrl.h"
17#include "eap_peer/eap.h"
18#include "eapol_supp/eapol_supp_sm.h"
19#include "rsn_supp/wpa.h"
20#include "rsn_supp/preauth.h"
21#include "rsn_supp/pmksa_cache.h"
22#include "l2_packet/l2_packet.h"
23#include "wps/wps.h"
24#include "config.h"
25#include "wpa_supplicant_i.h"
26#include "driver_i.h"
27#include "wps_supplicant.h"
28#include "ibss_rsn.h"
29#include "ap.h"
30#include "p2p_supplicant.h"
31#include "p2p/p2p.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070032#include "hs20_supplicant.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070033#include "wifi_display.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "notify.h"
35#include "bss.h"
36#include "scan.h"
37#include "ctrl_iface.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080038#include "interworking.h"
Dmitry Shmidte19501d2011-03-16 14:32:18 -070039#include "blacklist.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070040#include "autoscan.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070041
42extern struct wpa_driver_ops *wpa_drivers[];
43
44static int wpa_supplicant_global_iface_list(struct wpa_global *global,
45 char *buf, int len);
46static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
47 char *buf, int len);
48
49
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080050static int pno_start(struct wpa_supplicant *wpa_s)
51{
52 int ret;
53 size_t i, num_ssid;
54 struct wpa_ssid *ssid;
55 struct wpa_driver_scan_params params;
56
57 if (wpa_s->pno)
58 return 0;
59
60 os_memset(&params, 0, sizeof(params));
61
62 num_ssid = 0;
63 ssid = wpa_s->conf->ssid;
64 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -070065 if (!wpas_network_disabled(wpa_s, ssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080066 num_ssid++;
67 ssid = ssid->next;
68 }
69 if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
70 wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
71 "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
72 num_ssid = WPAS_MAX_SCAN_SSIDS;
73 }
74
75 if (num_ssid == 0) {
76 wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
77 return -1;
78 }
79
80 params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
81 num_ssid);
82 if (params.filter_ssids == NULL)
83 return -1;
84 i = 0;
85 ssid = wpa_s->conf->ssid;
86 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -070087 if (!wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080088 params.ssids[i].ssid = ssid->ssid;
89 params.ssids[i].ssid_len = ssid->ssid_len;
90 params.num_ssids++;
91 os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
92 ssid->ssid_len);
93 params.filter_ssids[i].ssid_len = ssid->ssid_len;
94 params.num_filter_ssids++;
95 i++;
96 if (i == num_ssid)
97 break;
98 }
99 ssid = ssid->next;
100 }
101
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700102 if (wpa_s->conf->filter_rssi)
103 params.filter_rssi = wpa_s->conf->filter_rssi;
104
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800105 ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
106 os_free(params.filter_ssids);
107 if (ret == 0)
108 wpa_s->pno = 1;
109 return ret;
110}
111
112
113static int pno_stop(struct wpa_supplicant *wpa_s)
114{
115 if (wpa_s->pno) {
116 wpa_s->pno = 0;
117 return wpa_drv_stop_sched_scan(wpa_s);
118 }
119 return 0;
120}
121
122
Dmitry Shmidt04949592012-07-19 12:16:46 -0700123static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
124{
125 char *pos;
126 u8 addr[ETH_ALEN], *filter = NULL, *n;
127 size_t count = 0;
128
129 pos = val;
130 while (pos) {
131 if (*pos == '\0')
132 break;
133 if (hwaddr_aton(pos, addr)) {
134 os_free(filter);
135 return -1;
136 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700137 n = os_realloc_array(filter, count + 1, ETH_ALEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700138 if (n == NULL) {
139 os_free(filter);
140 return -1;
141 }
142 filter = n;
143 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
144 count++;
145
146 pos = os_strchr(pos, ' ');
147 if (pos)
148 pos++;
149 }
150
151 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
152 os_free(wpa_s->bssid_filter);
153 wpa_s->bssid_filter = filter;
154 wpa_s->bssid_filter_count = count;
155
156 return 0;
157}
158
159
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800160static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
161{
162 char *pos;
163 u8 addr[ETH_ALEN], *bssid = NULL, *n;
164 struct wpa_ssid_value *ssid = NULL, *ns;
165 size_t count = 0, ssid_count = 0;
166 struct wpa_ssid *c;
167
168 /*
169 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
170 * SSID_SPEC ::= ssid <SSID_HEX>
171 * BSSID_SPEC ::= bssid <BSSID_HEX>
172 */
173
174 pos = val;
175 while (pos) {
176 if (*pos == '\0')
177 break;
178 if (os_strncmp(pos, "bssid ", 6) == 0) {
179 int res;
180 pos += 6;
181 res = hwaddr_aton2(pos, addr);
182 if (res < 0) {
183 os_free(ssid);
184 os_free(bssid);
185 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
186 "BSSID value '%s'", pos);
187 return -1;
188 }
189 pos += res;
190 n = os_realloc_array(bssid, count + 1, ETH_ALEN);
191 if (n == NULL) {
192 os_free(ssid);
193 os_free(bssid);
194 return -1;
195 }
196 bssid = n;
197 os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
198 count++;
199 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
200 char *end;
201 pos += 5;
202
203 end = pos;
204 while (*end) {
205 if (*end == '\0' || *end == ' ')
206 break;
207 end++;
208 }
209
210 ns = os_realloc_array(ssid, ssid_count + 1,
211 sizeof(struct wpa_ssid_value));
212 if (ns == NULL) {
213 os_free(ssid);
214 os_free(bssid);
215 return -1;
216 }
217 ssid = ns;
218
219 if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
220 hexstr2bin(pos, ssid[ssid_count].ssid,
221 (end - pos) / 2) < 0) {
222 os_free(ssid);
223 os_free(bssid);
224 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
225 "SSID value '%s'", pos);
226 return -1;
227 }
228 ssid[ssid_count].ssid_len = (end - pos) / 2;
229 wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
230 ssid[ssid_count].ssid,
231 ssid[ssid_count].ssid_len);
232 ssid_count++;
233 pos = end;
234 } else {
235 wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
236 "'%s'", pos);
237 os_free(ssid);
238 os_free(bssid);
239 return -1;
240 }
241
242 pos = os_strchr(pos, ' ');
243 if (pos)
244 pos++;
245 }
246
247 wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
248 os_free(wpa_s->disallow_aps_bssid);
249 wpa_s->disallow_aps_bssid = bssid;
250 wpa_s->disallow_aps_bssid_count = count;
251
252 wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
253 os_free(wpa_s->disallow_aps_ssid);
254 wpa_s->disallow_aps_ssid = ssid;
255 wpa_s->disallow_aps_ssid_count = ssid_count;
256
257 if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
258 return 0;
259
260 c = wpa_s->current_ssid;
261 if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
262 return 0;
263
264 if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
265 !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
266 return 0;
267
268 wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
269 "because current AP was marked disallowed");
270
271#ifdef CONFIG_SME
272 wpa_s->sme.prev_bssid_set = 0;
273#endif /* CONFIG_SME */
274 wpa_s->reassociate = 1;
275 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
276 wpa_supplicant_req_scan(wpa_s, 0, 0);
277
278 return 0;
279}
280
281
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700282static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
283 char *cmd)
284{
285 char *value;
286 int ret = 0;
287
288 value = os_strchr(cmd, ' ');
289 if (value == NULL)
290 return -1;
291 *value++ = '\0';
292
293 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
294 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
295 eapol_sm_configure(wpa_s->eapol,
296 atoi(value), -1, -1, -1);
297 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
298 eapol_sm_configure(wpa_s->eapol,
299 -1, atoi(value), -1, -1);
300 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
301 eapol_sm_configure(wpa_s->eapol,
302 -1, -1, atoi(value), -1);
303 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
304 eapol_sm_configure(wpa_s->eapol,
305 -1, -1, -1, atoi(value));
306 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
307 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
308 atoi(value)))
309 ret = -1;
310 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
311 0) {
312 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
313 atoi(value)))
314 ret = -1;
315 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
316 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
317 ret = -1;
318 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
319 wpa_s->wps_fragment_size = atoi(value);
320#ifdef CONFIG_WPS_TESTING
321 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
322 long int val;
323 val = strtol(value, NULL, 0);
324 if (val < 0 || val > 0xff) {
325 ret = -1;
326 wpa_printf(MSG_DEBUG, "WPS: Invalid "
327 "wps_version_number %ld", val);
328 } else {
329 wps_version_number = val;
330 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
331 "version %u.%u",
332 (wps_version_number & 0xf0) >> 4,
333 wps_version_number & 0x0f);
334 }
335 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
336 wps_testing_dummy_cred = atoi(value);
337 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
338 wps_testing_dummy_cred);
339#endif /* CONFIG_WPS_TESTING */
340 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
341 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
342 ret = -1;
343#ifdef CONFIG_TDLS_TESTING
344 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
345 extern unsigned int tdls_testing;
346 tdls_testing = strtol(value, NULL, 0);
347 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
348#endif /* CONFIG_TDLS_TESTING */
349#ifdef CONFIG_TDLS
350 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
351 int disabled = atoi(value);
352 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
353 if (disabled) {
354 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
355 ret = -1;
356 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
357 ret = -1;
358 wpa_tdls_enable(wpa_s->wpa, !disabled);
359#endif /* CONFIG_TDLS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800360 } else if (os_strcasecmp(cmd, "pno") == 0) {
361 if (atoi(value))
362 ret = pno_start(wpa_s);
363 else
364 ret = pno_stop(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700365 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
366 int disabled = atoi(value);
367 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
368 ret = -1;
369 else if (disabled)
370 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
371 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
372 if (os_strcmp(value, "disable") == 0)
373 wpa_s->set_sta_uapsd = 0;
374 else {
375 int be, bk, vi, vo;
376 char *pos;
377 /* format: BE,BK,VI,VO;max SP Length */
378 be = atoi(value);
379 pos = os_strchr(value, ',');
380 if (pos == NULL)
381 return -1;
382 pos++;
383 bk = atoi(pos);
384 pos = os_strchr(pos, ',');
385 if (pos == NULL)
386 return -1;
387 pos++;
388 vi = atoi(pos);
389 pos = os_strchr(pos, ',');
390 if (pos == NULL)
391 return -1;
392 pos++;
393 vo = atoi(pos);
394 /* ignore max SP Length for now */
395
396 wpa_s->set_sta_uapsd = 1;
397 wpa_s->sta_uapsd = 0;
398 if (be)
399 wpa_s->sta_uapsd |= BIT(0);
400 if (bk)
401 wpa_s->sta_uapsd |= BIT(1);
402 if (vi)
403 wpa_s->sta_uapsd |= BIT(2);
404 if (vo)
405 wpa_s->sta_uapsd |= BIT(3);
406 }
Jouni Malinen21d6bc82012-04-10 16:17:59 -0700407 } else if (os_strcasecmp(cmd, "ps") == 0) {
408 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700409#ifdef CONFIG_WIFI_DISPLAY
410 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
411 wifi_display_enable(wpa_s->global, !!atoi(value));
412#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700413 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
414 ret = set_bssid_filter(wpa_s, value);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800415 } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
416 ret = set_disallow_aps(wpa_s, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417 } else {
418 value[-1] = '=';
419 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
420 if (ret == 0)
421 wpa_supplicant_update_config(wpa_s);
422 }
423
424 return ret;
425}
426
427
428static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
429 char *cmd, char *buf, size_t buflen)
430{
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700431 int res = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700432
433 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
434
435 if (os_strcmp(cmd, "version") == 0) {
436 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700437 } else if (os_strcasecmp(cmd, "country") == 0) {
438 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
439 res = os_snprintf(buf, buflen, "%c%c",
440 wpa_s->conf->country[0],
441 wpa_s->conf->country[1]);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700442#ifdef CONFIG_WIFI_DISPLAY
443 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
444 res = os_snprintf(buf, buflen, "%d",
445 wpa_s->global->wifi_display);
446 if (res < 0 || (unsigned int) res >= buflen)
447 return -1;
448 return res;
449#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700450 }
451
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700452 if (res < 0 || (unsigned int) res >= buflen)
453 return -1;
454 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455}
456
457
458#ifdef IEEE8021X_EAPOL
459static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
460 char *addr)
461{
462 u8 bssid[ETH_ALEN];
463 struct wpa_ssid *ssid = wpa_s->current_ssid;
464
465 if (hwaddr_aton(addr, bssid)) {
466 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
467 "'%s'", addr);
468 return -1;
469 }
470
471 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
472 rsn_preauth_deinit(wpa_s->wpa);
473 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
474 return -1;
475
476 return 0;
477}
478#endif /* IEEE8021X_EAPOL */
479
480
481#ifdef CONFIG_PEERKEY
482/* MLME-STKSTART.request(peer) */
483static int wpa_supplicant_ctrl_iface_stkstart(
484 struct wpa_supplicant *wpa_s, char *addr)
485{
486 u8 peer[ETH_ALEN];
487
488 if (hwaddr_aton(addr, peer)) {
489 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
490 "address '%s'", addr);
491 return -1;
492 }
493
494 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
495 MAC2STR(peer));
496
497 return wpa_sm_stkstart(wpa_s->wpa, peer);
498}
499#endif /* CONFIG_PEERKEY */
500
501
502#ifdef CONFIG_TDLS
503
504static int wpa_supplicant_ctrl_iface_tdls_discover(
505 struct wpa_supplicant *wpa_s, char *addr)
506{
507 u8 peer[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800508 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700509
510 if (hwaddr_aton(addr, peer)) {
511 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
512 "address '%s'", addr);
513 return -1;
514 }
515
516 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
517 MAC2STR(peer));
518
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800519 if (wpa_tdls_is_external_setup(wpa_s->wpa))
520 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
521 else
522 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
523
524 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700525}
526
527
528static int wpa_supplicant_ctrl_iface_tdls_setup(
529 struct wpa_supplicant *wpa_s, char *addr)
530{
531 u8 peer[ETH_ALEN];
532 int ret;
533
534 if (hwaddr_aton(addr, peer)) {
535 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
536 "address '%s'", addr);
537 return -1;
538 }
539
540 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
541 MAC2STR(peer));
542
543 ret = wpa_tdls_reneg(wpa_s->wpa, peer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800544 if (ret) {
545 if (wpa_tdls_is_external_setup(wpa_s->wpa))
546 ret = wpa_tdls_start(wpa_s->wpa, peer);
547 else
548 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
549 }
550
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700551 return ret;
552}
553
554
555static int wpa_supplicant_ctrl_iface_tdls_teardown(
556 struct wpa_supplicant *wpa_s, char *addr)
557{
558 u8 peer[ETH_ALEN];
559
560 if (hwaddr_aton(addr, peer)) {
561 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
562 "address '%s'", addr);
563 return -1;
564 }
565
566 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
567 MAC2STR(peer));
568
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800569 return wpa_tdls_teardown_link(wpa_s->wpa, peer,
570 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700571}
572
573#endif /* CONFIG_TDLS */
574
575
576#ifdef CONFIG_IEEE80211R
577static int wpa_supplicant_ctrl_iface_ft_ds(
578 struct wpa_supplicant *wpa_s, char *addr)
579{
580 u8 target_ap[ETH_ALEN];
581 struct wpa_bss *bss;
582 const u8 *mdie;
583
584 if (hwaddr_aton(addr, target_ap)) {
585 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
586 "address '%s'", addr);
587 return -1;
588 }
589
590 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
591
592 bss = wpa_bss_get_bssid(wpa_s, target_ap);
593 if (bss)
594 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
595 else
596 mdie = NULL;
597
598 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
599}
600#endif /* CONFIG_IEEE80211R */
601
602
603#ifdef CONFIG_WPS
604static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
605 char *cmd)
606{
607 u8 bssid[ETH_ALEN], *_bssid = bssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700608#ifdef CONFIG_P2P
609 u8 p2p_dev_addr[ETH_ALEN];
610#endif /* CONFIG_P2P */
611#ifdef CONFIG_AP
612 u8 *_p2p_dev_addr = NULL;
613#endif /* CONFIG_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800614
Irfan Sheriffa7534b92012-09-06 18:30:39 -0700615 if (cmd == NULL || os_strcmp(cmd, "any") == 0 || cmd[0] == '\0') {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700616 _bssid = NULL;
617#ifdef CONFIG_P2P
618 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
619 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
620 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
621 "P2P Device Address '%s'",
622 cmd + 13);
623 return -1;
624 }
625 _p2p_dev_addr = p2p_dev_addr;
626#endif /* CONFIG_P2P */
627 } else if (hwaddr_aton(cmd, bssid)) {
628 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
629 cmd);
630 return -1;
631 }
632
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800633#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700634 if (wpa_s->ap_iface)
635 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
636#endif /* CONFIG_AP */
637
638 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
639}
640
641
642static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
643 char *cmd, char *buf,
644 size_t buflen)
645{
646 u8 bssid[ETH_ALEN], *_bssid = bssid;
647 char *pin;
648 int ret;
649
650 pin = os_strchr(cmd, ' ');
651 if (pin)
652 *pin++ = '\0';
653
654 if (os_strcmp(cmd, "any") == 0)
655 _bssid = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800656 else if (os_strcmp(cmd, "get") == 0) {
657 ret = wps_generate_pin();
658 goto done;
659 } else if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700660 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
661 cmd);
662 return -1;
663 }
664
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800665#ifdef CONFIG_AP
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800666 if (wpa_s->ap_iface) {
667 int timeout = 0;
668 char *pos;
669
670 if (pin) {
671 pos = os_strchr(pin, ' ');
672 if (pos) {
673 *pos++ = '\0';
674 timeout = atoi(pos);
675 }
676 }
677
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700678 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800679 buf, buflen, timeout);
680 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700681#endif /* CONFIG_AP */
682
683 if (pin) {
684 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
685 DEV_PW_DEFAULT);
686 if (ret < 0)
687 return -1;
688 ret = os_snprintf(buf, buflen, "%s", pin);
689 if (ret < 0 || (size_t) ret >= buflen)
690 return -1;
691 return ret;
692 }
693
694 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
695 if (ret < 0)
696 return -1;
697
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800698done:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700699 /* Return the generated PIN */
700 ret = os_snprintf(buf, buflen, "%08d", ret);
701 if (ret < 0 || (size_t) ret >= buflen)
702 return -1;
703 return ret;
704}
705
706
707static int wpa_supplicant_ctrl_iface_wps_check_pin(
708 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
709{
710 char pin[9];
711 size_t len;
712 char *pos;
713 int ret;
714
715 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
716 (u8 *) cmd, os_strlen(cmd));
717 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
718 if (*pos < '0' || *pos > '9')
719 continue;
720 pin[len++] = *pos;
721 if (len == 9) {
722 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
723 return -1;
724 }
725 }
726 if (len != 4 && len != 8) {
727 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
728 return -1;
729 }
730 pin[len] = '\0';
731
732 if (len == 8) {
733 unsigned int pin_val;
734 pin_val = atoi(pin);
735 if (!wps_pin_valid(pin_val)) {
736 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
737 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
738 if (ret < 0 || (size_t) ret >= buflen)
739 return -1;
740 return ret;
741 }
742 }
743
744 ret = os_snprintf(buf, buflen, "%s", pin);
745 if (ret < 0 || (size_t) ret >= buflen)
746 return -1;
747
748 return ret;
749}
750
751
Dmitry Shmidt04949592012-07-19 12:16:46 -0700752#ifdef CONFIG_WPS_NFC
753
754static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
755 char *cmd)
756{
757 u8 bssid[ETH_ALEN], *_bssid = bssid;
758
759 if (cmd == NULL || cmd[0] == '\0')
760 _bssid = NULL;
761 else if (hwaddr_aton(cmd, bssid))
762 return -1;
763
764 return wpas_wps_start_nfc(wpa_s, _bssid);
765}
766
767
768static int wpa_supplicant_ctrl_iface_wps_nfc_token(
769 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
770{
771 int ndef;
772 struct wpabuf *buf;
773 int res;
774
775 if (os_strcmp(cmd, "WPS") == 0)
776 ndef = 0;
777 else if (os_strcmp(cmd, "NDEF") == 0)
778 ndef = 1;
779 else
780 return -1;
781
782 buf = wpas_wps_nfc_token(wpa_s, ndef);
783 if (buf == NULL)
784 return -1;
785
786 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
787 wpabuf_len(buf));
788 reply[res++] = '\n';
789 reply[res] = '\0';
790
791 wpabuf_free(buf);
792
793 return res;
794}
795
796
797static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
798 struct wpa_supplicant *wpa_s, char *pos)
799{
800 size_t len;
801 struct wpabuf *buf;
802 int ret;
803
804 len = os_strlen(pos);
805 if (len & 0x01)
806 return -1;
807 len /= 2;
808
809 buf = wpabuf_alloc(len);
810 if (buf == NULL)
811 return -1;
812 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
813 wpabuf_free(buf);
814 return -1;
815 }
816
817 ret = wpas_wps_nfc_tag_read(wpa_s, buf);
818 wpabuf_free(buf);
819
820 return ret;
821}
822
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800823
824static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
825 char *reply, size_t max_len)
826{
827 struct wpabuf *buf;
828 int res;
829
830 buf = wpas_wps_nfc_handover_req(wpa_s);
831 if (buf == NULL)
832 return -1;
833
834 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
835 wpabuf_len(buf));
836 reply[res++] = '\n';
837 reply[res] = '\0';
838
839 wpabuf_free(buf);
840
841 return res;
842}
843
844
845static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
846 char *cmd, char *reply,
847 size_t max_len)
848{
849 char *pos;
850
851 pos = os_strchr(cmd, ' ');
852 if (pos == NULL)
853 return -1;
854 *pos++ = '\0';
855
856 if (os_strcmp(cmd, "NDEF") != 0)
857 return -1;
858
859 if (os_strcmp(pos, "WPS") == 0) {
860 return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
861 max_len);
862 }
863
864 return -1;
865}
866
867
868static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
869 char *reply, size_t max_len)
870{
871 struct wpabuf *buf;
872 int res;
873
874 buf = wpas_wps_nfc_handover_sel(wpa_s);
875 if (buf == NULL)
876 return -1;
877
878 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
879 wpabuf_len(buf));
880 reply[res++] = '\n';
881 reply[res] = '\0';
882
883 wpabuf_free(buf);
884
885 return res;
886}
887
888
889static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
890 char *cmd, char *reply,
891 size_t max_len)
892{
893 char *pos;
894
895 pos = os_strchr(cmd, ' ');
896 if (pos == NULL)
897 return -1;
898 *pos++ = '\0';
899
900 if (os_strcmp(cmd, "NDEF") != 0)
901 return -1;
902
903 if (os_strcmp(pos, "WPS") == 0) {
904 return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
905 max_len);
906 }
907
908 return -1;
909}
910
911
912static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
913 char *cmd, char *reply,
914 size_t max_len)
915{
916 size_t len;
917 struct wpabuf *buf;
918 int ret;
919
920 len = os_strlen(cmd);
921 if (len & 0x01)
922 return -1;
923 len /= 2;
924
925 buf = wpabuf_alloc(len);
926 if (buf == NULL)
927 return -1;
928 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
929 wpabuf_free(buf);
930 return -1;
931 }
932
933 ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
934 wpabuf_free(buf);
935
936 return ret;
937}
938
939
940static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
941 char *cmd)
942{
943 size_t len;
944 struct wpabuf *buf;
945 int ret;
946
947 len = os_strlen(cmd);
948 if (len & 0x01)
949 return -1;
950 len /= 2;
951
952 buf = wpabuf_alloc(len);
953 if (buf == NULL)
954 return -1;
955 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
956 wpabuf_free(buf);
957 return -1;
958 }
959
960 ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
961 wpabuf_free(buf);
962
963 return ret;
964}
965
Dmitry Shmidt04949592012-07-19 12:16:46 -0700966#endif /* CONFIG_WPS_NFC */
967
968
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700969static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
970 char *cmd)
971{
972 u8 bssid[ETH_ALEN];
973 char *pin;
974 char *new_ssid;
975 char *new_auth;
976 char *new_encr;
977 char *new_key;
978 struct wps_new_ap_settings ap;
979
980 pin = os_strchr(cmd, ' ');
981 if (pin == NULL)
982 return -1;
983 *pin++ = '\0';
984
985 if (hwaddr_aton(cmd, bssid)) {
986 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
987 cmd);
988 return -1;
989 }
990
991 new_ssid = os_strchr(pin, ' ');
992 if (new_ssid == NULL)
993 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
994 *new_ssid++ = '\0';
995
996 new_auth = os_strchr(new_ssid, ' ');
997 if (new_auth == NULL)
998 return -1;
999 *new_auth++ = '\0';
1000
1001 new_encr = os_strchr(new_auth, ' ');
1002 if (new_encr == NULL)
1003 return -1;
1004 *new_encr++ = '\0';
1005
1006 new_key = os_strchr(new_encr, ' ');
1007 if (new_key == NULL)
1008 return -1;
1009 *new_key++ = '\0';
1010
1011 os_memset(&ap, 0, sizeof(ap));
1012 ap.ssid_hex = new_ssid;
1013 ap.auth = new_auth;
1014 ap.encr = new_encr;
1015 ap.key_hex = new_key;
1016 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1017}
1018
1019
1020#ifdef CONFIG_AP
1021static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1022 char *cmd, char *buf,
1023 size_t buflen)
1024{
1025 int timeout = 300;
1026 char *pos;
1027 const char *pin_txt;
1028
1029 if (!wpa_s->ap_iface)
1030 return -1;
1031
1032 pos = os_strchr(cmd, ' ');
1033 if (pos)
1034 *pos++ = '\0';
1035
1036 if (os_strcmp(cmd, "disable") == 0) {
1037 wpas_wps_ap_pin_disable(wpa_s);
1038 return os_snprintf(buf, buflen, "OK\n");
1039 }
1040
1041 if (os_strcmp(cmd, "random") == 0) {
1042 if (pos)
1043 timeout = atoi(pos);
1044 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1045 if (pin_txt == NULL)
1046 return -1;
1047 return os_snprintf(buf, buflen, "%s", pin_txt);
1048 }
1049
1050 if (os_strcmp(cmd, "get") == 0) {
1051 pin_txt = wpas_wps_ap_pin_get(wpa_s);
1052 if (pin_txt == NULL)
1053 return -1;
1054 return os_snprintf(buf, buflen, "%s", pin_txt);
1055 }
1056
1057 if (os_strcmp(cmd, "set") == 0) {
1058 char *pin;
1059 if (pos == NULL)
1060 return -1;
1061 pin = pos;
1062 pos = os_strchr(pos, ' ');
1063 if (pos) {
1064 *pos++ = '\0';
1065 timeout = atoi(pos);
1066 }
1067 if (os_strlen(pin) > buflen)
1068 return -1;
1069 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1070 return -1;
1071 return os_snprintf(buf, buflen, "%s", pin);
1072 }
1073
1074 return -1;
1075}
1076#endif /* CONFIG_AP */
1077
1078
1079#ifdef CONFIG_WPS_ER
1080static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1081 char *cmd)
1082{
1083 char *uuid = cmd, *pin, *pos;
1084 u8 addr_buf[ETH_ALEN], *addr = NULL;
1085 pin = os_strchr(uuid, ' ');
1086 if (pin == NULL)
1087 return -1;
1088 *pin++ = '\0';
1089 pos = os_strchr(pin, ' ');
1090 if (pos) {
1091 *pos++ = '\0';
1092 if (hwaddr_aton(pos, addr_buf) == 0)
1093 addr = addr_buf;
1094 }
1095 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1096}
1097
1098
1099static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1100 char *cmd)
1101{
1102 char *uuid = cmd, *pin;
1103 pin = os_strchr(uuid, ' ');
1104 if (pin == NULL)
1105 return -1;
1106 *pin++ = '\0';
1107 return wpas_wps_er_learn(wpa_s, uuid, pin);
1108}
1109
1110
1111static int wpa_supplicant_ctrl_iface_wps_er_set_config(
1112 struct wpa_supplicant *wpa_s, char *cmd)
1113{
1114 char *uuid = cmd, *id;
1115 id = os_strchr(uuid, ' ');
1116 if (id == NULL)
1117 return -1;
1118 *id++ = '\0';
1119 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1120}
1121
1122
1123static int wpa_supplicant_ctrl_iface_wps_er_config(
1124 struct wpa_supplicant *wpa_s, char *cmd)
1125{
1126 char *pin;
1127 char *new_ssid;
1128 char *new_auth;
1129 char *new_encr;
1130 char *new_key;
1131 struct wps_new_ap_settings ap;
1132
1133 pin = os_strchr(cmd, ' ');
1134 if (pin == NULL)
1135 return -1;
1136 *pin++ = '\0';
1137
1138 new_ssid = os_strchr(pin, ' ');
1139 if (new_ssid == NULL)
1140 return -1;
1141 *new_ssid++ = '\0';
1142
1143 new_auth = os_strchr(new_ssid, ' ');
1144 if (new_auth == NULL)
1145 return -1;
1146 *new_auth++ = '\0';
1147
1148 new_encr = os_strchr(new_auth, ' ');
1149 if (new_encr == NULL)
1150 return -1;
1151 *new_encr++ = '\0';
1152
1153 new_key = os_strchr(new_encr, ' ');
1154 if (new_key == NULL)
1155 return -1;
1156 *new_key++ = '\0';
1157
1158 os_memset(&ap, 0, sizeof(ap));
1159 ap.ssid_hex = new_ssid;
1160 ap.auth = new_auth;
1161 ap.encr = new_encr;
1162 ap.key_hex = new_key;
1163 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1164}
Dmitry Shmidt04949592012-07-19 12:16:46 -07001165
1166
1167#ifdef CONFIG_WPS_NFC
1168static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1169 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1170{
1171 int ndef;
1172 struct wpabuf *buf;
1173 int res;
1174 char *uuid;
1175
1176 uuid = os_strchr(cmd, ' ');
1177 if (uuid == NULL)
1178 return -1;
1179 *uuid++ = '\0';
1180
1181 if (os_strcmp(cmd, "WPS") == 0)
1182 ndef = 0;
1183 else if (os_strcmp(cmd, "NDEF") == 0)
1184 ndef = 1;
1185 else
1186 return -1;
1187
1188 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1189 if (buf == NULL)
1190 return -1;
1191
1192 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1193 wpabuf_len(buf));
1194 reply[res++] = '\n';
1195 reply[res] = '\0';
1196
1197 wpabuf_free(buf);
1198
1199 return res;
1200}
1201#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202#endif /* CONFIG_WPS_ER */
1203
1204#endif /* CONFIG_WPS */
1205
1206
1207#ifdef CONFIG_IBSS_RSN
1208static int wpa_supplicant_ctrl_iface_ibss_rsn(
1209 struct wpa_supplicant *wpa_s, char *addr)
1210{
1211 u8 peer[ETH_ALEN];
1212
1213 if (hwaddr_aton(addr, peer)) {
1214 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1215 "address '%s'", addr);
1216 return -1;
1217 }
1218
1219 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1220 MAC2STR(peer));
1221
1222 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1223}
1224#endif /* CONFIG_IBSS_RSN */
1225
1226
1227static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1228 char *rsp)
1229{
1230#ifdef IEEE8021X_EAPOL
1231 char *pos, *id_pos;
1232 int id;
1233 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001234
1235 pos = os_strchr(rsp, '-');
1236 if (pos == NULL)
1237 return -1;
1238 *pos++ = '\0';
1239 id_pos = pos;
1240 pos = os_strchr(pos, ':');
1241 if (pos == NULL)
1242 return -1;
1243 *pos++ = '\0';
1244 id = atoi(id_pos);
1245 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1246 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1247 (u8 *) pos, os_strlen(pos));
1248
1249 ssid = wpa_config_get_network(wpa_s->conf, id);
1250 if (ssid == NULL) {
1251 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1252 "to update", id);
1253 return -1;
1254 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001256 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1257 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001258#else /* IEEE8021X_EAPOL */
1259 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1260 return -1;
1261#endif /* IEEE8021X_EAPOL */
1262}
1263
1264
1265static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1266 const char *params,
1267 char *buf, size_t buflen)
1268{
1269 char *pos, *end, tmp[30];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001270 int res, verbose, wps, ret;
Dmitry Shmidt44da0252011-08-23 12:30:30 -07001271
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272 verbose = os_strcmp(params, "-VERBOSE") == 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001273 wps = os_strcmp(params, "-WPS") == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001274 pos = buf;
1275 end = buf + buflen;
1276 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1277 struct wpa_ssid *ssid = wpa_s->current_ssid;
1278 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1279 MAC2STR(wpa_s->bssid));
1280 if (ret < 0 || ret >= end - pos)
1281 return pos - buf;
1282 pos += ret;
1283 if (ssid) {
1284 u8 *_ssid = ssid->ssid;
1285 size_t ssid_len = ssid->ssid_len;
1286 u8 ssid_buf[MAX_SSID_LEN];
1287 if (ssid_len == 0) {
1288 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1289 if (_res < 0)
1290 ssid_len = 0;
1291 else
1292 ssid_len = _res;
1293 _ssid = ssid_buf;
1294 }
1295 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1296 wpa_ssid_txt(_ssid, ssid_len),
1297 ssid->id);
1298 if (ret < 0 || ret >= end - pos)
1299 return pos - buf;
1300 pos += ret;
1301
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001302 if (wps && ssid->passphrase &&
1303 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1304 (ssid->mode == WPAS_MODE_AP ||
1305 ssid->mode == WPAS_MODE_P2P_GO)) {
1306 ret = os_snprintf(pos, end - pos,
1307 "passphrase=%s\n",
1308 ssid->passphrase);
1309 if (ret < 0 || ret >= end - pos)
1310 return pos - buf;
1311 pos += ret;
1312 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001313 if (ssid->id_str) {
1314 ret = os_snprintf(pos, end - pos,
1315 "id_str=%s\n",
1316 ssid->id_str);
1317 if (ret < 0 || ret >= end - pos)
1318 return pos - buf;
1319 pos += ret;
1320 }
1321
1322 switch (ssid->mode) {
1323 case WPAS_MODE_INFRA:
1324 ret = os_snprintf(pos, end - pos,
1325 "mode=station\n");
1326 break;
1327 case WPAS_MODE_IBSS:
1328 ret = os_snprintf(pos, end - pos,
1329 "mode=IBSS\n");
1330 break;
1331 case WPAS_MODE_AP:
1332 ret = os_snprintf(pos, end - pos,
1333 "mode=AP\n");
1334 break;
1335 case WPAS_MODE_P2P_GO:
1336 ret = os_snprintf(pos, end - pos,
1337 "mode=P2P GO\n");
1338 break;
1339 case WPAS_MODE_P2P_GROUP_FORMATION:
1340 ret = os_snprintf(pos, end - pos,
1341 "mode=P2P GO - group "
1342 "formation\n");
1343 break;
1344 default:
1345 ret = 0;
1346 break;
1347 }
1348 if (ret < 0 || ret >= end - pos)
1349 return pos - buf;
1350 pos += ret;
1351 }
1352
1353#ifdef CONFIG_AP
1354 if (wpa_s->ap_iface) {
1355 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1356 end - pos,
1357 verbose);
1358 } else
1359#endif /* CONFIG_AP */
1360 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1361 }
1362 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1363 wpa_supplicant_state_txt(wpa_s->wpa_state));
1364 if (ret < 0 || ret >= end - pos)
1365 return pos - buf;
1366 pos += ret;
1367
1368 if (wpa_s->l2 &&
1369 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1370 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
1371 if (ret < 0 || ret >= end - pos)
1372 return pos - buf;
1373 pos += ret;
1374 }
1375
1376#ifdef CONFIG_P2P
1377 if (wpa_s->global->p2p) {
1378 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1379 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
1380 if (ret < 0 || ret >= end - pos)
1381 return pos - buf;
1382 pos += ret;
1383 }
1384#endif /* CONFIG_P2P */
1385
1386 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1387 MAC2STR(wpa_s->own_addr));
1388 if (ret < 0 || ret >= end - pos)
1389 return pos - buf;
1390 pos += ret;
1391
Dmitry Shmidt04949592012-07-19 12:16:46 -07001392#ifdef CONFIG_HS20
1393 if (wpa_s->current_bss &&
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001394 wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
1395 wpa_s->wpa_proto == WPA_PROTO_RSN &&
1396 wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001397 ret = os_snprintf(pos, end - pos, "hs20=1\n");
1398 if (ret < 0 || ret >= end - pos)
1399 return pos - buf;
1400 pos += ret;
1401 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001402
1403 if (wpa_s->current_ssid) {
1404 struct wpa_cred *cred;
1405 char *type;
1406
1407 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1408 if (wpa_s->current_ssid->parent_cred != cred)
1409 continue;
1410 if (!cred->domain)
1411 continue;
1412
1413 ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
1414 cred->domain);
1415 if (ret < 0 || ret >= end - pos)
1416 return pos - buf;
1417 pos += ret;
1418
1419 if (wpa_s->current_bss == NULL ||
1420 wpa_s->current_bss->anqp == NULL)
1421 res = -1;
1422 else
1423 res = interworking_home_sp_cred(
1424 wpa_s, cred,
1425 wpa_s->current_bss->anqp->domain_name);
1426 if (res > 0)
1427 type = "home";
1428 else if (res == 0)
1429 type = "roaming";
1430 else
1431 type = "unknown";
1432
1433 ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
1434 if (ret < 0 || ret >= end - pos)
1435 return pos - buf;
1436 pos += ret;
1437
1438 break;
1439 }
1440 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001441#endif /* CONFIG_HS20 */
1442
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001443 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
1444 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1445 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
1446 verbose);
1447 if (res >= 0)
1448 pos += res;
1449 }
1450
1451 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
1452 if (res >= 0)
1453 pos += res;
1454
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001455#ifdef ANDROID
1456 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
Irfan Sherifff20a4432012-04-16 16:48:34 -07001457 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001458 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
Irfan Sherifff20a4432012-04-16 16:48:34 -07001459 wpa_s->wpa_state,
Irfan Sheriffe78e7672012-08-01 11:10:15 -07001460 MAC2STR(wpa_s->bssid),
andy2_kuo5b5fb022012-05-22 11:53:07 -07001461 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
1462 wpa_ssid_txt(wpa_s->current_ssid->ssid,
Irfan Sheriff10294772012-05-11 11:23:35 -07001463 wpa_s->current_ssid->ssid_len) : "");
Irfan Sheriffbf5edf42012-01-11 16:54:57 -08001464 if (wpa_s->wpa_state == WPA_COMPLETED) {
1465 struct wpa_ssid *ssid = wpa_s->current_ssid;
1466 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to "
1467 MACSTR " completed %s [id=%d id_str=%s]",
1468 MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
1469 "(reauth)" : "(auth)",
1470 ssid ? ssid->id : -1,
1471 ssid && ssid->id_str ? ssid->id_str : "");
1472 }
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001473#endif /* ANDROID */
1474
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001475 return pos - buf;
1476}
1477
1478
1479static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
1480 char *cmd)
1481{
1482 char *pos;
1483 int id;
1484 struct wpa_ssid *ssid;
1485 u8 bssid[ETH_ALEN];
1486
1487 /* cmd: "<network id> <BSSID>" */
1488 pos = os_strchr(cmd, ' ');
1489 if (pos == NULL)
1490 return -1;
1491 *pos++ = '\0';
1492 id = atoi(cmd);
1493 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
1494 if (hwaddr_aton(pos, bssid)) {
1495 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
1496 return -1;
1497 }
1498
1499 ssid = wpa_config_get_network(wpa_s->conf, id);
1500 if (ssid == NULL) {
1501 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1502 "to update", id);
1503 return -1;
1504 }
1505
1506 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
1507 ssid->bssid_set = !is_zero_ether_addr(bssid);
1508
1509 return 0;
1510}
1511
1512
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001513static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001514 char *cmd, char *buf,
1515 size_t buflen)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001516{
1517 u8 bssid[ETH_ALEN];
1518 struct wpa_blacklist *e;
1519 char *pos, *end;
1520 int ret;
1521
1522 /* cmd: "BLACKLIST [<BSSID>]" */
1523 if (*cmd == '\0') {
1524 pos = buf;
1525 end = buf + buflen;
1526 e = wpa_s->blacklist;
1527 while (e) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001528 ret = os_snprintf(pos, end - pos, MACSTR "\n",
1529 MAC2STR(e->bssid));
1530 if (ret < 0 || ret >= end - pos)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001531 return pos - buf;
1532 pos += ret;
1533 e = e->next;
1534 }
1535 return pos - buf;
1536 }
1537
1538 cmd++;
1539 if (os_strncmp(cmd, "clear", 5) == 0) {
1540 wpa_blacklist_clear(wpa_s);
1541 os_memcpy(buf, "OK\n", 3);
1542 return 3;
1543 }
1544
1545 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
1546 if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001547 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001548 return -1;
1549 }
1550
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001551 /*
1552 * Add the BSSID twice, so its count will be 2, causing it to be
1553 * skipped when processing scan results.
1554 */
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001555 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001556 if (ret != 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001557 return -1;
1558 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001559 if (ret != 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001560 return -1;
1561 os_memcpy(buf, "OK\n", 3);
1562 return 3;
1563}
1564
1565
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001566extern int wpa_debug_level;
1567extern int wpa_debug_timestamp;
1568
1569static const char * debug_level_str(int level)
1570{
1571 switch (level) {
1572 case MSG_EXCESSIVE:
1573 return "EXCESSIVE";
1574 case MSG_MSGDUMP:
1575 return "MSGDUMP";
1576 case MSG_DEBUG:
1577 return "DEBUG";
1578 case MSG_INFO:
1579 return "INFO";
1580 case MSG_WARNING:
1581 return "WARNING";
1582 case MSG_ERROR:
1583 return "ERROR";
1584 default:
1585 return "?";
1586 }
1587}
1588
1589
1590static int str_to_debug_level(const char *s)
1591{
1592 if (os_strcasecmp(s, "EXCESSIVE") == 0)
1593 return MSG_EXCESSIVE;
1594 if (os_strcasecmp(s, "MSGDUMP") == 0)
1595 return MSG_MSGDUMP;
1596 if (os_strcasecmp(s, "DEBUG") == 0)
1597 return MSG_DEBUG;
1598 if (os_strcasecmp(s, "INFO") == 0)
1599 return MSG_INFO;
1600 if (os_strcasecmp(s, "WARNING") == 0)
1601 return MSG_WARNING;
1602 if (os_strcasecmp(s, "ERROR") == 0)
1603 return MSG_ERROR;
1604 return -1;
1605}
1606
1607
1608static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
1609 char *cmd, char *buf,
1610 size_t buflen)
1611{
1612 char *pos, *end, *stamp;
1613 int ret;
1614
1615 if (cmd == NULL) {
1616 return -1;
1617 }
1618
1619 /* cmd: "LOG_LEVEL [<level>]" */
1620 if (*cmd == '\0') {
1621 pos = buf;
1622 end = buf + buflen;
1623 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1624 "Timestamp: %d\n",
1625 debug_level_str(wpa_debug_level),
1626 wpa_debug_timestamp);
1627 if (ret < 0 || ret >= end - pos)
1628 ret = 0;
1629
1630 return ret;
1631 }
1632
1633 while (*cmd == ' ')
1634 cmd++;
1635
1636 stamp = os_strchr(cmd, ' ');
1637 if (stamp) {
1638 *stamp++ = '\0';
1639 while (*stamp == ' ') {
1640 stamp++;
1641 }
1642 }
1643
1644 if (cmd && os_strlen(cmd)) {
1645 int level = str_to_debug_level(cmd);
1646 if (level < 0)
1647 return -1;
1648 wpa_debug_level = level;
1649 }
1650
1651 if (stamp && os_strlen(stamp))
1652 wpa_debug_timestamp = atoi(stamp);
1653
1654 os_memcpy(buf, "OK\n", 3);
1655 return 3;
1656}
1657
1658
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001659static int wpa_supplicant_ctrl_iface_list_networks(
1660 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1661{
1662 char *pos, *end;
1663 struct wpa_ssid *ssid;
1664 int ret;
1665
1666 pos = buf;
1667 end = buf + buflen;
1668 ret = os_snprintf(pos, end - pos,
1669 "network id / ssid / bssid / flags\n");
1670 if (ret < 0 || ret >= end - pos)
1671 return pos - buf;
1672 pos += ret;
1673
1674 ssid = wpa_s->conf->ssid;
1675 while (ssid) {
1676 ret = os_snprintf(pos, end - pos, "%d\t%s",
1677 ssid->id,
1678 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1679 if (ret < 0 || ret >= end - pos)
1680 return pos - buf;
1681 pos += ret;
1682 if (ssid->bssid_set) {
1683 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
1684 MAC2STR(ssid->bssid));
1685 } else {
1686 ret = os_snprintf(pos, end - pos, "\tany");
1687 }
1688 if (ret < 0 || ret >= end - pos)
1689 return pos - buf;
1690 pos += ret;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001691 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001692 ssid == wpa_s->current_ssid ?
1693 "[CURRENT]" : "",
1694 ssid->disabled ? "[DISABLED]" : "",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001695 ssid->disabled_until.sec ?
1696 "[TEMP-DISABLED]" : "",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001697 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
1698 "");
1699 if (ret < 0 || ret >= end - pos)
1700 return pos - buf;
1701 pos += ret;
1702 ret = os_snprintf(pos, end - pos, "\n");
1703 if (ret < 0 || ret >= end - pos)
1704 return pos - buf;
1705 pos += ret;
1706
1707 ssid = ssid->next;
1708 }
1709
1710 return pos - buf;
1711}
1712
1713
1714static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
1715{
1716 int first = 1, ret;
1717 ret = os_snprintf(pos, end - pos, "-");
1718 if (ret < 0 || ret >= end - pos)
1719 return pos;
1720 pos += ret;
1721 if (cipher & WPA_CIPHER_NONE) {
1722 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
1723 if (ret < 0 || ret >= end - pos)
1724 return pos;
1725 pos += ret;
1726 first = 0;
1727 }
1728 if (cipher & WPA_CIPHER_WEP40) {
1729 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
1730 if (ret < 0 || ret >= end - pos)
1731 return pos;
1732 pos += ret;
1733 first = 0;
1734 }
1735 if (cipher & WPA_CIPHER_WEP104) {
1736 ret = os_snprintf(pos, end - pos, "%sWEP104",
1737 first ? "" : "+");
1738 if (ret < 0 || ret >= end - pos)
1739 return pos;
1740 pos += ret;
1741 first = 0;
1742 }
1743 if (cipher & WPA_CIPHER_TKIP) {
1744 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
1745 if (ret < 0 || ret >= end - pos)
1746 return pos;
1747 pos += ret;
1748 first = 0;
1749 }
1750 if (cipher & WPA_CIPHER_CCMP) {
1751 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
1752 if (ret < 0 || ret >= end - pos)
1753 return pos;
1754 pos += ret;
1755 first = 0;
1756 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001757 if (cipher & WPA_CIPHER_GCMP) {
1758 ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
1759 if (ret < 0 || ret >= end - pos)
1760 return pos;
1761 pos += ret;
1762 first = 0;
1763 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001764 return pos;
1765}
1766
1767
1768static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
1769 const u8 *ie, size_t ie_len)
1770{
1771 struct wpa_ie_data data;
1772 int first, ret;
1773
1774 ret = os_snprintf(pos, end - pos, "[%s-", proto);
1775 if (ret < 0 || ret >= end - pos)
1776 return pos;
1777 pos += ret;
1778
1779 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
1780 ret = os_snprintf(pos, end - pos, "?]");
1781 if (ret < 0 || ret >= end - pos)
1782 return pos;
1783 pos += ret;
1784 return pos;
1785 }
1786
1787 first = 1;
1788 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1789 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
1790 if (ret < 0 || ret >= end - pos)
1791 return pos;
1792 pos += ret;
1793 first = 0;
1794 }
1795 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
1796 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
1797 if (ret < 0 || ret >= end - pos)
1798 return pos;
1799 pos += ret;
1800 first = 0;
1801 }
1802 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
1803 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
1804 if (ret < 0 || ret >= end - pos)
1805 return pos;
1806 pos += ret;
1807 first = 0;
1808 }
1809#ifdef CONFIG_IEEE80211R
1810 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1811 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
1812 first ? "" : "+");
1813 if (ret < 0 || ret >= end - pos)
1814 return pos;
1815 pos += ret;
1816 first = 0;
1817 }
1818 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1819 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
1820 first ? "" : "+");
1821 if (ret < 0 || ret >= end - pos)
1822 return pos;
1823 pos += ret;
1824 first = 0;
1825 }
1826#endif /* CONFIG_IEEE80211R */
1827#ifdef CONFIG_IEEE80211W
1828 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1829 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
1830 first ? "" : "+");
1831 if (ret < 0 || ret >= end - pos)
1832 return pos;
1833 pos += ret;
1834 first = 0;
1835 }
1836 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1837 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
1838 first ? "" : "+");
1839 if (ret < 0 || ret >= end - pos)
1840 return pos;
1841 pos += ret;
1842 first = 0;
1843 }
1844#endif /* CONFIG_IEEE80211W */
1845
1846 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
1847
1848 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
1849 ret = os_snprintf(pos, end - pos, "-preauth");
1850 if (ret < 0 || ret >= end - pos)
1851 return pos;
1852 pos += ret;
1853 }
1854
1855 ret = os_snprintf(pos, end - pos, "]");
1856 if (ret < 0 || ret >= end - pos)
1857 return pos;
1858 pos += ret;
1859
1860 return pos;
1861}
1862
1863
1864#ifdef CONFIG_WPS
1865static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
1866 char *pos, char *end,
1867 struct wpabuf *wps_ie)
1868{
1869 int ret;
1870 const char *txt;
1871
1872 if (wps_ie == NULL)
1873 return pos;
1874 if (wps_is_selected_pbc_registrar(wps_ie))
1875 txt = "[WPS-PBC]";
1876#ifdef CONFIG_WPS2
1877 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
1878 txt = "[WPS-AUTH]";
1879#endif /* CONFIG_WPS2 */
1880 else if (wps_is_selected_pin_registrar(wps_ie))
1881 txt = "[WPS-PIN]";
1882 else
1883 txt = "[WPS]";
1884
1885 ret = os_snprintf(pos, end - pos, "%s", txt);
1886 if (ret >= 0 && ret < end - pos)
1887 pos += ret;
1888 wpabuf_free(wps_ie);
1889 return pos;
1890}
1891#endif /* CONFIG_WPS */
1892
1893
1894static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
1895 char *pos, char *end,
1896 const struct wpa_bss *bss)
1897{
1898#ifdef CONFIG_WPS
1899 struct wpabuf *wps_ie;
1900 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1901 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
1902#else /* CONFIG_WPS */
1903 return pos;
1904#endif /* CONFIG_WPS */
1905}
1906
1907
1908/* Format one result on one text line into a buffer. */
1909static int wpa_supplicant_ctrl_iface_scan_result(
1910 struct wpa_supplicant *wpa_s,
1911 const struct wpa_bss *bss, char *buf, size_t buflen)
1912{
1913 char *pos, *end;
1914 int ret;
1915 const u8 *ie, *ie2, *p2p;
1916
1917 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
1918 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
1919 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
1920 0)
1921 return 0; /* Do not show P2P listen discovery results here */
1922
1923 pos = buf;
1924 end = buf + buflen;
1925
1926 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
1927 MAC2STR(bss->bssid), bss->freq, bss->level);
1928 if (ret < 0 || ret >= end - pos)
1929 return -1;
1930 pos += ret;
1931 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1932 if (ie)
1933 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1934 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1935 if (ie2)
1936 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1937 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
1938 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1939 ret = os_snprintf(pos, end - pos, "[WEP]");
1940 if (ret < 0 || ret >= end - pos)
1941 return -1;
1942 pos += ret;
1943 }
1944 if (bss->caps & IEEE80211_CAP_IBSS) {
1945 ret = os_snprintf(pos, end - pos, "[IBSS]");
1946 if (ret < 0 || ret >= end - pos)
1947 return -1;
1948 pos += ret;
1949 }
1950 if (bss->caps & IEEE80211_CAP_ESS) {
1951 ret = os_snprintf(pos, end - pos, "[ESS]");
1952 if (ret < 0 || ret >= end - pos)
1953 return -1;
1954 pos += ret;
1955 }
1956 if (p2p) {
1957 ret = os_snprintf(pos, end - pos, "[P2P]");
1958 if (ret < 0 || ret >= end - pos)
1959 return -1;
1960 pos += ret;
1961 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001962#ifdef CONFIG_HS20
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001963 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001964 ret = os_snprintf(pos, end - pos, "[HS20]");
1965 if (ret < 0 || ret >= end - pos)
1966 return -1;
1967 pos += ret;
1968 }
1969#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970
1971 ret = os_snprintf(pos, end - pos, "\t%s",
1972 wpa_ssid_txt(bss->ssid, bss->ssid_len));
1973 if (ret < 0 || ret >= end - pos)
1974 return -1;
1975 pos += ret;
1976
1977 ret = os_snprintf(pos, end - pos, "\n");
1978 if (ret < 0 || ret >= end - pos)
1979 return -1;
1980 pos += ret;
1981
1982 return pos - buf;
1983}
1984
1985
1986static int wpa_supplicant_ctrl_iface_scan_results(
1987 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1988{
1989 char *pos, *end;
1990 struct wpa_bss *bss;
1991 int ret;
1992
1993 pos = buf;
1994 end = buf + buflen;
1995 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
1996 "flags / ssid\n");
1997 if (ret < 0 || ret >= end - pos)
1998 return pos - buf;
1999 pos += ret;
2000
2001 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2002 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
2003 end - pos);
2004 if (ret < 0 || ret >= end - pos)
2005 return pos - buf;
2006 pos += ret;
2007 }
2008
2009 return pos - buf;
2010}
2011
2012
2013static int wpa_supplicant_ctrl_iface_select_network(
2014 struct wpa_supplicant *wpa_s, char *cmd)
2015{
2016 int id;
2017 struct wpa_ssid *ssid;
2018
2019 /* cmd: "<network id>" or "any" */
2020 if (os_strcmp(cmd, "any") == 0) {
2021 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
2022 ssid = NULL;
2023 } else {
2024 id = atoi(cmd);
2025 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
2026
2027 ssid = wpa_config_get_network(wpa_s->conf, id);
2028 if (ssid == NULL) {
2029 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2030 "network id=%d", id);
2031 return -1;
2032 }
2033 if (ssid->disabled == 2) {
2034 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2035 "SELECT_NETWORK with persistent P2P group");
2036 return -1;
2037 }
2038 }
2039
2040 wpa_supplicant_select_network(wpa_s, ssid);
2041
2042 return 0;
2043}
2044
2045
2046static int wpa_supplicant_ctrl_iface_enable_network(
2047 struct wpa_supplicant *wpa_s, char *cmd)
2048{
2049 int id;
2050 struct wpa_ssid *ssid;
2051
2052 /* cmd: "<network id>" or "all" */
2053 if (os_strcmp(cmd, "all") == 0) {
2054 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
2055 ssid = NULL;
2056 } else {
2057 id = atoi(cmd);
2058 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
2059
2060 ssid = wpa_config_get_network(wpa_s->conf, id);
2061 if (ssid == NULL) {
2062 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2063 "network id=%d", id);
2064 return -1;
2065 }
2066 if (ssid->disabled == 2) {
2067 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2068 "ENABLE_NETWORK with persistent P2P group");
2069 return -1;
2070 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002071
2072 if (os_strstr(cmd, " no-connect")) {
2073 ssid->disabled = 0;
2074 return 0;
2075 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002076 }
2077 wpa_supplicant_enable_network(wpa_s, ssid);
2078
2079 return 0;
2080}
2081
2082
2083static int wpa_supplicant_ctrl_iface_disable_network(
2084 struct wpa_supplicant *wpa_s, char *cmd)
2085{
2086 int id;
2087 struct wpa_ssid *ssid;
2088
2089 /* cmd: "<network id>" or "all" */
2090 if (os_strcmp(cmd, "all") == 0) {
2091 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
2092 ssid = NULL;
2093 } else {
2094 id = atoi(cmd);
2095 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
2096
2097 ssid = wpa_config_get_network(wpa_s->conf, id);
2098 if (ssid == NULL) {
2099 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2100 "network id=%d", id);
2101 return -1;
2102 }
2103 if (ssid->disabled == 2) {
2104 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2105 "DISABLE_NETWORK with persistent P2P "
2106 "group");
2107 return -1;
2108 }
2109 }
2110 wpa_supplicant_disable_network(wpa_s, ssid);
2111
2112 return 0;
2113}
2114
2115
2116static int wpa_supplicant_ctrl_iface_add_network(
2117 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2118{
2119 struct wpa_ssid *ssid;
2120 int ret;
2121
2122 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
2123
2124 ssid = wpa_config_add_network(wpa_s->conf);
2125 if (ssid == NULL)
2126 return -1;
2127
2128 wpas_notify_network_added(wpa_s, ssid);
2129
2130 ssid->disabled = 1;
2131 wpa_config_set_network_defaults(ssid);
2132
2133 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
2134 if (ret < 0 || (size_t) ret >= buflen)
2135 return -1;
2136 return ret;
2137}
2138
2139
2140static int wpa_supplicant_ctrl_iface_remove_network(
2141 struct wpa_supplicant *wpa_s, char *cmd)
2142{
2143 int id;
2144 struct wpa_ssid *ssid;
2145
2146 /* cmd: "<network id>" or "all" */
2147 if (os_strcmp(cmd, "all") == 0) {
2148 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
2149 ssid = wpa_s->conf->ssid;
2150 while (ssid) {
2151 struct wpa_ssid *remove_ssid = ssid;
2152 id = ssid->id;
2153 ssid = ssid->next;
2154 wpas_notify_network_removed(wpa_s, remove_ssid);
2155 wpa_config_remove_network(wpa_s->conf, id);
2156 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002157 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002158 if (wpa_s->current_ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002159#ifdef CONFIG_SME
2160 wpa_s->sme.prev_bssid_set = 0;
2161#endif /* CONFIG_SME */
Jouni Malinen75ecf522011-06-27 15:19:46 -07002162 wpa_sm_set_config(wpa_s->wpa, NULL);
2163 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002164 wpa_supplicant_deauthenticate(
2165 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002166 }
2167 return 0;
2168 }
2169
2170 id = atoi(cmd);
2171 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
2172
2173 ssid = wpa_config_get_network(wpa_s->conf, id);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002174 if (ssid)
2175 wpas_notify_network_removed(wpa_s, ssid);
Deepthi Gowria831d782012-09-03 11:55:38 +03002176 if (ssid == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002177 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2178 "id=%d", id);
2179 return -1;
2180 }
2181
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002182 if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002183#ifdef CONFIG_SME
2184 wpa_s->sme.prev_bssid_set = 0;
2185#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002186 /*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002187 * Invalidate the EAP session cache if the current or
2188 * previously used network is removed.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002189 */
2190 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002191 }
2192
2193 if (ssid == wpa_s->current_ssid) {
Jouni Malinen75ecf522011-06-27 15:19:46 -07002194 wpa_sm_set_config(wpa_s->wpa, NULL);
2195 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002196
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002197 wpa_supplicant_deauthenticate(wpa_s,
2198 WLAN_REASON_DEAUTH_LEAVING);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002199 }
2200
Deepthi Gowria831d782012-09-03 11:55:38 +03002201 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
2202 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
2203 "network id=%d", id);
2204 return -1;
2205 }
2206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002207 return 0;
2208}
2209
2210
2211static int wpa_supplicant_ctrl_iface_set_network(
2212 struct wpa_supplicant *wpa_s, char *cmd)
2213{
2214 int id;
2215 struct wpa_ssid *ssid;
2216 char *name, *value;
2217
2218 /* cmd: "<network id> <variable name> <value>" */
2219 name = os_strchr(cmd, ' ');
2220 if (name == NULL)
2221 return -1;
2222 *name++ = '\0';
2223
2224 value = os_strchr(name, ' ');
2225 if (value == NULL)
2226 return -1;
2227 *value++ = '\0';
2228
2229 id = atoi(cmd);
2230 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
2231 id, name);
2232 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2233 (u8 *) value, os_strlen(value));
2234
2235 ssid = wpa_config_get_network(wpa_s->conf, id);
2236 if (ssid == NULL) {
2237 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2238 "id=%d", id);
2239 return -1;
2240 }
2241
2242 if (wpa_config_set(ssid, name, value, 0) < 0) {
2243 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
2244 "variable '%s'", name);
2245 return -1;
2246 }
2247
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002248 if (os_strcmp(name, "bssid") != 0 &&
2249 os_strcmp(name, "priority") != 0)
2250 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002251
2252 if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002253 /*
2254 * Invalidate the EAP session cache if anything in the current
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002255 * or previously used configuration changes.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002256 */
2257 eapol_sm_invalidate_cached_session(wpa_s->eapol);
2258 }
2259
2260 if ((os_strcmp(name, "psk") == 0 &&
2261 value[0] == '"' && ssid->ssid_len) ||
2262 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
2263 wpa_config_update_psk(ssid);
2264 else if (os_strcmp(name, "priority") == 0)
2265 wpa_config_update_prio_list(wpa_s->conf);
2266
2267 return 0;
2268}
2269
2270
2271static int wpa_supplicant_ctrl_iface_get_network(
2272 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
2273{
2274 int id;
2275 size_t res;
2276 struct wpa_ssid *ssid;
2277 char *name, *value;
2278
2279 /* cmd: "<network id> <variable name>" */
2280 name = os_strchr(cmd, ' ');
2281 if (name == NULL || buflen == 0)
2282 return -1;
2283 *name++ = '\0';
2284
2285 id = atoi(cmd);
2286 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
2287 id, name);
2288
2289 ssid = wpa_config_get_network(wpa_s->conf, id);
2290 if (ssid == NULL) {
2291 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2292 "id=%d", id);
2293 return -1;
2294 }
2295
2296 value = wpa_config_get_no_key(ssid, name);
2297 if (value == NULL) {
2298 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
2299 "variable '%s'", name);
2300 return -1;
2301 }
2302
2303 res = os_strlcpy(buf, value, buflen);
2304 if (res >= buflen) {
2305 os_free(value);
2306 return -1;
2307 }
2308
2309 os_free(value);
2310
2311 return res;
2312}
2313
2314
Dmitry Shmidt04949592012-07-19 12:16:46 -07002315static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
2316 char *buf, size_t buflen)
2317{
2318 char *pos, *end;
2319 struct wpa_cred *cred;
2320 int ret;
2321
2322 pos = buf;
2323 end = buf + buflen;
2324 ret = os_snprintf(pos, end - pos,
2325 "cred id / realm / username / domain / imsi\n");
2326 if (ret < 0 || ret >= end - pos)
2327 return pos - buf;
2328 pos += ret;
2329
2330 cred = wpa_s->conf->cred;
2331 while (cred) {
2332 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
2333 cred->id, cred->realm ? cred->realm : "",
2334 cred->username ? cred->username : "",
2335 cred->domain ? cred->domain : "",
2336 cred->imsi ? cred->imsi : "");
2337 if (ret < 0 || ret >= end - pos)
2338 return pos - buf;
2339 pos += ret;
2340
2341 cred = cred->next;
2342 }
2343
2344 return pos - buf;
2345}
2346
2347
2348static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
2349 char *buf, size_t buflen)
2350{
2351 struct wpa_cred *cred;
2352 int ret;
2353
2354 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
2355
2356 cred = wpa_config_add_cred(wpa_s->conf);
2357 if (cred == NULL)
2358 return -1;
2359
2360 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
2361 if (ret < 0 || (size_t) ret >= buflen)
2362 return -1;
2363 return ret;
2364}
2365
2366
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002367static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
2368 struct wpa_cred *cred)
2369{
2370 struct wpa_ssid *ssid;
2371 char str[20];
2372
2373 if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
2374 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
2375 return -1;
2376 }
2377
2378 /* Remove any network entry created based on the removed credential */
2379 ssid = wpa_s->conf->ssid;
2380 while (ssid) {
2381 if (ssid->parent_cred == cred) {
2382 wpa_printf(MSG_DEBUG, "Remove network id %d since it "
2383 "used the removed credential", ssid->id);
2384 os_snprintf(str, sizeof(str), "%d", ssid->id);
2385 ssid = ssid->next;
2386 wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
2387 } else
2388 ssid = ssid->next;
2389 }
2390
2391 return 0;
2392}
2393
2394
Dmitry Shmidt04949592012-07-19 12:16:46 -07002395static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
2396 char *cmd)
2397{
2398 int id;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002399 struct wpa_cred *cred, *prev;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002400
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002401 /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002402 if (os_strcmp(cmd, "all") == 0) {
2403 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
2404 cred = wpa_s->conf->cred;
2405 while (cred) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002406 prev = cred;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002407 cred = cred->next;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002408 wpas_ctrl_remove_cred(wpa_s, prev);
2409 }
2410 return 0;
2411 }
2412
2413 if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
2414 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
2415 cmd + 8);
2416 cred = wpa_s->conf->cred;
2417 while (cred) {
2418 prev = cred;
2419 cred = cred->next;
2420 if (prev->domain &&
2421 os_strcmp(prev->domain, cmd + 8) == 0)
2422 wpas_ctrl_remove_cred(wpa_s, prev);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002423 }
2424 return 0;
2425 }
2426
2427 id = atoi(cmd);
2428 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
2429
2430 cred = wpa_config_get_cred(wpa_s->conf, id);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002431 return wpas_ctrl_remove_cred(wpa_s, cred);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002432}
2433
2434
2435static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
2436 char *cmd)
2437{
2438 int id;
2439 struct wpa_cred *cred;
2440 char *name, *value;
2441
2442 /* cmd: "<cred id> <variable name> <value>" */
2443 name = os_strchr(cmd, ' ');
2444 if (name == NULL)
2445 return -1;
2446 *name++ = '\0';
2447
2448 value = os_strchr(name, ' ');
2449 if (value == NULL)
2450 return -1;
2451 *value++ = '\0';
2452
2453 id = atoi(cmd);
2454 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
2455 id, name);
2456 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2457 (u8 *) value, os_strlen(value));
2458
2459 cred = wpa_config_get_cred(wpa_s->conf, id);
2460 if (cred == NULL) {
2461 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
2462 id);
2463 return -1;
2464 }
2465
2466 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
2467 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
2468 "variable '%s'", name);
2469 return -1;
2470 }
2471
2472 return 0;
2473}
2474
2475
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002476#ifndef CONFIG_NO_CONFIG_WRITE
2477static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
2478{
2479 int ret;
2480
2481 if (!wpa_s->conf->update_config) {
2482 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
2483 "to update configuration (update_config=0)");
2484 return -1;
2485 }
2486
2487 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2488 if (ret) {
2489 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
2490 "update configuration");
2491 } else {
2492 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
2493 " updated");
2494 }
2495
2496 return ret;
2497}
2498#endif /* CONFIG_NO_CONFIG_WRITE */
2499
2500
2501static int ctrl_iface_get_capability_pairwise(int res, char *strict,
2502 struct wpa_driver_capa *capa,
2503 char *buf, size_t buflen)
2504{
2505 int ret, first = 1;
2506 char *pos, *end;
2507 size_t len;
2508
2509 pos = buf;
2510 end = pos + buflen;
2511
2512 if (res < 0) {
2513 if (strict)
2514 return 0;
2515 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
2516 if (len >= buflen)
2517 return -1;
2518 return len;
2519 }
2520
2521 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2522 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2523 if (ret < 0 || ret >= end - pos)
2524 return pos - buf;
2525 pos += ret;
2526 first = 0;
2527 }
2528
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002529 if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2530 ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
2531 if (ret < 0 || ret >= end - pos)
2532 return pos - buf;
2533 pos += ret;
2534 first = 0;
2535 }
2536
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002537 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2538 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2539 if (ret < 0 || ret >= end - pos)
2540 return pos - buf;
2541 pos += ret;
2542 first = 0;
2543 }
2544
2545 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2546 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
2547 if (ret < 0 || ret >= end - pos)
2548 return pos - buf;
2549 pos += ret;
2550 first = 0;
2551 }
2552
2553 return pos - buf;
2554}
2555
2556
2557static int ctrl_iface_get_capability_group(int res, char *strict,
2558 struct wpa_driver_capa *capa,
2559 char *buf, size_t buflen)
2560{
2561 int ret, first = 1;
2562 char *pos, *end;
2563 size_t len;
2564
2565 pos = buf;
2566 end = pos + buflen;
2567
2568 if (res < 0) {
2569 if (strict)
2570 return 0;
2571 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
2572 if (len >= buflen)
2573 return -1;
2574 return len;
2575 }
2576
2577 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2578 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2579 if (ret < 0 || ret >= end - pos)
2580 return pos - buf;
2581 pos += ret;
2582 first = 0;
2583 }
2584
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002585 if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2586 ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
2587 if (ret < 0 || ret >= end - pos)
2588 return pos - buf;
2589 pos += ret;
2590 first = 0;
2591 }
2592
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002593 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2594 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2595 if (ret < 0 || ret >= end - pos)
2596 return pos - buf;
2597 pos += ret;
2598 first = 0;
2599 }
2600
2601 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2602 ret = os_snprintf(pos, end - pos, "%sWEP104",
2603 first ? "" : " ");
2604 if (ret < 0 || ret >= end - pos)
2605 return pos - buf;
2606 pos += ret;
2607 first = 0;
2608 }
2609
2610 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2611 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
2612 if (ret < 0 || ret >= end - pos)
2613 return pos - buf;
2614 pos += ret;
2615 first = 0;
2616 }
2617
2618 return pos - buf;
2619}
2620
2621
2622static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
2623 struct wpa_driver_capa *capa,
2624 char *buf, size_t buflen)
2625{
2626 int ret;
2627 char *pos, *end;
2628 size_t len;
2629
2630 pos = buf;
2631 end = pos + buflen;
2632
2633 if (res < 0) {
2634 if (strict)
2635 return 0;
2636 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
2637 "NONE", buflen);
2638 if (len >= buflen)
2639 return -1;
2640 return len;
2641 }
2642
2643 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
2644 if (ret < 0 || ret >= end - pos)
2645 return pos - buf;
2646 pos += ret;
2647
2648 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2649 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2650 ret = os_snprintf(pos, end - pos, " WPA-EAP");
2651 if (ret < 0 || ret >= end - pos)
2652 return pos - buf;
2653 pos += ret;
2654 }
2655
2656 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2657 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2658 ret = os_snprintf(pos, end - pos, " WPA-PSK");
2659 if (ret < 0 || ret >= end - pos)
2660 return pos - buf;
2661 pos += ret;
2662 }
2663
2664 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2665 ret = os_snprintf(pos, end - pos, " WPA-NONE");
2666 if (ret < 0 || ret >= end - pos)
2667 return pos - buf;
2668 pos += ret;
2669 }
2670
2671 return pos - buf;
2672}
2673
2674
2675static int ctrl_iface_get_capability_proto(int res, char *strict,
2676 struct wpa_driver_capa *capa,
2677 char *buf, size_t buflen)
2678{
2679 int ret, first = 1;
2680 char *pos, *end;
2681 size_t len;
2682
2683 pos = buf;
2684 end = pos + buflen;
2685
2686 if (res < 0) {
2687 if (strict)
2688 return 0;
2689 len = os_strlcpy(buf, "RSN WPA", buflen);
2690 if (len >= buflen)
2691 return -1;
2692 return len;
2693 }
2694
2695 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2696 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2697 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
2698 if (ret < 0 || ret >= end - pos)
2699 return pos - buf;
2700 pos += ret;
2701 first = 0;
2702 }
2703
2704 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2705 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2706 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
2707 if (ret < 0 || ret >= end - pos)
2708 return pos - buf;
2709 pos += ret;
2710 first = 0;
2711 }
2712
2713 return pos - buf;
2714}
2715
2716
2717static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
2718 struct wpa_driver_capa *capa,
2719 char *buf, size_t buflen)
2720{
2721 int ret, first = 1;
2722 char *pos, *end;
2723 size_t len;
2724
2725 pos = buf;
2726 end = pos + buflen;
2727
2728 if (res < 0) {
2729 if (strict)
2730 return 0;
2731 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
2732 if (len >= buflen)
2733 return -1;
2734 return len;
2735 }
2736
2737 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
2738 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
2739 if (ret < 0 || ret >= end - pos)
2740 return pos - buf;
2741 pos += ret;
2742 first = 0;
2743 }
2744
2745 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
2746 ret = os_snprintf(pos, end - pos, "%sSHARED",
2747 first ? "" : " ");
2748 if (ret < 0 || ret >= end - pos)
2749 return pos - buf;
2750 pos += ret;
2751 first = 0;
2752 }
2753
2754 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
2755 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
2756 if (ret < 0 || ret >= end - pos)
2757 return pos - buf;
2758 pos += ret;
2759 first = 0;
2760 }
2761
2762 return pos - buf;
2763}
2764
2765
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002766static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
2767 char *buf, size_t buflen)
2768{
2769 struct hostapd_channel_data *chnl;
2770 int ret, i, j;
2771 char *pos, *end, *hmode;
2772
2773 pos = buf;
2774 end = pos + buflen;
2775
2776 for (j = 0; j < wpa_s->hw.num_modes; j++) {
2777 switch (wpa_s->hw.modes[j].mode) {
2778 case HOSTAPD_MODE_IEEE80211B:
2779 hmode = "B";
2780 break;
2781 case HOSTAPD_MODE_IEEE80211G:
2782 hmode = "G";
2783 break;
2784 case HOSTAPD_MODE_IEEE80211A:
2785 hmode = "A";
2786 break;
2787 default:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002788 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002789 }
2790 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
2791 if (ret < 0 || ret >= end - pos)
2792 return pos - buf;
2793 pos += ret;
2794 chnl = wpa_s->hw.modes[j].channels;
2795 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002796 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
2797 continue;
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002798 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
2799 if (ret < 0 || ret >= end - pos)
2800 return pos - buf;
2801 pos += ret;
2802 }
2803 ret = os_snprintf(pos, end - pos, "\n");
2804 if (ret < 0 || ret >= end - pos)
2805 return pos - buf;
2806 pos += ret;
2807 }
2808
2809 return pos - buf;
2810}
2811
2812
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002813static int wpa_supplicant_ctrl_iface_get_capability(
2814 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
2815 size_t buflen)
2816{
2817 struct wpa_driver_capa capa;
2818 int res;
2819 char *strict;
2820 char field[30];
2821 size_t len;
2822
2823 /* Determine whether or not strict checking was requested */
2824 len = os_strlcpy(field, _field, sizeof(field));
2825 if (len >= sizeof(field))
2826 return -1;
2827 strict = os_strchr(field, ' ');
2828 if (strict != NULL) {
2829 *strict++ = '\0';
2830 if (os_strcmp(strict, "strict") != 0)
2831 return -1;
2832 }
2833
2834 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
2835 field, strict ? strict : "");
2836
2837 if (os_strcmp(field, "eap") == 0) {
2838 return eap_get_names(buf, buflen);
2839 }
2840
2841 res = wpa_drv_get_capa(wpa_s, &capa);
2842
2843 if (os_strcmp(field, "pairwise") == 0)
2844 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
2845 buf, buflen);
2846
2847 if (os_strcmp(field, "group") == 0)
2848 return ctrl_iface_get_capability_group(res, strict, &capa,
2849 buf, buflen);
2850
2851 if (os_strcmp(field, "key_mgmt") == 0)
2852 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
2853 buf, buflen);
2854
2855 if (os_strcmp(field, "proto") == 0)
2856 return ctrl_iface_get_capability_proto(res, strict, &capa,
2857 buf, buflen);
2858
2859 if (os_strcmp(field, "auth_alg") == 0)
2860 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
2861 buf, buflen);
2862
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002863 if (os_strcmp(field, "channels") == 0)
2864 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
2865
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002866 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
2867 field);
2868
2869 return -1;
2870}
2871
2872
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002873#ifdef CONFIG_INTERWORKING
2874static char * anqp_add_hex(char *pos, char *end, const char *title,
2875 struct wpabuf *data)
2876{
2877 char *start = pos;
2878 size_t i;
2879 int ret;
2880 const u8 *d;
2881
2882 if (data == NULL)
2883 return start;
2884
2885 ret = os_snprintf(pos, end - pos, "%s=", title);
2886 if (ret < 0 || ret >= end - pos)
2887 return start;
2888 pos += ret;
2889
2890 d = wpabuf_head_u8(data);
2891 for (i = 0; i < wpabuf_len(data); i++) {
2892 ret = os_snprintf(pos, end - pos, "%02x", *d++);
2893 if (ret < 0 || ret >= end - pos)
2894 return start;
2895 pos += ret;
2896 }
2897
2898 ret = os_snprintf(pos, end - pos, "\n");
2899 if (ret < 0 || ret >= end - pos)
2900 return start;
2901 pos += ret;
2902
2903 return pos;
2904}
2905#endif /* CONFIG_INTERWORKING */
2906
2907
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002908static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
2909 unsigned long mask, char *buf, size_t buflen)
2910{
2911 size_t i;
2912 int ret;
2913 char *pos, *end;
2914 const u8 *ie, *ie2;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002915
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002916 pos = buf;
2917 end = buf + buflen;
2918
2919 if (mask & WPA_BSS_MASK_ID) {
2920 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
2921 if (ret < 0 || ret >= end - pos)
2922 return 0;
2923 pos += ret;
2924 }
2925
2926 if (mask & WPA_BSS_MASK_BSSID) {
2927 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
2928 MAC2STR(bss->bssid));
2929 if (ret < 0 || ret >= end - pos)
2930 return 0;
2931 pos += ret;
2932 }
2933
2934 if (mask & WPA_BSS_MASK_FREQ) {
2935 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
2936 if (ret < 0 || ret >= end - pos)
2937 return 0;
2938 pos += ret;
2939 }
2940
2941 if (mask & WPA_BSS_MASK_BEACON_INT) {
2942 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
2943 bss->beacon_int);
2944 if (ret < 0 || ret >= end - pos)
2945 return 0;
2946 pos += ret;
2947 }
2948
2949 if (mask & WPA_BSS_MASK_CAPABILITIES) {
2950 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
2951 bss->caps);
2952 if (ret < 0 || ret >= end - pos)
2953 return 0;
2954 pos += ret;
2955 }
2956
2957 if (mask & WPA_BSS_MASK_QUAL) {
2958 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
2959 if (ret < 0 || ret >= end - pos)
2960 return 0;
2961 pos += ret;
2962 }
2963
2964 if (mask & WPA_BSS_MASK_NOISE) {
2965 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
2966 if (ret < 0 || ret >= end - pos)
2967 return 0;
2968 pos += ret;
2969 }
2970
2971 if (mask & WPA_BSS_MASK_LEVEL) {
2972 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
2973 if (ret < 0 || ret >= end - pos)
2974 return 0;
2975 pos += ret;
2976 }
2977
2978 if (mask & WPA_BSS_MASK_TSF) {
2979 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
2980 (unsigned long long) bss->tsf);
2981 if (ret < 0 || ret >= end - pos)
2982 return 0;
2983 pos += ret;
2984 }
2985
2986 if (mask & WPA_BSS_MASK_AGE) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002987 struct os_time now;
2988
2989 os_get_time(&now);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002990 ret = os_snprintf(pos, end - pos, "age=%d\n",
2991 (int) (now.sec - bss->last_update.sec));
2992 if (ret < 0 || ret >= end - pos)
2993 return 0;
2994 pos += ret;
2995 }
2996
2997 if (mask & WPA_BSS_MASK_IE) {
2998 ret = os_snprintf(pos, end - pos, "ie=");
2999 if (ret < 0 || ret >= end - pos)
3000 return 0;
3001 pos += ret;
3002
3003 ie = (const u8 *) (bss + 1);
3004 for (i = 0; i < bss->ie_len; i++) {
3005 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
3006 if (ret < 0 || ret >= end - pos)
3007 return 0;
3008 pos += ret;
3009 }
3010
3011 ret = os_snprintf(pos, end - pos, "\n");
3012 if (ret < 0 || ret >= end - pos)
3013 return 0;
3014 pos += ret;
3015 }
3016
3017 if (mask & WPA_BSS_MASK_FLAGS) {
3018 ret = os_snprintf(pos, end - pos, "flags=");
3019 if (ret < 0 || ret >= end - pos)
3020 return 0;
3021 pos += ret;
3022
3023 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
3024 if (ie)
3025 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
3026 2 + ie[1]);
3027 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
3028 if (ie2)
3029 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
3030 2 + ie2[1]);
3031 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
3032 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
3033 ret = os_snprintf(pos, end - pos, "[WEP]");
3034 if (ret < 0 || ret >= end - pos)
3035 return 0;
3036 pos += ret;
3037 }
3038 if (bss->caps & IEEE80211_CAP_IBSS) {
3039 ret = os_snprintf(pos, end - pos, "[IBSS]");
3040 if (ret < 0 || ret >= end - pos)
3041 return 0;
3042 pos += ret;
3043 }
3044 if (bss->caps & IEEE80211_CAP_ESS) {
3045 ret = os_snprintf(pos, end - pos, "[ESS]");
3046 if (ret < 0 || ret >= end - pos)
3047 return 0;
3048 pos += ret;
3049 }
3050 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
3051 ret = os_snprintf(pos, end - pos, "[P2P]");
3052 if (ret < 0 || ret >= end - pos)
3053 return 0;
3054 pos += ret;
3055 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003056#ifdef CONFIG_HS20
3057 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
3058 ret = os_snprintf(pos, end - pos, "[HS20]");
3059 if (ret < 0 || ret >= end - pos)
3060 return -1;
3061 pos += ret;
3062 }
3063#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003064
3065 ret = os_snprintf(pos, end - pos, "\n");
3066 if (ret < 0 || ret >= end - pos)
3067 return 0;
3068 pos += ret;
3069 }
3070
3071 if (mask & WPA_BSS_MASK_SSID) {
3072 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
3073 wpa_ssid_txt(bss->ssid, bss->ssid_len));
3074 if (ret < 0 || ret >= end - pos)
3075 return 0;
3076 pos += ret;
3077 }
3078
3079#ifdef CONFIG_WPS
3080 if (mask & WPA_BSS_MASK_WPS_SCAN) {
3081 ie = (const u8 *) (bss + 1);
3082 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
3083 if (ret < 0 || ret >= end - pos)
3084 return 0;
3085 pos += ret;
3086 }
3087#endif /* CONFIG_WPS */
3088
3089#ifdef CONFIG_P2P
3090 if (mask & WPA_BSS_MASK_P2P_SCAN) {
3091 ie = (const u8 *) (bss + 1);
3092 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
3093 if (ret < 0 || ret >= end - pos)
3094 return 0;
3095 pos += ret;
3096 }
3097#endif /* CONFIG_P2P */
3098
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003099#ifdef CONFIG_WIFI_DISPLAY
3100 if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
3101 struct wpabuf *wfd;
3102 ie = (const u8 *) (bss + 1);
3103 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
3104 WFD_IE_VENDOR_TYPE);
3105 if (wfd) {
3106 ret = os_snprintf(pos, end - pos, "wfd_subelems=");
3107 if (ret < 0 || ret >= end - pos)
3108 return pos - buf;
3109 pos += ret;
3110
3111 pos += wpa_snprintf_hex(pos, end - pos,
3112 wpabuf_head(wfd),
3113 wpabuf_len(wfd));
3114 wpabuf_free(wfd);
3115
3116 ret = os_snprintf(pos, end - pos, "\n");
3117 if (ret < 0 || ret >= end - pos)
3118 return pos - buf;
3119 pos += ret;
3120 }
3121 }
3122#endif /* CONFIG_WIFI_DISPLAY */
3123
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003124#ifdef CONFIG_INTERWORKING
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003125 if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
3126 struct wpa_bss_anqp *anqp = bss->anqp;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003127 pos = anqp_add_hex(pos, end, "anqp_venue_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003128 anqp->venue_name);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003129 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003130 anqp->network_auth_type);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003131 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003132 anqp->roaming_consortium);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003133 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003134 anqp->ip_addr_type_availability);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003135 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003136 anqp->nai_realm);
3137 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003138 pos = anqp_add_hex(pos, end, "anqp_domain_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003139 anqp->domain_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003140#ifdef CONFIG_HS20
3141 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003142 anqp->hs20_operator_friendly_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003143 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003144 anqp->hs20_wan_metrics);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003145 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003146 anqp->hs20_connection_capability);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003147#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003148 }
3149#endif /* CONFIG_INTERWORKING */
3150
Irfan Sheriffe2ea0082012-08-13 10:56:16 -07003151#ifdef ANDROID
3152 ret = os_snprintf(pos, end - pos, "====\n");
3153 if (ret < 0 || ret >= end - pos)
3154 return 0;
3155 pos += ret;
3156#endif
3157
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003158 return pos - buf;
3159}
3160
Dmitry Shmidt04949592012-07-19 12:16:46 -07003161
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003162static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
3163 const char *cmd, char *buf,
3164 size_t buflen)
3165{
3166 u8 bssid[ETH_ALEN];
3167 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003168 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003169 struct wpa_bss *bsslast = NULL;
3170 struct dl_list *next;
3171 int ret = 0;
3172 int len;
3173 char *ctmp;
3174 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003175
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003176 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
3177 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
3178 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003179 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003180 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
3181 list_id);
3182 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07003183 unsigned int id1, id2;
3184
3185 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
3186 wpa_printf(MSG_INFO, "Wrong BSS range "
3187 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003188 return 0;
3189 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003190
3191 id1 = atoi(cmd + 6);
3192 bss = wpa_bss_get_id(wpa_s, id1);
3193 id2 = atoi(ctmp + 1);
3194 if (id2 == 0)
3195 bsslast = dl_list_last(&wpa_s->bss_id,
3196 struct wpa_bss,
3197 list_id);
3198 else {
3199 bsslast = wpa_bss_get_id(wpa_s, id2);
3200 if (bsslast == NULL && bss && id2 > id1) {
3201 struct wpa_bss *tmp = bss;
3202 for (;;) {
3203 next = tmp->list_id.next;
3204 if (next == &wpa_s->bss_id)
3205 break;
3206 tmp = dl_list_entry(
3207 next, struct wpa_bss,
3208 list_id);
3209 if (tmp->id > id2)
3210 break;
3211 bsslast = tmp;
3212 }
3213 }
3214 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003215 }
3216 } else if (os_strcmp(cmd, "FIRST") == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07003217 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003218 else if (os_strncmp(cmd, "ID-", 3) == 0) {
3219 i = atoi(cmd + 3);
3220 bss = wpa_bss_get_id(wpa_s, i);
3221 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
3222 i = atoi(cmd + 5);
3223 bss = wpa_bss_get_id(wpa_s, i);
3224 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003225 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003226 if (next == &wpa_s->bss_id)
3227 bss = NULL;
3228 else
3229 bss = dl_list_entry(next, struct wpa_bss,
3230 list_id);
3231 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003232#ifdef CONFIG_P2P
3233 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
3234 if (hwaddr_aton(cmd + 13, bssid) == 0)
3235 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
3236 else
3237 bss = NULL;
3238#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003239 } else if (hwaddr_aton(cmd, bssid) == 0)
3240 bss = wpa_bss_get_bssid(wpa_s, bssid);
3241 else {
3242 struct wpa_bss *tmp;
3243 i = atoi(cmd);
3244 bss = NULL;
3245 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
3246 {
3247 if (i-- == 0) {
3248 bss = tmp;
3249 break;
3250 }
3251 }
3252 }
3253
Dmitry Shmidt04949592012-07-19 12:16:46 -07003254 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
3255 mask = strtoul(ctmp + 5, NULL, 0x10);
3256 if (mask == 0)
3257 mask = WPA_BSS_MASK_ALL;
3258 }
3259
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003260 if (bss == NULL)
3261 return 0;
3262
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003263 if (bsslast == NULL)
3264 bsslast = bss;
3265 do {
3266 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
3267 ret += len;
3268 buf += len;
3269 buflen -= len;
3270 if (bss == bsslast)
3271 break;
3272 next = bss->list_id.next;
3273 if (next == &wpa_s->bss_id)
3274 break;
3275 bss = dl_list_entry(next, struct wpa_bss, list_id);
3276 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003277
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07003278 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003279}
3280
3281
3282static int wpa_supplicant_ctrl_iface_ap_scan(
3283 struct wpa_supplicant *wpa_s, char *cmd)
3284{
3285 int ap_scan = atoi(cmd);
3286 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
3287}
3288
3289
3290static int wpa_supplicant_ctrl_iface_scan_interval(
3291 struct wpa_supplicant *wpa_s, char *cmd)
3292{
3293 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07003294 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003295}
3296
3297
3298static int wpa_supplicant_ctrl_iface_bss_expire_age(
3299 struct wpa_supplicant *wpa_s, char *cmd)
3300{
3301 int expire_age = atoi(cmd);
3302 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
3303}
3304
3305
3306static int wpa_supplicant_ctrl_iface_bss_expire_count(
3307 struct wpa_supplicant *wpa_s, char *cmd)
3308{
3309 int expire_count = atoi(cmd);
3310 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
3311}
3312
3313
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07003314static int wpa_supplicant_ctrl_iface_bss_flush(
3315 struct wpa_supplicant *wpa_s, char *cmd)
3316{
3317 int flush_age = atoi(cmd);
3318
3319 if (flush_age == 0)
3320 wpa_bss_flush(wpa_s);
3321 else
3322 wpa_bss_flush_by_age(wpa_s, flush_age);
3323 return 0;
3324}
3325
3326
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003327static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
3328{
3329 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
3330 /* MLME-DELETEKEYS.request */
3331 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
3332 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
3333 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
3334 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
3335#ifdef CONFIG_IEEE80211W
3336 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
3337 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
3338#endif /* CONFIG_IEEE80211W */
3339
3340 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
3341 0);
3342 /* MLME-SETPROTECTION.request(None) */
3343 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
3344 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
3345 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
3346 wpa_sm_drop_sa(wpa_s->wpa);
3347}
3348
3349
3350static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
3351 char *addr)
3352{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003353#ifdef CONFIG_NO_SCAN_PROCESSING
3354 return -1;
3355#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003356 u8 bssid[ETH_ALEN];
3357 struct wpa_bss *bss;
3358 struct wpa_ssid *ssid = wpa_s->current_ssid;
3359
3360 if (hwaddr_aton(addr, bssid)) {
3361 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
3362 "address '%s'", addr);
3363 return -1;
3364 }
3365
3366 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
3367
3368 bss = wpa_bss_get_bssid(wpa_s, bssid);
3369 if (!bss) {
3370 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
3371 "from BSS table");
3372 return -1;
3373 }
3374
3375 /*
3376 * TODO: Find best network configuration block from configuration to
3377 * allow roaming to other networks
3378 */
3379
3380 if (!ssid) {
3381 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
3382 "configuration known for the target AP");
3383 return -1;
3384 }
3385
3386 wpa_s->reassociate = 1;
3387 wpa_supplicant_connect(wpa_s, bss, ssid);
3388
3389 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003390#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003391}
3392
3393
3394#ifdef CONFIG_P2P
3395static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
3396{
3397 unsigned int timeout = atoi(cmd);
3398 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003399 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
3400 char *pos;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003401 unsigned int search_delay;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003402
3403 if (os_strstr(cmd, "type=social"))
3404 type = P2P_FIND_ONLY_SOCIAL;
3405 else if (os_strstr(cmd, "type=progressive"))
3406 type = P2P_FIND_PROGRESSIVE;
3407
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003408 pos = os_strstr(cmd, "dev_id=");
3409 if (pos) {
3410 pos += 7;
3411 if (hwaddr_aton(pos, dev_id))
3412 return -1;
3413 _dev_id = dev_id;
3414 }
3415
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003416 pos = os_strstr(cmd, "delay=");
3417 if (pos) {
3418 pos += 6;
3419 search_delay = atoi(pos);
3420 } else
3421 search_delay = wpas_p2p_search_delay(wpa_s);
3422
3423 return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
3424 search_delay);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003425}
3426
3427
3428static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
3429 char *buf, size_t buflen)
3430{
3431 u8 addr[ETH_ALEN];
3432 char *pos, *pos2;
3433 char *pin = NULL;
3434 enum p2p_wps_method wps_method;
3435 int new_pin;
3436 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003437 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003438 int join;
3439 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003440 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003441 int go_intent = -1;
3442 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003443 int pd;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003444 int ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003445
Dmitry Shmidt04949592012-07-19 12:16:46 -07003446 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
3447 * [persistent|persistent=<network id>]
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003448 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
3449 * [ht40] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003450
3451 if (hwaddr_aton(cmd, addr))
3452 return -1;
3453
3454 pos = cmd + 17;
3455 if (*pos != ' ')
3456 return -1;
3457 pos++;
3458
3459 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003460 pos2 = os_strstr(pos, " persistent=");
3461 if (pos2) {
3462 struct wpa_ssid *ssid;
3463 persistent_id = atoi(pos2 + 12);
3464 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
3465 if (ssid == NULL || ssid->disabled != 2 ||
3466 ssid->mode != WPAS_MODE_P2P_GO) {
3467 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3468 "SSID id=%d for persistent P2P group (GO)",
3469 persistent_id);
3470 return -1;
3471 }
3472 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003473 join = os_strstr(pos, " join") != NULL;
3474 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003475 automatic = os_strstr(pos, " auto") != NULL;
3476 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003477 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003478
3479 pos2 = os_strstr(pos, " go_intent=");
3480 if (pos2) {
3481 pos2 += 11;
3482 go_intent = atoi(pos2);
3483 if (go_intent < 0 || go_intent > 15)
3484 return -1;
3485 }
3486
3487 pos2 = os_strstr(pos, " freq=");
3488 if (pos2) {
3489 pos2 += 6;
3490 freq = atoi(pos2);
3491 if (freq <= 0)
3492 return -1;
3493 }
3494
3495 if (os_strncmp(pos, "pin", 3) == 0) {
3496 /* Request random PIN (to be displayed) and enable the PIN */
3497 wps_method = WPS_PIN_DISPLAY;
3498 } else if (os_strncmp(pos, "pbc", 3) == 0) {
3499 wps_method = WPS_PBC;
3500 } else {
3501 pin = pos;
3502 pos = os_strchr(pin, ' ');
3503 wps_method = WPS_PIN_KEYPAD;
3504 if (pos) {
3505 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003506 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003507 wps_method = WPS_PIN_DISPLAY;
3508 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003509 if (!wps_pin_str_valid(pin)) {
3510 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
3511 return 17;
3512 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003513 }
3514
3515 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003516 persistent_group, automatic, join,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003517 auth, go_intent, freq, persistent_id, pd,
3518 ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003519 if (new_pin == -2) {
3520 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
3521 return 25;
3522 }
3523 if (new_pin == -3) {
3524 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
3525 return 25;
3526 }
3527 if (new_pin < 0)
3528 return -1;
3529 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
3530 ret = os_snprintf(buf, buflen, "%08d", new_pin);
3531 if (ret < 0 || (size_t) ret >= buflen)
3532 return -1;
3533 return ret;
3534 }
3535
3536 os_memcpy(buf, "OK\n", 3);
3537 return 3;
3538}
3539
3540
3541static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
3542{
3543 unsigned int timeout = atoi(cmd);
3544 return wpas_p2p_listen(wpa_s, timeout);
3545}
3546
3547
3548static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
3549{
3550 u8 addr[ETH_ALEN];
3551 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003552 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003553
Dmitry Shmidt04949592012-07-19 12:16:46 -07003554 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003555
3556 if (hwaddr_aton(cmd, addr))
3557 return -1;
3558
3559 pos = cmd + 17;
3560 if (*pos != ' ')
3561 return -1;
3562 pos++;
3563
Dmitry Shmidt04949592012-07-19 12:16:46 -07003564 if (os_strstr(pos, " join") != NULL)
3565 use = WPAS_P2P_PD_FOR_JOIN;
3566 else if (os_strstr(pos, " auto") != NULL)
3567 use = WPAS_P2P_PD_AUTO;
3568
3569 return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003570}
3571
3572
3573static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
3574 size_t buflen)
3575{
3576 struct wpa_ssid *ssid = wpa_s->current_ssid;
3577
3578 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
3579 ssid->passphrase == NULL)
3580 return -1;
3581
3582 os_strlcpy(buf, ssid->passphrase, buflen);
3583 return os_strlen(buf);
3584}
3585
3586
3587static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
3588 char *buf, size_t buflen)
3589{
3590 u64 ref;
3591 int res;
3592 u8 dst_buf[ETH_ALEN], *dst;
3593 struct wpabuf *tlvs;
3594 char *pos;
3595 size_t len;
3596
3597 if (hwaddr_aton(cmd, dst_buf))
3598 return -1;
3599 dst = dst_buf;
3600 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
3601 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
3602 dst = NULL;
3603 pos = cmd + 17;
3604 if (*pos != ' ')
3605 return -1;
3606 pos++;
3607
3608 if (os_strncmp(pos, "upnp ", 5) == 0) {
3609 u8 version;
3610 pos += 5;
3611 if (hexstr2bin(pos, &version, 1) < 0)
3612 return -1;
3613 pos += 2;
3614 if (*pos != ' ')
3615 return -1;
3616 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003617 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003618#ifdef CONFIG_WIFI_DISPLAY
3619 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
3620 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
3621#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003622 } else {
3623 len = os_strlen(pos);
3624 if (len & 1)
3625 return -1;
3626 len /= 2;
3627 tlvs = wpabuf_alloc(len);
3628 if (tlvs == NULL)
3629 return -1;
3630 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
3631 wpabuf_free(tlvs);
3632 return -1;
3633 }
3634
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003635 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003636 wpabuf_free(tlvs);
3637 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003638 if (ref == 0)
3639 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003640 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
3641 if (res < 0 || (unsigned) res >= buflen)
3642 return -1;
3643 return res;
3644}
3645
3646
3647static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
3648 char *cmd)
3649{
3650 long long unsigned val;
3651 u64 req;
3652 if (sscanf(cmd, "%llx", &val) != 1)
3653 return -1;
3654 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003655 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003656}
3657
3658
3659static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
3660{
3661 int freq;
3662 u8 dst[ETH_ALEN];
3663 u8 dialog_token;
3664 struct wpabuf *resp_tlvs;
3665 char *pos, *pos2;
3666 size_t len;
3667
3668 pos = os_strchr(cmd, ' ');
3669 if (pos == NULL)
3670 return -1;
3671 *pos++ = '\0';
3672 freq = atoi(cmd);
3673 if (freq == 0)
3674 return -1;
3675
3676 if (hwaddr_aton(pos, dst))
3677 return -1;
3678 pos += 17;
3679 if (*pos != ' ')
3680 return -1;
3681 pos++;
3682
3683 pos2 = os_strchr(pos, ' ');
3684 if (pos2 == NULL)
3685 return -1;
3686 *pos2++ = '\0';
3687 dialog_token = atoi(pos);
3688
3689 len = os_strlen(pos2);
3690 if (len & 1)
3691 return -1;
3692 len /= 2;
3693 resp_tlvs = wpabuf_alloc(len);
3694 if (resp_tlvs == NULL)
3695 return -1;
3696 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
3697 wpabuf_free(resp_tlvs);
3698 return -1;
3699 }
3700
3701 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
3702 wpabuf_free(resp_tlvs);
3703 return 0;
3704}
3705
3706
3707static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
3708 char *cmd)
3709{
Dmitry Shmidt04949592012-07-19 12:16:46 -07003710 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
3711 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003712 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
3713 return 0;
3714}
3715
3716
3717static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
3718 char *cmd)
3719{
3720 char *pos;
3721 size_t len;
3722 struct wpabuf *query, *resp;
3723
3724 pos = os_strchr(cmd, ' ');
3725 if (pos == NULL)
3726 return -1;
3727 *pos++ = '\0';
3728
3729 len = os_strlen(cmd);
3730 if (len & 1)
3731 return -1;
3732 len /= 2;
3733 query = wpabuf_alloc(len);
3734 if (query == NULL)
3735 return -1;
3736 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3737 wpabuf_free(query);
3738 return -1;
3739 }
3740
3741 len = os_strlen(pos);
3742 if (len & 1) {
3743 wpabuf_free(query);
3744 return -1;
3745 }
3746 len /= 2;
3747 resp = wpabuf_alloc(len);
3748 if (resp == NULL) {
3749 wpabuf_free(query);
3750 return -1;
3751 }
3752 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
3753 wpabuf_free(query);
3754 wpabuf_free(resp);
3755 return -1;
3756 }
3757
3758 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
3759 wpabuf_free(query);
3760 wpabuf_free(resp);
3761 return -1;
3762 }
3763 return 0;
3764}
3765
3766
3767static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3768{
3769 char *pos;
3770 u8 version;
3771
3772 pos = os_strchr(cmd, ' ');
3773 if (pos == NULL)
3774 return -1;
3775 *pos++ = '\0';
3776
3777 if (hexstr2bin(cmd, &version, 1) < 0)
3778 return -1;
3779
3780 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
3781}
3782
3783
3784static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
3785{
3786 char *pos;
3787
3788 pos = os_strchr(cmd, ' ');
3789 if (pos == NULL)
3790 return -1;
3791 *pos++ = '\0';
3792
3793 if (os_strcmp(cmd, "bonjour") == 0)
3794 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
3795 if (os_strcmp(cmd, "upnp") == 0)
3796 return p2p_ctrl_service_add_upnp(wpa_s, pos);
3797 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3798 return -1;
3799}
3800
3801
3802static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
3803 char *cmd)
3804{
3805 size_t len;
3806 struct wpabuf *query;
3807 int ret;
3808
3809 len = os_strlen(cmd);
3810 if (len & 1)
3811 return -1;
3812 len /= 2;
3813 query = wpabuf_alloc(len);
3814 if (query == NULL)
3815 return -1;
3816 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3817 wpabuf_free(query);
3818 return -1;
3819 }
3820
3821 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
3822 wpabuf_free(query);
3823 return ret;
3824}
3825
3826
3827static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3828{
3829 char *pos;
3830 u8 version;
3831
3832 pos = os_strchr(cmd, ' ');
3833 if (pos == NULL)
3834 return -1;
3835 *pos++ = '\0';
3836
3837 if (hexstr2bin(cmd, &version, 1) < 0)
3838 return -1;
3839
3840 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
3841}
3842
3843
3844static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
3845{
3846 char *pos;
3847
3848 pos = os_strchr(cmd, ' ');
3849 if (pos == NULL)
3850 return -1;
3851 *pos++ = '\0';
3852
3853 if (os_strcmp(cmd, "bonjour") == 0)
3854 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
3855 if (os_strcmp(cmd, "upnp") == 0)
3856 return p2p_ctrl_service_del_upnp(wpa_s, pos);
3857 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3858 return -1;
3859}
3860
3861
3862static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
3863{
3864 u8 addr[ETH_ALEN];
3865
3866 /* <addr> */
3867
3868 if (hwaddr_aton(cmd, addr))
3869 return -1;
3870
3871 return wpas_p2p_reject(wpa_s, addr);
3872}
3873
3874
3875static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
3876{
3877 char *pos;
3878 int id;
3879 struct wpa_ssid *ssid;
Dmitry Shmidtaa532512012-09-24 10:35:31 -07003880 u8 *_peer = NULL, peer[ETH_ALEN];
Jouni Malinen31be0a42012-08-31 21:20:51 +03003881 int freq = 0;
3882 int ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003883
3884 id = atoi(cmd);
Dmitry Shmidtaa532512012-09-24 10:35:31 -07003885 pos = os_strstr(cmd, " peer=");
3886 if (pos) {
3887 pos += 6;
3888 if (hwaddr_aton(pos, peer))
3889 return -1;
3890 _peer = peer;
3891 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003892 ssid = wpa_config_get_network(wpa_s->conf, id);
3893 if (ssid == NULL || ssid->disabled != 2) {
3894 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3895 "for persistent P2P group",
3896 id);
3897 return -1;
3898 }
3899
Jouni Malinen31be0a42012-08-31 21:20:51 +03003900 pos = os_strstr(cmd, " freq=");
3901 if (pos) {
3902 pos += 6;
3903 freq = atoi(pos);
3904 if (freq <= 0)
3905 return -1;
3906 }
3907
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003908 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
Jouni Malinen31be0a42012-08-31 21:20:51 +03003909
Dmitry Shmidtaa532512012-09-24 10:35:31 -07003910 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003911}
3912
3913
3914static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
3915{
3916 char *pos;
3917 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
3918
3919 pos = os_strstr(cmd, " peer=");
3920 if (!pos)
3921 return -1;
3922
3923 *pos = '\0';
3924 pos += 6;
3925 if (hwaddr_aton(pos, peer)) {
3926 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
3927 return -1;
3928 }
3929
3930 pos = os_strstr(pos, " go_dev_addr=");
3931 if (pos) {
3932 pos += 13;
3933 if (hwaddr_aton(pos, go_dev_addr)) {
3934 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
3935 pos);
3936 return -1;
3937 }
3938 go_dev = go_dev_addr;
3939 }
3940
3941 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
3942}
3943
3944
3945static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
3946{
3947 if (os_strncmp(cmd, "persistent=", 11) == 0)
3948 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
3949 if (os_strncmp(cmd, "group=", 6) == 0)
3950 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
3951
3952 return -1;
3953}
3954
3955
3956static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003957 char *cmd, int freq, int ht40)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003958{
3959 int id;
3960 struct wpa_ssid *ssid;
3961
3962 id = atoi(cmd);
3963 ssid = wpa_config_get_network(wpa_s->conf, id);
3964 if (ssid == NULL || ssid->disabled != 2) {
3965 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3966 "for persistent P2P group",
3967 id);
3968 return -1;
3969 }
3970
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003971 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003972}
3973
3974
3975static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
3976{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003977 int freq = 0, ht40;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003978 char *pos;
3979
3980 pos = os_strstr(cmd, "freq=");
3981 if (pos)
3982 freq = atoi(pos + 5);
3983
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003984 ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003985
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003986 if (os_strncmp(cmd, "persistent=", 11) == 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003987 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
3988 ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003989 if (os_strcmp(cmd, "persistent") == 0 ||
3990 os_strncmp(cmd, "persistent ", 11) == 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003991 return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003992 if (os_strncmp(cmd, "freq=", 5) == 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003993 return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
3994 if (ht40)
3995 return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003996
3997 wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
3998 cmd);
3999 return -1;
4000}
4001
4002
4003static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
4004 char *buf, size_t buflen)
4005{
4006 u8 addr[ETH_ALEN], *addr_ptr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004007 int next, res;
4008 const struct p2p_peer_info *info;
4009 char *pos, *end;
4010 char devtype[WPS_DEV_TYPE_BUFSIZE];
4011 struct wpa_ssid *ssid;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004012 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004013
4014 if (!wpa_s->global->p2p)
4015 return -1;
4016
4017 if (os_strcmp(cmd, "FIRST") == 0) {
4018 addr_ptr = NULL;
4019 next = 0;
4020 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4021 if (hwaddr_aton(cmd + 5, addr) < 0)
4022 return -1;
4023 addr_ptr = addr;
4024 next = 1;
4025 } else {
4026 if (hwaddr_aton(cmd, addr) < 0)
4027 return -1;
4028 addr_ptr = addr;
4029 next = 0;
4030 }
4031
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004032 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
4033 if (info == NULL)
4034 return -1;
4035
4036 pos = buf;
4037 end = buf + buflen;
4038
4039 res = os_snprintf(pos, end - pos, MACSTR "\n"
4040 "pri_dev_type=%s\n"
4041 "device_name=%s\n"
4042 "manufacturer=%s\n"
4043 "model_name=%s\n"
4044 "model_number=%s\n"
4045 "serial_number=%s\n"
4046 "config_methods=0x%x\n"
4047 "dev_capab=0x%x\n"
4048 "group_capab=0x%x\n"
4049 "level=%d\n",
4050 MAC2STR(info->p2p_device_addr),
4051 wps_dev_type_bin2str(info->pri_dev_type,
4052 devtype, sizeof(devtype)),
4053 info->device_name,
4054 info->manufacturer,
4055 info->model_name,
4056 info->model_number,
4057 info->serial_number,
4058 info->config_methods,
4059 info->dev_capab,
4060 info->group_capab,
4061 info->level);
4062 if (res < 0 || res >= end - pos)
4063 return pos - buf;
4064 pos += res;
4065
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004066 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
4067 {
4068 const u8 *t;
4069 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
4070 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
4071 wps_dev_type_bin2str(t, devtype,
4072 sizeof(devtype)));
4073 if (res < 0 || res >= end - pos)
4074 return pos - buf;
4075 pos += res;
4076 }
4077
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004078 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004079 if (ssid) {
4080 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
4081 if (res < 0 || res >= end - pos)
4082 return pos - buf;
4083 pos += res;
4084 }
4085
4086 res = p2p_get_peer_info_txt(info, pos, end - pos);
4087 if (res < 0)
4088 return pos - buf;
4089 pos += res;
4090
4091 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004092}
4093
4094
Dmitry Shmidt04949592012-07-19 12:16:46 -07004095static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
4096 const char *param)
4097{
4098 struct wpa_freq_range *freq = NULL, *n;
4099 unsigned int count = 0, i;
4100 const char *pos, *pos2, *pos3;
4101
4102 if (wpa_s->global->p2p == NULL)
4103 return -1;
4104
4105 /*
4106 * param includes comma separated frequency range.
4107 * For example: 2412-2432,2462,5000-6000
4108 */
4109 pos = param;
4110 while (pos && pos[0]) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004111 n = os_realloc_array(freq, count + 1,
4112 sizeof(struct wpa_freq_range));
Dmitry Shmidt04949592012-07-19 12:16:46 -07004113 if (n == NULL) {
4114 os_free(freq);
4115 return -1;
4116 }
4117 freq = n;
4118 freq[count].min = atoi(pos);
4119 pos2 = os_strchr(pos, '-');
4120 pos3 = os_strchr(pos, ',');
4121 if (pos2 && (!pos3 || pos2 < pos3)) {
4122 pos2++;
4123 freq[count].max = atoi(pos2);
4124 } else
4125 freq[count].max = freq[count].min;
4126 pos = pos3;
4127 if (pos)
4128 pos++;
4129 count++;
4130 }
4131
4132 for (i = 0; i < count; i++) {
4133 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
4134 freq[i].min, freq[i].max);
4135 }
4136
4137 os_free(wpa_s->global->p2p_disallow_freq);
4138 wpa_s->global->p2p_disallow_freq = freq;
4139 wpa_s->global->num_p2p_disallow_freq = count;
4140 wpas_p2p_update_channel_list(wpa_s);
4141 return 0;
4142}
4143
4144
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004145static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
4146{
4147 char *param;
4148
4149 if (wpa_s->global->p2p == NULL)
4150 return -1;
4151
4152 param = os_strchr(cmd, ' ');
4153 if (param == NULL)
4154 return -1;
4155 *param++ = '\0';
4156
4157 if (os_strcmp(cmd, "discoverability") == 0) {
4158 p2p_set_client_discoverability(wpa_s->global->p2p,
4159 atoi(param));
4160 return 0;
4161 }
4162
4163 if (os_strcmp(cmd, "managed") == 0) {
4164 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
4165 return 0;
4166 }
4167
4168 if (os_strcmp(cmd, "listen_channel") == 0) {
4169 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
4170 atoi(param));
4171 }
4172
4173 if (os_strcmp(cmd, "ssid_postfix") == 0) {
4174 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
4175 os_strlen(param));
4176 }
4177
4178 if (os_strcmp(cmd, "noa") == 0) {
4179 char *pos;
4180 int count, start, duration;
4181 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
4182 count = atoi(param);
4183 pos = os_strchr(param, ',');
4184 if (pos == NULL)
4185 return -1;
4186 pos++;
4187 start = atoi(pos);
4188 pos = os_strchr(pos, ',');
4189 if (pos == NULL)
4190 return -1;
4191 pos++;
4192 duration = atoi(pos);
4193 if (count < 0 || count > 255 || start < 0 || duration < 0)
4194 return -1;
4195 if (count == 0 && duration > 0)
4196 return -1;
4197 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
4198 "start=%d duration=%d", count, start, duration);
4199 return wpas_p2p_set_noa(wpa_s, count, start, duration);
4200 }
4201
4202 if (os_strcmp(cmd, "ps") == 0)
4203 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
4204
4205 if (os_strcmp(cmd, "oppps") == 0)
4206 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
4207
4208 if (os_strcmp(cmd, "ctwindow") == 0)
4209 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
4210
4211 if (os_strcmp(cmd, "disabled") == 0) {
4212 wpa_s->global->p2p_disabled = atoi(param);
4213 wpa_printf(MSG_DEBUG, "P2P functionality %s",
4214 wpa_s->global->p2p_disabled ?
4215 "disabled" : "enabled");
4216 if (wpa_s->global->p2p_disabled) {
4217 wpas_p2p_stop_find(wpa_s);
4218 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
4219 p2p_flush(wpa_s->global->p2p);
4220 }
4221 return 0;
4222 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004223
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07004224 if (os_strcmp(cmd, "conc_pref") == 0) {
4225 if (os_strcmp(param, "sta") == 0)
4226 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
4227 else if (os_strcmp(param, "p2p") == 0)
4228 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07004229 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07004230 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07004231 return -1;
4232 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07004233 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07004234 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07004235 return 0;
4236 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07004237
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004238 if (os_strcmp(cmd, "force_long_sd") == 0) {
4239 wpa_s->force_long_sd = atoi(param);
4240 return 0;
4241 }
4242
4243 if (os_strcmp(cmd, "peer_filter") == 0) {
4244 u8 addr[ETH_ALEN];
4245 if (hwaddr_aton(param, addr))
4246 return -1;
4247 p2p_set_peer_filter(wpa_s->global->p2p, addr);
4248 return 0;
4249 }
4250
4251 if (os_strcmp(cmd, "cross_connect") == 0)
4252 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
4253
4254 if (os_strcmp(cmd, "go_apsd") == 0) {
4255 if (os_strcmp(param, "disable") == 0)
4256 wpa_s->set_ap_uapsd = 0;
4257 else {
4258 wpa_s->set_ap_uapsd = 1;
4259 wpa_s->ap_uapsd = atoi(param);
4260 }
4261 return 0;
4262 }
4263
4264 if (os_strcmp(cmd, "client_apsd") == 0) {
4265 if (os_strcmp(param, "disable") == 0)
4266 wpa_s->set_sta_uapsd = 0;
4267 else {
4268 int be, bk, vi, vo;
4269 char *pos;
4270 /* format: BE,BK,VI,VO;max SP Length */
4271 be = atoi(param);
4272 pos = os_strchr(param, ',');
4273 if (pos == NULL)
4274 return -1;
4275 pos++;
4276 bk = atoi(pos);
4277 pos = os_strchr(pos, ',');
4278 if (pos == NULL)
4279 return -1;
4280 pos++;
4281 vi = atoi(pos);
4282 pos = os_strchr(pos, ',');
4283 if (pos == NULL)
4284 return -1;
4285 pos++;
4286 vo = atoi(pos);
4287 /* ignore max SP Length for now */
4288
4289 wpa_s->set_sta_uapsd = 1;
4290 wpa_s->sta_uapsd = 0;
4291 if (be)
4292 wpa_s->sta_uapsd |= BIT(0);
4293 if (bk)
4294 wpa_s->sta_uapsd |= BIT(1);
4295 if (vi)
4296 wpa_s->sta_uapsd |= BIT(2);
4297 if (vo)
4298 wpa_s->sta_uapsd |= BIT(3);
4299 }
4300 return 0;
4301 }
4302
Dmitry Shmidt04949592012-07-19 12:16:46 -07004303 if (os_strcmp(cmd, "disallow_freq") == 0)
4304 return p2p_ctrl_disallow_freq(wpa_s, param);
4305
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004306 if (os_strcmp(cmd, "disc_int") == 0) {
4307 int min_disc_int, max_disc_int, max_disc_tu;
4308 char *pos;
4309
4310 pos = param;
4311
4312 min_disc_int = atoi(pos);
4313 pos = os_strchr(pos, ' ');
4314 if (pos == NULL)
4315 return -1;
4316 *pos++ = '\0';
4317
4318 max_disc_int = atoi(pos);
4319 pos = os_strchr(pos, ' ');
4320 if (pos == NULL)
4321 return -1;
4322 *pos++ = '\0';
4323
4324 max_disc_tu = atoi(pos);
4325
4326 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
4327 max_disc_int, max_disc_tu);
4328 }
4329
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004330 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
4331 cmd);
4332
4333 return -1;
4334}
4335
4336
4337static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
4338{
4339 char *pos, *pos2;
4340 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
4341
4342 if (cmd[0]) {
4343 pos = os_strchr(cmd, ' ');
4344 if (pos == NULL)
4345 return -1;
4346 *pos++ = '\0';
4347 dur1 = atoi(cmd);
4348
4349 pos2 = os_strchr(pos, ' ');
4350 if (pos2)
4351 *pos2++ = '\0';
4352 int1 = atoi(pos);
4353 } else
4354 pos2 = NULL;
4355
4356 if (pos2) {
4357 pos = os_strchr(pos2, ' ');
4358 if (pos == NULL)
4359 return -1;
4360 *pos++ = '\0';
4361 dur2 = atoi(pos2);
4362 int2 = atoi(pos);
4363 }
4364
4365 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
4366}
4367
4368
4369static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
4370{
4371 char *pos;
4372 unsigned int period = 0, interval = 0;
4373
4374 if (cmd[0]) {
4375 pos = os_strchr(cmd, ' ');
4376 if (pos == NULL)
4377 return -1;
4378 *pos++ = '\0';
4379 period = atoi(cmd);
4380 interval = atoi(pos);
4381 }
4382
4383 return wpas_p2p_ext_listen(wpa_s, period, interval);
4384}
4385
4386#endif /* CONFIG_P2P */
4387
4388
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004389#ifdef CONFIG_INTERWORKING
4390static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
4391{
4392 u8 bssid[ETH_ALEN];
4393 struct wpa_bss *bss;
4394
4395 if (hwaddr_aton(dst, bssid)) {
4396 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
4397 return -1;
4398 }
4399
4400 bss = wpa_bss_get_bssid(wpa_s, bssid);
4401 if (bss == NULL) {
4402 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
4403 MAC2STR(bssid));
4404 return -1;
4405 }
4406
4407 return interworking_connect(wpa_s, bss);
4408}
4409
4410
4411static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
4412{
4413 u8 dst_addr[ETH_ALEN];
4414 int used;
4415 char *pos;
4416#define MAX_ANQP_INFO_ID 100
4417 u16 id[MAX_ANQP_INFO_ID];
4418 size_t num_id = 0;
4419
4420 used = hwaddr_aton2(dst, dst_addr);
4421 if (used < 0)
4422 return -1;
4423 pos = dst + used;
4424 while (num_id < MAX_ANQP_INFO_ID) {
4425 id[num_id] = atoi(pos);
4426 if (id[num_id])
4427 num_id++;
4428 pos = os_strchr(pos + 1, ',');
4429 if (pos == NULL)
4430 break;
4431 pos++;
4432 }
4433
4434 if (num_id == 0)
4435 return -1;
4436
4437 return anqp_send_req(wpa_s, dst_addr, id, num_id);
4438}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004439
4440
4441static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
4442{
4443 u8 dst_addr[ETH_ALEN];
4444 struct wpabuf *advproto, *query = NULL;
4445 int used, ret = -1;
4446 char *pos, *end;
4447 size_t len;
4448
4449 used = hwaddr_aton2(cmd, dst_addr);
4450 if (used < 0)
4451 return -1;
4452
4453 pos = cmd + used;
4454 while (*pos == ' ')
4455 pos++;
4456
4457 /* Advertisement Protocol ID */
4458 end = os_strchr(pos, ' ');
4459 if (end)
4460 len = end - pos;
4461 else
4462 len = os_strlen(pos);
4463 if (len & 0x01)
4464 return -1;
4465 len /= 2;
4466 if (len == 0)
4467 return -1;
4468 advproto = wpabuf_alloc(len);
4469 if (advproto == NULL)
4470 return -1;
4471 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
4472 goto fail;
4473
4474 if (end) {
4475 /* Optional Query Request */
4476 pos = end + 1;
4477 while (*pos == ' ')
4478 pos++;
4479
4480 len = os_strlen(pos);
4481 if (len) {
4482 if (len & 0x01)
4483 goto fail;
4484 len /= 2;
4485 if (len == 0)
4486 goto fail;
4487 query = wpabuf_alloc(len);
4488 if (query == NULL)
4489 goto fail;
4490 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
4491 goto fail;
4492 }
4493 }
4494
4495 ret = gas_send_request(wpa_s, dst_addr, advproto, query);
4496
4497fail:
4498 wpabuf_free(advproto);
4499 wpabuf_free(query);
4500
4501 return ret;
4502}
4503
4504
4505static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
4506 size_t buflen)
4507{
4508 u8 addr[ETH_ALEN];
4509 int dialog_token;
4510 int used;
4511 char *pos;
4512 size_t resp_len, start, requested_len;
4513
4514 if (!wpa_s->last_gas_resp)
4515 return -1;
4516
4517 used = hwaddr_aton2(cmd, addr);
4518 if (used < 0)
4519 return -1;
4520
4521 pos = cmd + used;
4522 while (*pos == ' ')
4523 pos++;
4524 dialog_token = atoi(pos);
4525
4526 if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
4527 dialog_token != wpa_s->last_gas_dialog_token)
4528 return -1;
4529
4530 resp_len = wpabuf_len(wpa_s->last_gas_resp);
4531 start = 0;
4532 requested_len = resp_len;
4533
4534 pos = os_strchr(pos, ' ');
4535 if (pos) {
4536 start = atoi(pos);
4537 if (start > resp_len)
4538 return os_snprintf(buf, buflen, "FAIL-Invalid range");
4539 pos = os_strchr(pos, ',');
4540 if (pos == NULL)
4541 return -1;
4542 pos++;
4543 requested_len = atoi(pos);
4544 if (start + requested_len > resp_len)
4545 return os_snprintf(buf, buflen, "FAIL-Invalid range");
4546 }
4547
4548 if (requested_len * 2 + 1 > buflen)
4549 return os_snprintf(buf, buflen, "FAIL-Too long response");
4550
4551 return wpa_snprintf_hex(buf, buflen,
4552 wpabuf_head_u8(wpa_s->last_gas_resp) + start,
4553 requested_len);
4554}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004555#endif /* CONFIG_INTERWORKING */
4556
4557
Dmitry Shmidt04949592012-07-19 12:16:46 -07004558#ifdef CONFIG_HS20
4559
4560static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
4561{
4562 u8 dst_addr[ETH_ALEN];
4563 int used;
4564 char *pos;
4565 u32 subtypes = 0;
4566
4567 used = hwaddr_aton2(dst, dst_addr);
4568 if (used < 0)
4569 return -1;
4570 pos = dst + used;
4571 for (;;) {
4572 int num = atoi(pos);
4573 if (num <= 0 || num > 31)
4574 return -1;
4575 subtypes |= BIT(num);
4576 pos = os_strchr(pos + 1, ',');
4577 if (pos == NULL)
4578 break;
4579 pos++;
4580 }
4581
4582 if (subtypes == 0)
4583 return -1;
4584
4585 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
4586}
4587
4588
4589static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4590 const u8 *addr, const char *realm)
4591{
4592 u8 *buf;
4593 size_t rlen, len;
4594 int ret;
4595
4596 rlen = os_strlen(realm);
4597 len = 3 + rlen;
4598 buf = os_malloc(len);
4599 if (buf == NULL)
4600 return -1;
4601 buf[0] = 1; /* NAI Home Realm Count */
4602 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
4603 buf[2] = rlen;
4604 os_memcpy(buf + 3, realm, rlen);
4605
4606 ret = hs20_anqp_send_req(wpa_s, addr,
4607 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4608 buf, len);
4609
4610 os_free(buf);
4611
4612 return ret;
4613}
4614
4615
4616static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4617 char *dst)
4618{
4619 struct wpa_cred *cred = wpa_s->conf->cred;
4620 u8 dst_addr[ETH_ALEN];
4621 int used;
4622 u8 *buf;
4623 size_t len;
4624 int ret;
4625
4626 used = hwaddr_aton2(dst, dst_addr);
4627 if (used < 0)
4628 return -1;
4629
4630 while (dst[used] == ' ')
4631 used++;
4632 if (os_strncmp(dst + used, "realm=", 6) == 0)
4633 return hs20_nai_home_realm_list(wpa_s, dst_addr,
4634 dst + used + 6);
4635
4636 len = os_strlen(dst + used);
4637
4638 if (len == 0 && cred && cred->realm)
4639 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
4640
4641 if (len % 1)
4642 return -1;
4643 len /= 2;
4644 buf = os_malloc(len);
4645 if (buf == NULL)
4646 return -1;
4647 if (hexstr2bin(dst + used, buf, len) < 0) {
4648 os_free(buf);
4649 return -1;
4650 }
4651
4652 ret = hs20_anqp_send_req(wpa_s, dst_addr,
4653 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4654 buf, len);
4655 os_free(buf);
4656
4657 return ret;
4658}
4659
4660#endif /* CONFIG_HS20 */
4661
4662
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004663static int wpa_supplicant_ctrl_iface_sta_autoconnect(
4664 struct wpa_supplicant *wpa_s, char *cmd)
4665{
4666 wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
4667 return 0;
4668}
4669
4670
Dmitry Shmidt04949592012-07-19 12:16:46 -07004671#ifdef CONFIG_AUTOSCAN
4672
4673static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
4674 char *cmd)
4675{
4676 enum wpa_states state = wpa_s->wpa_state;
4677 char *new_params = NULL;
4678
4679 if (os_strlen(cmd) > 0) {
4680 new_params = os_strdup(cmd);
4681 if (new_params == NULL)
4682 return -1;
4683 }
4684
4685 os_free(wpa_s->conf->autoscan);
4686 wpa_s->conf->autoscan = new_params;
4687
4688 if (wpa_s->conf->autoscan == NULL)
4689 autoscan_deinit(wpa_s);
4690 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
4691 autoscan_init(wpa_s, 1);
4692 else if (state == WPA_SCANNING)
4693 wpa_supplicant_reinit_autoscan(wpa_s);
4694
4695 return 0;
4696}
4697
4698#endif /* CONFIG_AUTOSCAN */
4699
4700
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004701static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
4702 size_t buflen)
4703{
4704 struct wpa_signal_info si;
4705 int ret;
4706
4707 ret = wpa_drv_signal_poll(wpa_s, &si);
4708 if (ret)
4709 return -1;
4710
4711 ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
4712 "NOISE=%d\nFREQUENCY=%u\n",
4713 si.current_signal, si.current_txrate / 1000,
4714 si.current_noise, si.frequency);
4715 if (ret < 0 || (unsigned int) ret > buflen)
4716 return -1;
4717 return ret;
4718}
4719
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03004720
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004721static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
4722 size_t buflen)
4723{
4724 struct hostap_sta_driver_data sta;
4725 int ret;
4726
4727 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
4728 if (ret)
4729 return -1;
4730
4731 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03004732 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
4733 if (ret < 0 || (size_t) ret > buflen)
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004734 return -1;
4735 return ret;
4736}
4737
4738
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004739#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004740static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
4741 char *buf, size_t buflen)
4742{
4743 int ret;
4744
4745 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
4746 if (ret == 0)
4747 ret = sprintf(buf, "%s\n", "OK");
4748 return ret;
4749}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004750#endif
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004751
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07004752
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004753char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
4754 char *buf, size_t *resp_len)
4755{
4756 char *reply;
4757 const int reply_size = 4096;
4758 int ctrl_rsp = 0;
4759 int reply_len;
4760
4761 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004762 os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
4763 os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
4764 os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004765 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
4766 (const u8 *) buf, os_strlen(buf));
4767 } else {
4768 int level = MSG_DEBUG;
4769 if (os_strcmp(buf, "PING") == 0)
4770 level = MSG_EXCESSIVE;
4771 wpa_hexdump_ascii(level, "RX ctrl_iface",
4772 (const u8 *) buf, os_strlen(buf));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07004773 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004774 }
4775
4776 reply = os_malloc(reply_size);
4777 if (reply == NULL) {
4778 *resp_len = 1;
4779 return NULL;
4780 }
4781
4782 os_memcpy(reply, "OK\n", 3);
4783 reply_len = 3;
4784
4785 if (os_strcmp(buf, "PING") == 0) {
4786 os_memcpy(reply, "PONG\n", 5);
4787 reply_len = 5;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004788 } else if (os_strcmp(buf, "IFNAME") == 0) {
4789 reply_len = os_strlen(wpa_s->ifname);
4790 os_memcpy(reply, wpa_s->ifname, reply_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004791 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
4792 if (wpa_debug_reopen_file() < 0)
4793 reply_len = -1;
4794 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
4795 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
4796 } else if (os_strcmp(buf, "MIB") == 0) {
4797 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
4798 if (reply_len >= 0) {
4799 int res;
4800 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
4801 reply_size - reply_len);
4802 if (res < 0)
4803 reply_len = -1;
4804 else
4805 reply_len += res;
4806 }
4807 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
4808 reply_len = wpa_supplicant_ctrl_iface_status(
4809 wpa_s, buf + 6, reply, reply_size);
4810 } else if (os_strcmp(buf, "PMKSA") == 0) {
4811 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
4812 reply_size);
4813 } else if (os_strncmp(buf, "SET ", 4) == 0) {
4814 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
4815 reply_len = -1;
4816 } else if (os_strncmp(buf, "GET ", 4) == 0) {
4817 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
4818 reply, reply_size);
4819 } else if (os_strcmp(buf, "LOGON") == 0) {
4820 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
4821 } else if (os_strcmp(buf, "LOGOFF") == 0) {
4822 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
4823 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
4824 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4825 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004826 else
4827 wpas_request_connection(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004828 } else if (os_strcmp(buf, "RECONNECT") == 0) {
4829 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4830 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004831 else if (wpa_s->disconnected)
4832 wpas_request_connection(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004833#ifdef IEEE8021X_EAPOL
4834 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
4835 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
4836 reply_len = -1;
4837#endif /* IEEE8021X_EAPOL */
4838#ifdef CONFIG_PEERKEY
4839 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
4840 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
4841 reply_len = -1;
4842#endif /* CONFIG_PEERKEY */
4843#ifdef CONFIG_IEEE80211R
4844 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
4845 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
4846 reply_len = -1;
4847#endif /* CONFIG_IEEE80211R */
4848#ifdef CONFIG_WPS
4849 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
4850 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
4851 if (res == -2) {
4852 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4853 reply_len = 17;
4854 } else if (res)
4855 reply_len = -1;
4856 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
4857 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
4858 if (res == -2) {
4859 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4860 reply_len = 17;
4861 } else if (res)
4862 reply_len = -1;
4863 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
4864 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
4865 reply,
4866 reply_size);
4867 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4868 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
4869 wpa_s, buf + 14, reply, reply_size);
4870 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4871 if (wpas_wps_cancel(wpa_s))
4872 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004873#ifdef CONFIG_WPS_NFC
4874 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
4875 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
4876 reply_len = -1;
4877 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
4878 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
4879 reply_len = -1;
4880 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4881 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
4882 wpa_s, buf + 14, reply, reply_size);
4883 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4884 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
4885 buf + 17))
4886 reply_len = -1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004887 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
4888 reply_len = wpas_ctrl_nfc_get_handover_req(
4889 wpa_s, buf + 21, reply, reply_size);
4890 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
4891 reply_len = wpas_ctrl_nfc_get_handover_sel(
4892 wpa_s, buf + 21, reply, reply_size);
4893 } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
4894 reply_len = wpas_ctrl_nfc_rx_handover_req(
4895 wpa_s, buf + 20, reply, reply_size);
4896 } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
4897 if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
4898 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004899#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004900 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
4901 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
4902 reply_len = -1;
4903#ifdef CONFIG_AP
4904 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4905 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
4906 wpa_s, buf + 11, reply, reply_size);
4907#endif /* CONFIG_AP */
4908#ifdef CONFIG_WPS_ER
4909 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
4910 if (wpas_wps_er_start(wpa_s, NULL))
4911 reply_len = -1;
4912 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
4913 if (wpas_wps_er_start(wpa_s, buf + 13))
4914 reply_len = -1;
4915 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
4916 if (wpas_wps_er_stop(wpa_s))
4917 reply_len = -1;
4918 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
4919 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
4920 reply_len = -1;
4921 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
4922 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
4923 if (ret == -2) {
4924 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4925 reply_len = 17;
4926 } else if (ret == -3) {
4927 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
4928 reply_len = 18;
4929 } else if (ret == -4) {
4930 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
4931 reply_len = 20;
4932 } else if (ret)
4933 reply_len = -1;
4934 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
4935 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
4936 reply_len = -1;
4937 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
4938 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
4939 buf + 18))
4940 reply_len = -1;
4941 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
4942 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
4943 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004944#ifdef CONFIG_WPS_NFC
4945 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
4946 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
4947 wpa_s, buf + 24, reply, reply_size);
4948#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004949#endif /* CONFIG_WPS_ER */
4950#endif /* CONFIG_WPS */
4951#ifdef CONFIG_IBSS_RSN
4952 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
4953 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
4954 reply_len = -1;
4955#endif /* CONFIG_IBSS_RSN */
4956#ifdef CONFIG_P2P
4957 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
4958 if (p2p_ctrl_find(wpa_s, buf + 9))
4959 reply_len = -1;
4960 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
4961 if (p2p_ctrl_find(wpa_s, ""))
4962 reply_len = -1;
4963 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
4964 wpas_p2p_stop_find(wpa_s);
4965 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
4966 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
4967 reply_size);
4968 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
4969 if (p2p_ctrl_listen(wpa_s, buf + 11))
4970 reply_len = -1;
4971 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
4972 if (p2p_ctrl_listen(wpa_s, ""))
4973 reply_len = -1;
4974 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
4975 if (wpas_p2p_group_remove(wpa_s, buf + 17))
4976 reply_len = -1;
4977 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004978 if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004979 reply_len = -1;
4980 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
4981 if (p2p_ctrl_group_add(wpa_s, buf + 14))
4982 reply_len = -1;
4983 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
4984 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
4985 reply_len = -1;
4986 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
4987 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
4988 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
4989 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
4990 reply_size);
4991 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
4992 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
4993 reply_len = -1;
4994 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
4995 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
4996 reply_len = -1;
4997 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07004998#ifdef ANDROID_P2P
4999 wpas_p2p_sd_service_update(wpa_s, SRV_UPDATE);
5000#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005001 wpas_p2p_sd_service_update(wpa_s);
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07005002#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005003 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
5004 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
5005 reply_len = -1;
5006 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
5007 wpas_p2p_service_flush(wpa_s);
5008 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
5009 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
5010 reply_len = -1;
5011 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
5012 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
5013 reply_len = -1;
5014 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
5015 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
5016 reply_len = -1;
5017 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
5018 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
5019 reply_len = -1;
5020 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
5021 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
5022 reply_size);
5023 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
5024 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
5025 reply_len = -1;
5026 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
5027 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
5028 wpa_s->force_long_sd = 0;
5029 if (wpa_s->global->p2p)
5030 p2p_flush(wpa_s->global->p2p);
5031 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
5032 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
5033 reply_len = -1;
5034 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
5035 if (wpas_p2p_cancel(wpa_s))
5036 reply_len = -1;
5037 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
5038 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
5039 reply_len = -1;
5040 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
5041 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
5042 reply_len = -1;
5043 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
5044 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
5045 reply_len = -1;
5046 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
5047 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
5048 reply_len = -1;
5049#endif /* CONFIG_P2P */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005050#ifdef CONFIG_WIFI_DISPLAY
5051 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
5052 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
5053 reply_len = -1;
5054 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
5055 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
5056 reply, reply_size);
5057#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005058#ifdef CONFIG_INTERWORKING
5059 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
5060 if (interworking_fetch_anqp(wpa_s) < 0)
5061 reply_len = -1;
5062 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
5063 interworking_stop_fetch_anqp(wpa_s);
5064 } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
5065 if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
5066 NULL) < 0)
5067 reply_len = -1;
5068 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
5069 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
5070 reply_len = -1;
5071 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
5072 if (get_anqp(wpa_s, buf + 9) < 0)
5073 reply_len = -1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005074 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
5075 if (gas_request(wpa_s, buf + 12) < 0)
5076 reply_len = -1;
5077 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
5078 reply_len = gas_response_get(wpa_s, buf + 17, reply,
5079 reply_size);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005080#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07005081#ifdef CONFIG_HS20
5082 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
5083 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
5084 reply_len = -1;
5085 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
5086 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
5087 reply_len = -1;
5088#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005089 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
5090 {
5091 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
5092 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
5093 reply_len = -1;
5094 else
5095 ctrl_rsp = 1;
5096 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
5097 if (wpa_supplicant_reload_configuration(wpa_s))
5098 reply_len = -1;
5099 } else if (os_strcmp(buf, "TERMINATE") == 0) {
5100 wpa_supplicant_terminate_proc(wpa_s->global);
5101 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
5102 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
5103 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -07005104 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005105 reply_len = wpa_supplicant_ctrl_iface_blacklist(
5106 wpa_s, buf + 9, reply, reply_size);
5107 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
5108 reply_len = wpa_supplicant_ctrl_iface_log_level(
5109 wpa_s, buf + 9, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005110 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
5111 reply_len = wpa_supplicant_ctrl_iface_list_networks(
5112 wpa_s, reply, reply_size);
5113 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07005114#ifdef CONFIG_SME
5115 wpa_s->sme.prev_bssid_set = 0;
5116#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005117 wpa_s->reassociate = 0;
5118 wpa_s->disconnected = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005119 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005120 wpa_supplicant_cancel_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005121 wpa_supplicant_deauthenticate(wpa_s,
5122 WLAN_REASON_DEAUTH_LEAVING);
5123 } else if (os_strcmp(buf, "SCAN") == 0) {
5124 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
5125 reply_len = -1;
5126 else {
5127 if (!wpa_s->scanning &&
5128 ((wpa_s->wpa_state <= WPA_SCANNING) ||
5129 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07005130 wpa_s->normal_scans = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005131 wpa_s->scan_req = MANUAL_SCAN_REQ;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005132 wpa_supplicant_req_scan(wpa_s, 0, 0);
5133 } else if (wpa_s->sched_scanning) {
5134 wpa_printf(MSG_DEBUG, "Stop ongoing "
5135 "sched_scan to allow requested "
5136 "full scan to proceed");
5137 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005138 wpa_s->scan_req = MANUAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005139 wpa_supplicant_req_scan(wpa_s, 0, 0);
5140 } else {
5141 wpa_printf(MSG_DEBUG, "Ongoing scan action - "
5142 "reject new request");
5143 reply_len = os_snprintf(reply, reply_size,
5144 "FAIL-BUSY\n");
5145 }
5146 }
5147 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
5148 reply_len = wpa_supplicant_ctrl_iface_scan_results(
5149 wpa_s, reply, reply_size);
5150 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
5151 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
5152 reply_len = -1;
5153 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
5154 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
5155 reply_len = -1;
5156 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
5157 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
5158 reply_len = -1;
5159 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
5160 reply_len = wpa_supplicant_ctrl_iface_add_network(
5161 wpa_s, reply, reply_size);
5162 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
5163 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
5164 reply_len = -1;
5165 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
5166 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
5167 reply_len = -1;
5168 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
5169 reply_len = wpa_supplicant_ctrl_iface_get_network(
5170 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005171 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
5172 reply_len = wpa_supplicant_ctrl_iface_list_creds(
5173 wpa_s, reply, reply_size);
5174 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
5175 reply_len = wpa_supplicant_ctrl_iface_add_cred(
5176 wpa_s, reply, reply_size);
5177 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
5178 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
5179 reply_len = -1;
5180 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
5181 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
5182 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005183#ifndef CONFIG_NO_CONFIG_WRITE
5184 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
5185 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
5186 reply_len = -1;
5187#endif /* CONFIG_NO_CONFIG_WRITE */
5188 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
5189 reply_len = wpa_supplicant_ctrl_iface_get_capability(
5190 wpa_s, buf + 15, reply, reply_size);
5191 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
5192 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
5193 reply_len = -1;
5194 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
5195 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
5196 reply_len = -1;
5197 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
5198 reply_len = wpa_supplicant_global_iface_list(
5199 wpa_s->global, reply, reply_size);
5200 } else if (os_strcmp(buf, "INTERFACES") == 0) {
5201 reply_len = wpa_supplicant_global_iface_interfaces(
5202 wpa_s->global, reply, reply_size);
5203 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
5204 reply_len = wpa_supplicant_ctrl_iface_bss(
5205 wpa_s, buf + 4, reply, reply_size);
5206#ifdef CONFIG_AP
5207 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
5208 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
5209 } else if (os_strncmp(buf, "STA ", 4) == 0) {
5210 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
5211 reply_size);
5212 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
5213 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
5214 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005215 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
5216 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
5217 reply_len = -1;
5218 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
5219 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
5220 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005221#endif /* CONFIG_AP */
5222 } else if (os_strcmp(buf, "SUSPEND") == 0) {
5223 wpas_notify_suspend(wpa_s->global);
5224 } else if (os_strcmp(buf, "RESUME") == 0) {
5225 wpas_notify_resume(wpa_s->global);
5226 } else if (os_strcmp(buf, "DROP_SA") == 0) {
5227 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
5228 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
5229 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
5230 reply_len = -1;
5231 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
5232 if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
5233 reply_len = -1;
5234 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
5235 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
5236 reply_len = -1;
5237 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
5238 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
5239 buf + 17))
5240 reply_len = -1;
Dmitry Shmidtf48e4f92012-08-24 11:14:44 -07005241 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
5242 if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
5243 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005244#ifdef CONFIG_TDLS
5245 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
5246 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
5247 reply_len = -1;
5248 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
5249 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
5250 reply_len = -1;
5251 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
5252 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
5253 reply_len = -1;
5254#endif /* CONFIG_TDLS */
5255 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
5256 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
5257 reply_size);
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07005258 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
5259 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
5260 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07005261#ifdef CONFIG_AUTOSCAN
5262 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
5263 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
5264 reply_len = -1;
5265#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005266#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07005267 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
5268 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
5269 reply_size);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005270#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005271 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005272 pmksa_cache_clear_current(wpa_s->wpa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005273 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005274 } else {
5275 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
5276 reply_len = 16;
5277 }
5278
5279 if (reply_len < 0) {
5280 os_memcpy(reply, "FAIL\n", 5);
5281 reply_len = 5;
5282 }
5283
5284 if (ctrl_rsp)
5285 eapol_sm_notify_ctrl_response(wpa_s->eapol);
5286
5287 *resp_len = reply_len;
5288 return reply;
5289}
5290
5291
5292static int wpa_supplicant_global_iface_add(struct wpa_global *global,
5293 char *cmd)
5294{
5295 struct wpa_interface iface;
5296 char *pos;
5297
5298 /*
5299 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
5300 * TAB<bridge_ifname>
5301 */
5302 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
5303
5304 os_memset(&iface, 0, sizeof(iface));
5305
5306 do {
5307 iface.ifname = pos = cmd;
5308 pos = os_strchr(pos, '\t');
5309 if (pos)
5310 *pos++ = '\0';
5311 if (iface.ifname[0] == '\0')
5312 return -1;
5313 if (pos == NULL)
5314 break;
5315
5316 iface.confname = pos;
5317 pos = os_strchr(pos, '\t');
5318 if (pos)
5319 *pos++ = '\0';
5320 if (iface.confname[0] == '\0')
5321 iface.confname = NULL;
5322 if (pos == NULL)
5323 break;
5324
5325 iface.driver = pos;
5326 pos = os_strchr(pos, '\t');
5327 if (pos)
5328 *pos++ = '\0';
5329 if (iface.driver[0] == '\0')
5330 iface.driver = NULL;
5331 if (pos == NULL)
5332 break;
5333
5334 iface.ctrl_interface = pos;
5335 pos = os_strchr(pos, '\t');
5336 if (pos)
5337 *pos++ = '\0';
5338 if (iface.ctrl_interface[0] == '\0')
5339 iface.ctrl_interface = NULL;
5340 if (pos == NULL)
5341 break;
5342
5343 iface.driver_param = pos;
5344 pos = os_strchr(pos, '\t');
5345 if (pos)
5346 *pos++ = '\0';
5347 if (iface.driver_param[0] == '\0')
5348 iface.driver_param = NULL;
5349 if (pos == NULL)
5350 break;
5351
5352 iface.bridge_ifname = pos;
5353 pos = os_strchr(pos, '\t');
5354 if (pos)
5355 *pos++ = '\0';
5356 if (iface.bridge_ifname[0] == '\0')
5357 iface.bridge_ifname = NULL;
5358 if (pos == NULL)
5359 break;
5360 } while (0);
5361
5362 if (wpa_supplicant_get_iface(global, iface.ifname))
5363 return -1;
5364
5365 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
5366}
5367
5368
5369static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
5370 char *cmd)
5371{
5372 struct wpa_supplicant *wpa_s;
5373
5374 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
5375
5376 wpa_s = wpa_supplicant_get_iface(global, cmd);
5377 if (wpa_s == NULL)
5378 return -1;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07005379 return wpa_supplicant_remove_iface(global, wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005380}
5381
5382
5383static void wpa_free_iface_info(struct wpa_interface_info *iface)
5384{
5385 struct wpa_interface_info *prev;
5386
5387 while (iface) {
5388 prev = iface;
5389 iface = iface->next;
5390
5391 os_free(prev->ifname);
5392 os_free(prev->desc);
5393 os_free(prev);
5394 }
5395}
5396
5397
5398static int wpa_supplicant_global_iface_list(struct wpa_global *global,
5399 char *buf, int len)
5400{
5401 int i, res;
5402 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
5403 char *pos, *end;
5404
5405 for (i = 0; wpa_drivers[i]; i++) {
5406 struct wpa_driver_ops *drv = wpa_drivers[i];
5407 if (drv->get_interfaces == NULL)
5408 continue;
5409 tmp = drv->get_interfaces(global->drv_priv[i]);
5410 if (tmp == NULL)
5411 continue;
5412
5413 if (last == NULL)
5414 iface = last = tmp;
5415 else
5416 last->next = tmp;
5417 while (last->next)
5418 last = last->next;
5419 }
5420
5421 pos = buf;
5422 end = buf + len;
5423 for (tmp = iface; tmp; tmp = tmp->next) {
5424 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
5425 tmp->drv_name, tmp->ifname,
5426 tmp->desc ? tmp->desc : "");
5427 if (res < 0 || res >= end - pos) {
5428 *pos = '\0';
5429 break;
5430 }
5431 pos += res;
5432 }
5433
5434 wpa_free_iface_info(iface);
5435
5436 return pos - buf;
5437}
5438
5439
5440static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
5441 char *buf, int len)
5442{
5443 int res;
5444 char *pos, *end;
5445 struct wpa_supplicant *wpa_s;
5446
5447 wpa_s = global->ifaces;
5448 pos = buf;
5449 end = buf + len;
5450
5451 while (wpa_s) {
5452 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
5453 if (res < 0 || res >= end - pos) {
5454 *pos = '\0';
5455 break;
5456 }
5457 pos += res;
5458 wpa_s = wpa_s->next;
5459 }
5460 return pos - buf;
5461}
5462
5463
5464char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
5465 char *buf, size_t *resp_len)
5466{
5467 char *reply;
5468 const int reply_size = 2048;
5469 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005470 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005471
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005472 if (os_strcmp(buf, "PING") == 0)
5473 level = MSG_EXCESSIVE;
5474 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005475 (const u8 *) buf, os_strlen(buf));
5476
5477 reply = os_malloc(reply_size);
5478 if (reply == NULL) {
5479 *resp_len = 1;
5480 return NULL;
5481 }
5482
5483 os_memcpy(reply, "OK\n", 3);
5484 reply_len = 3;
5485
5486 if (os_strcmp(buf, "PING") == 0) {
5487 os_memcpy(reply, "PONG\n", 5);
5488 reply_len = 5;
5489 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
5490 if (wpa_supplicant_global_iface_add(global, buf + 14))
5491 reply_len = -1;
5492 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
5493 if (wpa_supplicant_global_iface_remove(global, buf + 17))
5494 reply_len = -1;
5495 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
5496 reply_len = wpa_supplicant_global_iface_list(
5497 global, reply, reply_size);
5498 } else if (os_strcmp(buf, "INTERFACES") == 0) {
5499 reply_len = wpa_supplicant_global_iface_interfaces(
5500 global, reply, reply_size);
5501 } else if (os_strcmp(buf, "TERMINATE") == 0) {
5502 wpa_supplicant_terminate_proc(global);
5503 } else if (os_strcmp(buf, "SUSPEND") == 0) {
5504 wpas_notify_suspend(global);
5505 } else if (os_strcmp(buf, "RESUME") == 0) {
5506 wpas_notify_resume(global);
5507 } else {
5508 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
5509 reply_len = 16;
5510 }
5511
5512 if (reply_len < 0) {
5513 os_memcpy(reply, "FAIL\n", 5);
5514 reply_len = 5;
5515 }
5516
5517 *resp_len = reply_len;
5518 return reply;
5519}