blob: c7030020d083dbb5a2cd45f56b9f682a0daf9f20 [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"
15#include "common/wpa_ctrl.h"
16#include "eap_peer/eap.h"
17#include "eapol_supp/eapol_supp_sm.h"
18#include "rsn_supp/wpa.h"
19#include "rsn_supp/preauth.h"
20#include "rsn_supp/pmksa_cache.h"
21#include "l2_packet/l2_packet.h"
22#include "wps/wps.h"
23#include "config.h"
24#include "wpa_supplicant_i.h"
25#include "driver_i.h"
26#include "wps_supplicant.h"
27#include "ibss_rsn.h"
28#include "ap.h"
29#include "p2p_supplicant.h"
30#include "p2p/p2p.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070031#include "hs20_supplicant.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070032#include "notify.h"
33#include "bss.h"
34#include "scan.h"
35#include "ctrl_iface.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080036#include "interworking.h"
Dmitry Shmidte19501d2011-03-16 14:32:18 -070037#include "blacklist.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080038#include "wpas_glue.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070039#include "autoscan.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070040
41extern struct wpa_driver_ops *wpa_drivers[];
42
43static int wpa_supplicant_global_iface_list(struct wpa_global *global,
44 char *buf, int len);
45static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
46 char *buf, int len);
47
48
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080049static int pno_start(struct wpa_supplicant *wpa_s)
50{
51 int ret;
52 size_t i, num_ssid;
53 struct wpa_ssid *ssid;
54 struct wpa_driver_scan_params params;
55
56 if (wpa_s->pno)
57 return 0;
58
59 os_memset(&params, 0, sizeof(params));
60
61 num_ssid = 0;
62 ssid = wpa_s->conf->ssid;
63 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -070064 if (!wpas_network_disabled(wpa_s, ssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080065 num_ssid++;
66 ssid = ssid->next;
67 }
68 if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
69 wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
70 "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
71 num_ssid = WPAS_MAX_SCAN_SSIDS;
72 }
73
74 if (num_ssid == 0) {
75 wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
76 return -1;
77 }
78
79 params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
80 num_ssid);
81 if (params.filter_ssids == NULL)
82 return -1;
83 i = 0;
84 ssid = wpa_s->conf->ssid;
85 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -070086 if (!wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080087 params.ssids[i].ssid = ssid->ssid;
88 params.ssids[i].ssid_len = ssid->ssid_len;
89 params.num_ssids++;
90 os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
91 ssid->ssid_len);
92 params.filter_ssids[i].ssid_len = ssid->ssid_len;
93 params.num_filter_ssids++;
94 i++;
95 if (i == num_ssid)
96 break;
97 }
98 ssid = ssid->next;
99 }
100
101 ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
102 os_free(params.filter_ssids);
103 if (ret == 0)
104 wpa_s->pno = 1;
105 return ret;
106}
107
108
109static int pno_stop(struct wpa_supplicant *wpa_s)
110{
111 if (wpa_s->pno) {
112 wpa_s->pno = 0;
113 return wpa_drv_stop_sched_scan(wpa_s);
114 }
115 return 0;
116}
117
118
Dmitry Shmidt04949592012-07-19 12:16:46 -0700119static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
120{
121 char *pos;
122 u8 addr[ETH_ALEN], *filter = NULL, *n;
123 size_t count = 0;
124
125 pos = val;
126 while (pos) {
127 if (*pos == '\0')
128 break;
129 if (hwaddr_aton(pos, addr)) {
130 os_free(filter);
131 return -1;
132 }
133 n = os_realloc(filter, (count + 1) * ETH_ALEN);
134 if (n == NULL) {
135 os_free(filter);
136 return -1;
137 }
138 filter = n;
139 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
140 count++;
141
142 pos = os_strchr(pos, ' ');
143 if (pos)
144 pos++;
145 }
146
147 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
148 os_free(wpa_s->bssid_filter);
149 wpa_s->bssid_filter = filter;
150 wpa_s->bssid_filter_count = count;
151
152 return 0;
153}
154
155
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700156static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
157 char *cmd)
158{
159 char *value;
160 int ret = 0;
161
162 value = os_strchr(cmd, ' ');
163 if (value == NULL)
164 return -1;
165 *value++ = '\0';
166
167 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
168 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
169 eapol_sm_configure(wpa_s->eapol,
170 atoi(value), -1, -1, -1);
171 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
172 eapol_sm_configure(wpa_s->eapol,
173 -1, atoi(value), -1, -1);
174 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
175 eapol_sm_configure(wpa_s->eapol,
176 -1, -1, atoi(value), -1);
177 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
178 eapol_sm_configure(wpa_s->eapol,
179 -1, -1, -1, atoi(value));
180 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
181 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
182 atoi(value)))
183 ret = -1;
184 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
185 0) {
186 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
187 atoi(value)))
188 ret = -1;
189 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
190 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
191 ret = -1;
192 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
193 wpa_s->wps_fragment_size = atoi(value);
194#ifdef CONFIG_WPS_TESTING
195 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
196 long int val;
197 val = strtol(value, NULL, 0);
198 if (val < 0 || val > 0xff) {
199 ret = -1;
200 wpa_printf(MSG_DEBUG, "WPS: Invalid "
201 "wps_version_number %ld", val);
202 } else {
203 wps_version_number = val;
204 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
205 "version %u.%u",
206 (wps_version_number & 0xf0) >> 4,
207 wps_version_number & 0x0f);
208 }
209 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
210 wps_testing_dummy_cred = atoi(value);
211 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
212 wps_testing_dummy_cred);
213#endif /* CONFIG_WPS_TESTING */
214 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
215 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
216 ret = -1;
217#ifdef CONFIG_TDLS_TESTING
218 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
219 extern unsigned int tdls_testing;
220 tdls_testing = strtol(value, NULL, 0);
221 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
222#endif /* CONFIG_TDLS_TESTING */
223#ifdef CONFIG_TDLS
224 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
225 int disabled = atoi(value);
226 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
227 if (disabled) {
228 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
229 ret = -1;
230 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
231 ret = -1;
232 wpa_tdls_enable(wpa_s->wpa, !disabled);
233#endif /* CONFIG_TDLS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800234 } else if (os_strcasecmp(cmd, "pno") == 0) {
235 if (atoi(value))
236 ret = pno_start(wpa_s);
237 else
238 ret = pno_stop(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700239 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
240 int disabled = atoi(value);
241 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
242 ret = -1;
243 else if (disabled)
244 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
245 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
246 if (os_strcmp(value, "disable") == 0)
247 wpa_s->set_sta_uapsd = 0;
248 else {
249 int be, bk, vi, vo;
250 char *pos;
251 /* format: BE,BK,VI,VO;max SP Length */
252 be = atoi(value);
253 pos = os_strchr(value, ',');
254 if (pos == NULL)
255 return -1;
256 pos++;
257 bk = atoi(pos);
258 pos = os_strchr(pos, ',');
259 if (pos == NULL)
260 return -1;
261 pos++;
262 vi = atoi(pos);
263 pos = os_strchr(pos, ',');
264 if (pos == NULL)
265 return -1;
266 pos++;
267 vo = atoi(pos);
268 /* ignore max SP Length for now */
269
270 wpa_s->set_sta_uapsd = 1;
271 wpa_s->sta_uapsd = 0;
272 if (be)
273 wpa_s->sta_uapsd |= BIT(0);
274 if (bk)
275 wpa_s->sta_uapsd |= BIT(1);
276 if (vi)
277 wpa_s->sta_uapsd |= BIT(2);
278 if (vo)
279 wpa_s->sta_uapsd |= BIT(3);
280 }
Jouni Malinen21d6bc82012-04-10 16:17:59 -0700281 } else if (os_strcasecmp(cmd, "ps") == 0) {
282 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700283 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
284 ret = set_bssid_filter(wpa_s, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285 } else {
286 value[-1] = '=';
287 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
288 if (ret == 0)
289 wpa_supplicant_update_config(wpa_s);
290 }
291
292 return ret;
293}
294
295
296static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
297 char *cmd, char *buf, size_t buflen)
298{
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700299 int res = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300
301 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
302
303 if (os_strcmp(cmd, "version") == 0) {
304 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700305 } else if (os_strcasecmp(cmd, "country") == 0) {
306 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
307 res = os_snprintf(buf, buflen, "%c%c",
308 wpa_s->conf->country[0],
309 wpa_s->conf->country[1]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310 }
311
Dmitry Shmidt6f3bdcf2011-04-19 16:42:47 -0700312 if (res < 0 || (unsigned int) res >= buflen)
313 return -1;
314 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700315}
316
317
318#ifdef IEEE8021X_EAPOL
319static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
320 char *addr)
321{
322 u8 bssid[ETH_ALEN];
323 struct wpa_ssid *ssid = wpa_s->current_ssid;
324
325 if (hwaddr_aton(addr, bssid)) {
326 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
327 "'%s'", addr);
328 return -1;
329 }
330
331 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
332 rsn_preauth_deinit(wpa_s->wpa);
333 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
334 return -1;
335
336 return 0;
337}
338#endif /* IEEE8021X_EAPOL */
339
340
341#ifdef CONFIG_PEERKEY
342/* MLME-STKSTART.request(peer) */
343static int wpa_supplicant_ctrl_iface_stkstart(
344 struct wpa_supplicant *wpa_s, char *addr)
345{
346 u8 peer[ETH_ALEN];
347
348 if (hwaddr_aton(addr, peer)) {
349 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
350 "address '%s'", addr);
351 return -1;
352 }
353
354 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
355 MAC2STR(peer));
356
357 return wpa_sm_stkstart(wpa_s->wpa, peer);
358}
359#endif /* CONFIG_PEERKEY */
360
361
362#ifdef CONFIG_TDLS
363
364static int wpa_supplicant_ctrl_iface_tdls_discover(
365 struct wpa_supplicant *wpa_s, char *addr)
366{
367 u8 peer[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800368 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700369
370 if (hwaddr_aton(addr, peer)) {
371 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
372 "address '%s'", addr);
373 return -1;
374 }
375
376 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
377 MAC2STR(peer));
378
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800379 if (wpa_tdls_is_external_setup(wpa_s->wpa))
380 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
381 else
382 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
383
384 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385}
386
387
388static int wpa_supplicant_ctrl_iface_tdls_setup(
389 struct wpa_supplicant *wpa_s, char *addr)
390{
391 u8 peer[ETH_ALEN];
392 int ret;
393
394 if (hwaddr_aton(addr, peer)) {
395 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
396 "address '%s'", addr);
397 return -1;
398 }
399
400 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
401 MAC2STR(peer));
402
403 ret = wpa_tdls_reneg(wpa_s->wpa, peer);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800404 if (ret) {
405 if (wpa_tdls_is_external_setup(wpa_s->wpa))
406 ret = wpa_tdls_start(wpa_s->wpa, peer);
407 else
408 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
409 }
410
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700411 return ret;
412}
413
414
415static int wpa_supplicant_ctrl_iface_tdls_teardown(
416 struct wpa_supplicant *wpa_s, char *addr)
417{
418 u8 peer[ETH_ALEN];
419
420 if (hwaddr_aton(addr, peer)) {
421 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
422 "address '%s'", addr);
423 return -1;
424 }
425
426 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
427 MAC2STR(peer));
428
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800429 return wpa_tdls_teardown_link(wpa_s->wpa, peer,
430 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700431}
432
433#endif /* CONFIG_TDLS */
434
435
436#ifdef CONFIG_IEEE80211R
437static int wpa_supplicant_ctrl_iface_ft_ds(
438 struct wpa_supplicant *wpa_s, char *addr)
439{
440 u8 target_ap[ETH_ALEN];
441 struct wpa_bss *bss;
442 const u8 *mdie;
443
444 if (hwaddr_aton(addr, target_ap)) {
445 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
446 "address '%s'", addr);
447 return -1;
448 }
449
450 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
451
452 bss = wpa_bss_get_bssid(wpa_s, target_ap);
453 if (bss)
454 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
455 else
456 mdie = NULL;
457
458 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
459}
460#endif /* CONFIG_IEEE80211R */
461
462
463#ifdef CONFIG_WPS
464static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
465 char *cmd)
466{
467 u8 bssid[ETH_ALEN], *_bssid = bssid;
Jouni Malinen75ecf522011-06-27 15:19:46 -0700468#ifdef CONFIG_P2P
469 u8 p2p_dev_addr[ETH_ALEN];
470#endif /* CONFIG_P2P */
471#ifdef CONFIG_AP
472 u8 *_p2p_dev_addr = NULL;
473#endif /* CONFIG_AP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800474
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700475 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
476 _bssid = NULL;
477#ifdef CONFIG_P2P
478 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
479 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
480 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
481 "P2P Device Address '%s'",
482 cmd + 13);
483 return -1;
484 }
485 _p2p_dev_addr = p2p_dev_addr;
486#endif /* CONFIG_P2P */
487 } else if (hwaddr_aton(cmd, bssid)) {
488 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
489 cmd);
490 return -1;
491 }
492
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800493#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700494 if (wpa_s->ap_iface)
495 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
496#endif /* CONFIG_AP */
497
498 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
499}
500
501
502static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
503 char *cmd, char *buf,
504 size_t buflen)
505{
506 u8 bssid[ETH_ALEN], *_bssid = bssid;
507 char *pin;
508 int ret;
509
510 pin = os_strchr(cmd, ' ');
511 if (pin)
512 *pin++ = '\0';
513
514 if (os_strcmp(cmd, "any") == 0)
515 _bssid = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800516 else if (os_strcmp(cmd, "get") == 0) {
517 ret = wps_generate_pin();
518 goto done;
519 } else if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700520 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
521 cmd);
522 return -1;
523 }
524
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800525#ifdef CONFIG_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700526 if (wpa_s->ap_iface)
527 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
528 buf, buflen);
529#endif /* CONFIG_AP */
530
531 if (pin) {
532 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
533 DEV_PW_DEFAULT);
534 if (ret < 0)
535 return -1;
536 ret = os_snprintf(buf, buflen, "%s", pin);
537 if (ret < 0 || (size_t) ret >= buflen)
538 return -1;
539 return ret;
540 }
541
542 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
543 if (ret < 0)
544 return -1;
545
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800546done:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700547 /* Return the generated PIN */
548 ret = os_snprintf(buf, buflen, "%08d", ret);
549 if (ret < 0 || (size_t) ret >= buflen)
550 return -1;
551 return ret;
552}
553
554
555static int wpa_supplicant_ctrl_iface_wps_check_pin(
556 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
557{
558 char pin[9];
559 size_t len;
560 char *pos;
561 int ret;
562
563 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
564 (u8 *) cmd, os_strlen(cmd));
565 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
566 if (*pos < '0' || *pos > '9')
567 continue;
568 pin[len++] = *pos;
569 if (len == 9) {
570 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
571 return -1;
572 }
573 }
574 if (len != 4 && len != 8) {
575 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
576 return -1;
577 }
578 pin[len] = '\0';
579
580 if (len == 8) {
581 unsigned int pin_val;
582 pin_val = atoi(pin);
583 if (!wps_pin_valid(pin_val)) {
584 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
585 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
586 if (ret < 0 || (size_t) ret >= buflen)
587 return -1;
588 return ret;
589 }
590 }
591
592 ret = os_snprintf(buf, buflen, "%s", pin);
593 if (ret < 0 || (size_t) ret >= buflen)
594 return -1;
595
596 return ret;
597}
598
599
600#ifdef CONFIG_WPS_OOB
601static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
602 char *cmd)
603{
604 char *path, *method, *name;
605
606 path = os_strchr(cmd, ' ');
607 if (path == NULL)
608 return -1;
609 *path++ = '\0';
610
611 method = os_strchr(path, ' ');
612 if (method == NULL)
613 return -1;
614 *method++ = '\0';
615
616 name = os_strchr(method, ' ');
617 if (name != NULL)
618 *name++ = '\0';
619
620 return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
621}
622#endif /* CONFIG_WPS_OOB */
623
624
Dmitry Shmidt04949592012-07-19 12:16:46 -0700625#ifdef CONFIG_WPS_NFC
626
627static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
628 char *cmd)
629{
630 u8 bssid[ETH_ALEN], *_bssid = bssid;
631
632 if (cmd == NULL || cmd[0] == '\0')
633 _bssid = NULL;
634 else if (hwaddr_aton(cmd, bssid))
635 return -1;
636
637 return wpas_wps_start_nfc(wpa_s, _bssid);
638}
639
640
641static int wpa_supplicant_ctrl_iface_wps_nfc_token(
642 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
643{
644 int ndef;
645 struct wpabuf *buf;
646 int res;
647
648 if (os_strcmp(cmd, "WPS") == 0)
649 ndef = 0;
650 else if (os_strcmp(cmd, "NDEF") == 0)
651 ndef = 1;
652 else
653 return -1;
654
655 buf = wpas_wps_nfc_token(wpa_s, ndef);
656 if (buf == NULL)
657 return -1;
658
659 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
660 wpabuf_len(buf));
661 reply[res++] = '\n';
662 reply[res] = '\0';
663
664 wpabuf_free(buf);
665
666 return res;
667}
668
669
670static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
671 struct wpa_supplicant *wpa_s, char *pos)
672{
673 size_t len;
674 struct wpabuf *buf;
675 int ret;
676
677 len = os_strlen(pos);
678 if (len & 0x01)
679 return -1;
680 len /= 2;
681
682 buf = wpabuf_alloc(len);
683 if (buf == NULL)
684 return -1;
685 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
686 wpabuf_free(buf);
687 return -1;
688 }
689
690 ret = wpas_wps_nfc_tag_read(wpa_s, buf);
691 wpabuf_free(buf);
692
693 return ret;
694}
695
696#endif /* CONFIG_WPS_NFC */
697
698
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700699static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
700 char *cmd)
701{
702 u8 bssid[ETH_ALEN];
703 char *pin;
704 char *new_ssid;
705 char *new_auth;
706 char *new_encr;
707 char *new_key;
708 struct wps_new_ap_settings ap;
709
710 pin = os_strchr(cmd, ' ');
711 if (pin == NULL)
712 return -1;
713 *pin++ = '\0';
714
715 if (hwaddr_aton(cmd, bssid)) {
716 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
717 cmd);
718 return -1;
719 }
720
721 new_ssid = os_strchr(pin, ' ');
722 if (new_ssid == NULL)
723 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
724 *new_ssid++ = '\0';
725
726 new_auth = os_strchr(new_ssid, ' ');
727 if (new_auth == NULL)
728 return -1;
729 *new_auth++ = '\0';
730
731 new_encr = os_strchr(new_auth, ' ');
732 if (new_encr == NULL)
733 return -1;
734 *new_encr++ = '\0';
735
736 new_key = os_strchr(new_encr, ' ');
737 if (new_key == NULL)
738 return -1;
739 *new_key++ = '\0';
740
741 os_memset(&ap, 0, sizeof(ap));
742 ap.ssid_hex = new_ssid;
743 ap.auth = new_auth;
744 ap.encr = new_encr;
745 ap.key_hex = new_key;
746 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
747}
748
749
750#ifdef CONFIG_AP
751static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
752 char *cmd, char *buf,
753 size_t buflen)
754{
755 int timeout = 300;
756 char *pos;
757 const char *pin_txt;
758
759 if (!wpa_s->ap_iface)
760 return -1;
761
762 pos = os_strchr(cmd, ' ');
763 if (pos)
764 *pos++ = '\0';
765
766 if (os_strcmp(cmd, "disable") == 0) {
767 wpas_wps_ap_pin_disable(wpa_s);
768 return os_snprintf(buf, buflen, "OK\n");
769 }
770
771 if (os_strcmp(cmd, "random") == 0) {
772 if (pos)
773 timeout = atoi(pos);
774 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
775 if (pin_txt == NULL)
776 return -1;
777 return os_snprintf(buf, buflen, "%s", pin_txt);
778 }
779
780 if (os_strcmp(cmd, "get") == 0) {
781 pin_txt = wpas_wps_ap_pin_get(wpa_s);
782 if (pin_txt == NULL)
783 return -1;
784 return os_snprintf(buf, buflen, "%s", pin_txt);
785 }
786
787 if (os_strcmp(cmd, "set") == 0) {
788 char *pin;
789 if (pos == NULL)
790 return -1;
791 pin = pos;
792 pos = os_strchr(pos, ' ');
793 if (pos) {
794 *pos++ = '\0';
795 timeout = atoi(pos);
796 }
797 if (os_strlen(pin) > buflen)
798 return -1;
799 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
800 return -1;
801 return os_snprintf(buf, buflen, "%s", pin);
802 }
803
804 return -1;
805}
806#endif /* CONFIG_AP */
807
808
809#ifdef CONFIG_WPS_ER
810static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
811 char *cmd)
812{
813 char *uuid = cmd, *pin, *pos;
814 u8 addr_buf[ETH_ALEN], *addr = NULL;
815 pin = os_strchr(uuid, ' ');
816 if (pin == NULL)
817 return -1;
818 *pin++ = '\0';
819 pos = os_strchr(pin, ' ');
820 if (pos) {
821 *pos++ = '\0';
822 if (hwaddr_aton(pos, addr_buf) == 0)
823 addr = addr_buf;
824 }
825 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
826}
827
828
829static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
830 char *cmd)
831{
832 char *uuid = cmd, *pin;
833 pin = os_strchr(uuid, ' ');
834 if (pin == NULL)
835 return -1;
836 *pin++ = '\0';
837 return wpas_wps_er_learn(wpa_s, uuid, pin);
838}
839
840
841static int wpa_supplicant_ctrl_iface_wps_er_set_config(
842 struct wpa_supplicant *wpa_s, char *cmd)
843{
844 char *uuid = cmd, *id;
845 id = os_strchr(uuid, ' ');
846 if (id == NULL)
847 return -1;
848 *id++ = '\0';
849 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
850}
851
852
853static int wpa_supplicant_ctrl_iface_wps_er_config(
854 struct wpa_supplicant *wpa_s, char *cmd)
855{
856 char *pin;
857 char *new_ssid;
858 char *new_auth;
859 char *new_encr;
860 char *new_key;
861 struct wps_new_ap_settings ap;
862
863 pin = os_strchr(cmd, ' ');
864 if (pin == NULL)
865 return -1;
866 *pin++ = '\0';
867
868 new_ssid = os_strchr(pin, ' ');
869 if (new_ssid == NULL)
870 return -1;
871 *new_ssid++ = '\0';
872
873 new_auth = os_strchr(new_ssid, ' ');
874 if (new_auth == NULL)
875 return -1;
876 *new_auth++ = '\0';
877
878 new_encr = os_strchr(new_auth, ' ');
879 if (new_encr == NULL)
880 return -1;
881 *new_encr++ = '\0';
882
883 new_key = os_strchr(new_encr, ' ');
884 if (new_key == NULL)
885 return -1;
886 *new_key++ = '\0';
887
888 os_memset(&ap, 0, sizeof(ap));
889 ap.ssid_hex = new_ssid;
890 ap.auth = new_auth;
891 ap.encr = new_encr;
892 ap.key_hex = new_key;
893 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
894}
Dmitry Shmidt04949592012-07-19 12:16:46 -0700895
896
897#ifdef CONFIG_WPS_NFC
898static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
899 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
900{
901 int ndef;
902 struct wpabuf *buf;
903 int res;
904 char *uuid;
905
906 uuid = os_strchr(cmd, ' ');
907 if (uuid == NULL)
908 return -1;
909 *uuid++ = '\0';
910
911 if (os_strcmp(cmd, "WPS") == 0)
912 ndef = 0;
913 else if (os_strcmp(cmd, "NDEF") == 0)
914 ndef = 1;
915 else
916 return -1;
917
918 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
919 if (buf == NULL)
920 return -1;
921
922 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
923 wpabuf_len(buf));
924 reply[res++] = '\n';
925 reply[res] = '\0';
926
927 wpabuf_free(buf);
928
929 return res;
930}
931#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700932#endif /* CONFIG_WPS_ER */
933
934#endif /* CONFIG_WPS */
935
936
937#ifdef CONFIG_IBSS_RSN
938static int wpa_supplicant_ctrl_iface_ibss_rsn(
939 struct wpa_supplicant *wpa_s, char *addr)
940{
941 u8 peer[ETH_ALEN];
942
943 if (hwaddr_aton(addr, peer)) {
944 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
945 "address '%s'", addr);
946 return -1;
947 }
948
949 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
950 MAC2STR(peer));
951
952 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
953}
954#endif /* CONFIG_IBSS_RSN */
955
956
957static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
958 char *rsp)
959{
960#ifdef IEEE8021X_EAPOL
961 char *pos, *id_pos;
962 int id;
963 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700964
965 pos = os_strchr(rsp, '-');
966 if (pos == NULL)
967 return -1;
968 *pos++ = '\0';
969 id_pos = pos;
970 pos = os_strchr(pos, ':');
971 if (pos == NULL)
972 return -1;
973 *pos++ = '\0';
974 id = atoi(id_pos);
975 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
976 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
977 (u8 *) pos, os_strlen(pos));
978
979 ssid = wpa_config_get_network(wpa_s->conf, id);
980 if (ssid == NULL) {
981 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
982 "to update", id);
983 return -1;
984 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800986 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
987 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700988#else /* IEEE8021X_EAPOL */
989 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
990 return -1;
991#endif /* IEEE8021X_EAPOL */
992}
993
994
995static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
996 const char *params,
997 char *buf, size_t buflen)
998{
999 char *pos, *end, tmp[30];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001000 int res, verbose, wps, ret;
Dmitry Shmidt44da0252011-08-23 12:30:30 -07001001
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001002 verbose = os_strcmp(params, "-VERBOSE") == 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001003 wps = os_strcmp(params, "-WPS") == 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001004 pos = buf;
1005 end = buf + buflen;
1006 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1007 struct wpa_ssid *ssid = wpa_s->current_ssid;
1008 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1009 MAC2STR(wpa_s->bssid));
1010 if (ret < 0 || ret >= end - pos)
1011 return pos - buf;
1012 pos += ret;
1013 if (ssid) {
1014 u8 *_ssid = ssid->ssid;
1015 size_t ssid_len = ssid->ssid_len;
1016 u8 ssid_buf[MAX_SSID_LEN];
1017 if (ssid_len == 0) {
1018 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1019 if (_res < 0)
1020 ssid_len = 0;
1021 else
1022 ssid_len = _res;
1023 _ssid = ssid_buf;
1024 }
1025 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1026 wpa_ssid_txt(_ssid, ssid_len),
1027 ssid->id);
1028 if (ret < 0 || ret >= end - pos)
1029 return pos - buf;
1030 pos += ret;
1031
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001032 if (wps && ssid->passphrase &&
1033 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1034 (ssid->mode == WPAS_MODE_AP ||
1035 ssid->mode == WPAS_MODE_P2P_GO)) {
1036 ret = os_snprintf(pos, end - pos,
1037 "passphrase=%s\n",
1038 ssid->passphrase);
1039 if (ret < 0 || ret >= end - pos)
1040 return pos - buf;
1041 pos += ret;
1042 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001043 if (ssid->id_str) {
1044 ret = os_snprintf(pos, end - pos,
1045 "id_str=%s\n",
1046 ssid->id_str);
1047 if (ret < 0 || ret >= end - pos)
1048 return pos - buf;
1049 pos += ret;
1050 }
1051
1052 switch (ssid->mode) {
1053 case WPAS_MODE_INFRA:
1054 ret = os_snprintf(pos, end - pos,
1055 "mode=station\n");
1056 break;
1057 case WPAS_MODE_IBSS:
1058 ret = os_snprintf(pos, end - pos,
1059 "mode=IBSS\n");
1060 break;
1061 case WPAS_MODE_AP:
1062 ret = os_snprintf(pos, end - pos,
1063 "mode=AP\n");
1064 break;
1065 case WPAS_MODE_P2P_GO:
1066 ret = os_snprintf(pos, end - pos,
1067 "mode=P2P GO\n");
1068 break;
1069 case WPAS_MODE_P2P_GROUP_FORMATION:
1070 ret = os_snprintf(pos, end - pos,
1071 "mode=P2P GO - group "
1072 "formation\n");
1073 break;
1074 default:
1075 ret = 0;
1076 break;
1077 }
1078 if (ret < 0 || ret >= end - pos)
1079 return pos - buf;
1080 pos += ret;
1081 }
1082
1083#ifdef CONFIG_AP
1084 if (wpa_s->ap_iface) {
1085 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1086 end - pos,
1087 verbose);
1088 } else
1089#endif /* CONFIG_AP */
1090 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1091 }
1092 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1093 wpa_supplicant_state_txt(wpa_s->wpa_state));
1094 if (ret < 0 || ret >= end - pos)
1095 return pos - buf;
1096 pos += ret;
1097
1098 if (wpa_s->l2 &&
1099 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1100 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
1101 if (ret < 0 || ret >= end - pos)
1102 return pos - buf;
1103 pos += ret;
1104 }
1105
1106#ifdef CONFIG_P2P
1107 if (wpa_s->global->p2p) {
1108 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1109 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
1110 if (ret < 0 || ret >= end - pos)
1111 return pos - buf;
1112 pos += ret;
1113 }
1114#endif /* CONFIG_P2P */
1115
1116 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1117 MAC2STR(wpa_s->own_addr));
1118 if (ret < 0 || ret >= end - pos)
1119 return pos - buf;
1120 pos += ret;
1121
Dmitry Shmidt04949592012-07-19 12:16:46 -07001122#ifdef CONFIG_HS20
1123 if (wpa_s->current_bss &&
1124 wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) {
1125 ret = os_snprintf(pos, end - pos, "hs20=1\n");
1126 if (ret < 0 || ret >= end - pos)
1127 return pos - buf;
1128 pos += ret;
1129 }
1130#endif /* CONFIG_HS20 */
1131
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001132 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
1133 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1134 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
1135 verbose);
1136 if (res >= 0)
1137 pos += res;
1138 }
1139
1140 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
1141 if (res >= 0)
1142 pos += res;
1143
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001144#ifdef ANDROID
1145 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
Irfan Sherifff20a4432012-04-16 16:48:34 -07001146 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001147 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
Irfan Sherifff20a4432012-04-16 16:48:34 -07001148 wpa_s->wpa_state,
Irfan Sheriffe78e7672012-08-01 11:10:15 -07001149 MAC2STR(wpa_s->bssid),
andy2_kuo5b5fb022012-05-22 11:53:07 -07001150 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
1151 wpa_ssid_txt(wpa_s->current_ssid->ssid,
Irfan Sheriff10294772012-05-11 11:23:35 -07001152 wpa_s->current_ssid->ssid_len) : "");
Irfan Sheriffbf5edf42012-01-11 16:54:57 -08001153 if (wpa_s->wpa_state == WPA_COMPLETED) {
1154 struct wpa_ssid *ssid = wpa_s->current_ssid;
1155 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to "
1156 MACSTR " completed %s [id=%d id_str=%s]",
1157 MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
1158 "(reauth)" : "(auth)",
1159 ssid ? ssid->id : -1,
1160 ssid && ssid->id_str ? ssid->id_str : "");
1161 }
Dmitry Shmidt2fd7fa62011-12-19 11:19:09 -08001162#endif /* ANDROID */
1163
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001164 return pos - buf;
1165}
1166
1167
1168static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
1169 char *cmd)
1170{
1171 char *pos;
1172 int id;
1173 struct wpa_ssid *ssid;
1174 u8 bssid[ETH_ALEN];
1175
1176 /* cmd: "<network id> <BSSID>" */
1177 pos = os_strchr(cmd, ' ');
1178 if (pos == NULL)
1179 return -1;
1180 *pos++ = '\0';
1181 id = atoi(cmd);
1182 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
1183 if (hwaddr_aton(pos, bssid)) {
1184 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
1185 return -1;
1186 }
1187
1188 ssid = wpa_config_get_network(wpa_s->conf, id);
1189 if (ssid == NULL) {
1190 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1191 "to update", id);
1192 return -1;
1193 }
1194
1195 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
1196 ssid->bssid_set = !is_zero_ether_addr(bssid);
1197
1198 return 0;
1199}
1200
1201
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001202static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001203 char *cmd, char *buf,
1204 size_t buflen)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001205{
1206 u8 bssid[ETH_ALEN];
1207 struct wpa_blacklist *e;
1208 char *pos, *end;
1209 int ret;
1210
1211 /* cmd: "BLACKLIST [<BSSID>]" */
1212 if (*cmd == '\0') {
1213 pos = buf;
1214 end = buf + buflen;
1215 e = wpa_s->blacklist;
1216 while (e) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001217 ret = os_snprintf(pos, end - pos, MACSTR "\n",
1218 MAC2STR(e->bssid));
1219 if (ret < 0 || ret >= end - pos)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001220 return pos - buf;
1221 pos += ret;
1222 e = e->next;
1223 }
1224 return pos - buf;
1225 }
1226
1227 cmd++;
1228 if (os_strncmp(cmd, "clear", 5) == 0) {
1229 wpa_blacklist_clear(wpa_s);
1230 os_memcpy(buf, "OK\n", 3);
1231 return 3;
1232 }
1233
1234 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
1235 if (hwaddr_aton(cmd, bssid)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001236 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001237 return -1;
1238 }
1239
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001240 /*
1241 * Add the BSSID twice, so its count will be 2, causing it to be
1242 * skipped when processing scan results.
1243 */
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001244 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001245 if (ret != 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001246 return -1;
1247 ret = wpa_blacklist_add(wpa_s, bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001248 if (ret != 0)
Dmitry Shmidte19501d2011-03-16 14:32:18 -07001249 return -1;
1250 os_memcpy(buf, "OK\n", 3);
1251 return 3;
1252}
1253
1254
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001255extern int wpa_debug_level;
1256extern int wpa_debug_timestamp;
1257
1258static const char * debug_level_str(int level)
1259{
1260 switch (level) {
1261 case MSG_EXCESSIVE:
1262 return "EXCESSIVE";
1263 case MSG_MSGDUMP:
1264 return "MSGDUMP";
1265 case MSG_DEBUG:
1266 return "DEBUG";
1267 case MSG_INFO:
1268 return "INFO";
1269 case MSG_WARNING:
1270 return "WARNING";
1271 case MSG_ERROR:
1272 return "ERROR";
1273 default:
1274 return "?";
1275 }
1276}
1277
1278
1279static int str_to_debug_level(const char *s)
1280{
1281 if (os_strcasecmp(s, "EXCESSIVE") == 0)
1282 return MSG_EXCESSIVE;
1283 if (os_strcasecmp(s, "MSGDUMP") == 0)
1284 return MSG_MSGDUMP;
1285 if (os_strcasecmp(s, "DEBUG") == 0)
1286 return MSG_DEBUG;
1287 if (os_strcasecmp(s, "INFO") == 0)
1288 return MSG_INFO;
1289 if (os_strcasecmp(s, "WARNING") == 0)
1290 return MSG_WARNING;
1291 if (os_strcasecmp(s, "ERROR") == 0)
1292 return MSG_ERROR;
1293 return -1;
1294}
1295
1296
1297static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
1298 char *cmd, char *buf,
1299 size_t buflen)
1300{
1301 char *pos, *end, *stamp;
1302 int ret;
1303
1304 if (cmd == NULL) {
1305 return -1;
1306 }
1307
1308 /* cmd: "LOG_LEVEL [<level>]" */
1309 if (*cmd == '\0') {
1310 pos = buf;
1311 end = buf + buflen;
1312 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1313 "Timestamp: %d\n",
1314 debug_level_str(wpa_debug_level),
1315 wpa_debug_timestamp);
1316 if (ret < 0 || ret >= end - pos)
1317 ret = 0;
1318
1319 return ret;
1320 }
1321
1322 while (*cmd == ' ')
1323 cmd++;
1324
1325 stamp = os_strchr(cmd, ' ');
1326 if (stamp) {
1327 *stamp++ = '\0';
1328 while (*stamp == ' ') {
1329 stamp++;
1330 }
1331 }
1332
1333 if (cmd && os_strlen(cmd)) {
1334 int level = str_to_debug_level(cmd);
1335 if (level < 0)
1336 return -1;
1337 wpa_debug_level = level;
1338 }
1339
1340 if (stamp && os_strlen(stamp))
1341 wpa_debug_timestamp = atoi(stamp);
1342
1343 os_memcpy(buf, "OK\n", 3);
1344 return 3;
1345}
1346
1347
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001348static int wpa_supplicant_ctrl_iface_list_networks(
1349 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1350{
1351 char *pos, *end;
1352 struct wpa_ssid *ssid;
1353 int ret;
1354
1355 pos = buf;
1356 end = buf + buflen;
1357 ret = os_snprintf(pos, end - pos,
1358 "network id / ssid / bssid / flags\n");
1359 if (ret < 0 || ret >= end - pos)
1360 return pos - buf;
1361 pos += ret;
1362
1363 ssid = wpa_s->conf->ssid;
1364 while (ssid) {
1365 ret = os_snprintf(pos, end - pos, "%d\t%s",
1366 ssid->id,
1367 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1368 if (ret < 0 || ret >= end - pos)
1369 return pos - buf;
1370 pos += ret;
1371 if (ssid->bssid_set) {
1372 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
1373 MAC2STR(ssid->bssid));
1374 } else {
1375 ret = os_snprintf(pos, end - pos, "\tany");
1376 }
1377 if (ret < 0 || ret >= end - pos)
1378 return pos - buf;
1379 pos += ret;
1380 ret = os_snprintf(pos, end - pos, "\t%s%s%s",
1381 ssid == wpa_s->current_ssid ?
1382 "[CURRENT]" : "",
1383 ssid->disabled ? "[DISABLED]" : "",
1384 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
1385 "");
1386 if (ret < 0 || ret >= end - pos)
1387 return pos - buf;
1388 pos += ret;
1389 ret = os_snprintf(pos, end - pos, "\n");
1390 if (ret < 0 || ret >= end - pos)
1391 return pos - buf;
1392 pos += ret;
1393
1394 ssid = ssid->next;
1395 }
1396
1397 return pos - buf;
1398}
1399
1400
1401static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
1402{
1403 int first = 1, ret;
1404 ret = os_snprintf(pos, end - pos, "-");
1405 if (ret < 0 || ret >= end - pos)
1406 return pos;
1407 pos += ret;
1408 if (cipher & WPA_CIPHER_NONE) {
1409 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
1410 if (ret < 0 || ret >= end - pos)
1411 return pos;
1412 pos += ret;
1413 first = 0;
1414 }
1415 if (cipher & WPA_CIPHER_WEP40) {
1416 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
1417 if (ret < 0 || ret >= end - pos)
1418 return pos;
1419 pos += ret;
1420 first = 0;
1421 }
1422 if (cipher & WPA_CIPHER_WEP104) {
1423 ret = os_snprintf(pos, end - pos, "%sWEP104",
1424 first ? "" : "+");
1425 if (ret < 0 || ret >= end - pos)
1426 return pos;
1427 pos += ret;
1428 first = 0;
1429 }
1430 if (cipher & WPA_CIPHER_TKIP) {
1431 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
1432 if (ret < 0 || ret >= end - pos)
1433 return pos;
1434 pos += ret;
1435 first = 0;
1436 }
1437 if (cipher & WPA_CIPHER_CCMP) {
1438 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
1439 if (ret < 0 || ret >= end - pos)
1440 return pos;
1441 pos += ret;
1442 first = 0;
1443 }
1444 return pos;
1445}
1446
1447
1448static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
1449 const u8 *ie, size_t ie_len)
1450{
1451 struct wpa_ie_data data;
1452 int first, ret;
1453
1454 ret = os_snprintf(pos, end - pos, "[%s-", proto);
1455 if (ret < 0 || ret >= end - pos)
1456 return pos;
1457 pos += ret;
1458
1459 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
1460 ret = os_snprintf(pos, end - pos, "?]");
1461 if (ret < 0 || ret >= end - pos)
1462 return pos;
1463 pos += ret;
1464 return pos;
1465 }
1466
1467 first = 1;
1468 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1469 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
1470 if (ret < 0 || ret >= end - pos)
1471 return pos;
1472 pos += ret;
1473 first = 0;
1474 }
1475 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
1476 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
1477 if (ret < 0 || ret >= end - pos)
1478 return pos;
1479 pos += ret;
1480 first = 0;
1481 }
1482 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
1483 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
1484 if (ret < 0 || ret >= end - pos)
1485 return pos;
1486 pos += ret;
1487 first = 0;
1488 }
1489#ifdef CONFIG_IEEE80211R
1490 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1491 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
1492 first ? "" : "+");
1493 if (ret < 0 || ret >= end - pos)
1494 return pos;
1495 pos += ret;
1496 first = 0;
1497 }
1498 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1499 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
1500 first ? "" : "+");
1501 if (ret < 0 || ret >= end - pos)
1502 return pos;
1503 pos += ret;
1504 first = 0;
1505 }
1506#endif /* CONFIG_IEEE80211R */
1507#ifdef CONFIG_IEEE80211W
1508 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1509 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
1510 first ? "" : "+");
1511 if (ret < 0 || ret >= end - pos)
1512 return pos;
1513 pos += ret;
1514 first = 0;
1515 }
1516 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1517 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
1518 first ? "" : "+");
1519 if (ret < 0 || ret >= end - pos)
1520 return pos;
1521 pos += ret;
1522 first = 0;
1523 }
1524#endif /* CONFIG_IEEE80211W */
1525
1526 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
1527
1528 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
1529 ret = os_snprintf(pos, end - pos, "-preauth");
1530 if (ret < 0 || ret >= end - pos)
1531 return pos;
1532 pos += ret;
1533 }
1534
1535 ret = os_snprintf(pos, end - pos, "]");
1536 if (ret < 0 || ret >= end - pos)
1537 return pos;
1538 pos += ret;
1539
1540 return pos;
1541}
1542
1543
1544#ifdef CONFIG_WPS
1545static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
1546 char *pos, char *end,
1547 struct wpabuf *wps_ie)
1548{
1549 int ret;
1550 const char *txt;
1551
1552 if (wps_ie == NULL)
1553 return pos;
1554 if (wps_is_selected_pbc_registrar(wps_ie))
1555 txt = "[WPS-PBC]";
1556#ifdef CONFIG_WPS2
1557 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
1558 txt = "[WPS-AUTH]";
1559#endif /* CONFIG_WPS2 */
1560 else if (wps_is_selected_pin_registrar(wps_ie))
1561 txt = "[WPS-PIN]";
1562 else
1563 txt = "[WPS]";
1564
1565 ret = os_snprintf(pos, end - pos, "%s", txt);
1566 if (ret >= 0 && ret < end - pos)
1567 pos += ret;
1568 wpabuf_free(wps_ie);
1569 return pos;
1570}
1571#endif /* CONFIG_WPS */
1572
1573
1574static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
1575 char *pos, char *end,
1576 const struct wpa_bss *bss)
1577{
1578#ifdef CONFIG_WPS
1579 struct wpabuf *wps_ie;
1580 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1581 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
1582#else /* CONFIG_WPS */
1583 return pos;
1584#endif /* CONFIG_WPS */
1585}
1586
1587
1588/* Format one result on one text line into a buffer. */
1589static int wpa_supplicant_ctrl_iface_scan_result(
1590 struct wpa_supplicant *wpa_s,
1591 const struct wpa_bss *bss, char *buf, size_t buflen)
1592{
1593 char *pos, *end;
1594 int ret;
1595 const u8 *ie, *ie2, *p2p;
1596
1597 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
1598 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
1599 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
1600 0)
1601 return 0; /* Do not show P2P listen discovery results here */
1602
1603 pos = buf;
1604 end = buf + buflen;
1605
1606 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
1607 MAC2STR(bss->bssid), bss->freq, bss->level);
1608 if (ret < 0 || ret >= end - pos)
1609 return -1;
1610 pos += ret;
1611 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1612 if (ie)
1613 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1614 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1615 if (ie2)
1616 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1617 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
1618 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1619 ret = os_snprintf(pos, end - pos, "[WEP]");
1620 if (ret < 0 || ret >= end - pos)
1621 return -1;
1622 pos += ret;
1623 }
1624 if (bss->caps & IEEE80211_CAP_IBSS) {
1625 ret = os_snprintf(pos, end - pos, "[IBSS]");
1626 if (ret < 0 || ret >= end - pos)
1627 return -1;
1628 pos += ret;
1629 }
1630 if (bss->caps & IEEE80211_CAP_ESS) {
1631 ret = os_snprintf(pos, end - pos, "[ESS]");
1632 if (ret < 0 || ret >= end - pos)
1633 return -1;
1634 pos += ret;
1635 }
1636 if (p2p) {
1637 ret = os_snprintf(pos, end - pos, "[P2P]");
1638 if (ret < 0 || ret >= end - pos)
1639 return -1;
1640 pos += ret;
1641 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001642#ifdef CONFIG_HS20
1643 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
1644 ret = os_snprintf(pos, end - pos, "[HS20]");
1645 if (ret < 0 || ret >= end - pos)
1646 return -1;
1647 pos += ret;
1648 }
1649#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001650
1651 ret = os_snprintf(pos, end - pos, "\t%s",
1652 wpa_ssid_txt(bss->ssid, bss->ssid_len));
1653 if (ret < 0 || ret >= end - pos)
1654 return -1;
1655 pos += ret;
1656
1657 ret = os_snprintf(pos, end - pos, "\n");
1658 if (ret < 0 || ret >= end - pos)
1659 return -1;
1660 pos += ret;
1661
1662 return pos - buf;
1663}
1664
1665
1666static int wpa_supplicant_ctrl_iface_scan_results(
1667 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1668{
1669 char *pos, *end;
1670 struct wpa_bss *bss;
1671 int ret;
1672
1673 pos = buf;
1674 end = buf + buflen;
1675 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
1676 "flags / ssid\n");
1677 if (ret < 0 || ret >= end - pos)
1678 return pos - buf;
1679 pos += ret;
1680
1681 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
1682 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
1683 end - pos);
1684 if (ret < 0 || ret >= end - pos)
1685 return pos - buf;
1686 pos += ret;
1687 }
1688
1689 return pos - buf;
1690}
1691
1692
1693static int wpa_supplicant_ctrl_iface_select_network(
1694 struct wpa_supplicant *wpa_s, char *cmd)
1695{
1696 int id;
1697 struct wpa_ssid *ssid;
1698
1699 /* cmd: "<network id>" or "any" */
1700 if (os_strcmp(cmd, "any") == 0) {
1701 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
1702 ssid = NULL;
1703 } else {
1704 id = atoi(cmd);
1705 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
1706
1707 ssid = wpa_config_get_network(wpa_s->conf, id);
1708 if (ssid == NULL) {
1709 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1710 "network id=%d", id);
1711 return -1;
1712 }
1713 if (ssid->disabled == 2) {
1714 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1715 "SELECT_NETWORK with persistent P2P group");
1716 return -1;
1717 }
1718 }
1719
1720 wpa_supplicant_select_network(wpa_s, ssid);
1721
1722 return 0;
1723}
1724
1725
1726static int wpa_supplicant_ctrl_iface_enable_network(
1727 struct wpa_supplicant *wpa_s, char *cmd)
1728{
1729 int id;
1730 struct wpa_ssid *ssid;
1731
1732 /* cmd: "<network id>" or "all" */
1733 if (os_strcmp(cmd, "all") == 0) {
1734 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
1735 ssid = NULL;
1736 } else {
1737 id = atoi(cmd);
1738 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
1739
1740 ssid = wpa_config_get_network(wpa_s->conf, id);
1741 if (ssid == NULL) {
1742 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1743 "network id=%d", id);
1744 return -1;
1745 }
1746 if (ssid->disabled == 2) {
1747 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1748 "ENABLE_NETWORK with persistent P2P group");
1749 return -1;
1750 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001751
1752 if (os_strstr(cmd, " no-connect")) {
1753 ssid->disabled = 0;
1754 return 0;
1755 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001756 }
1757 wpa_supplicant_enable_network(wpa_s, ssid);
1758
1759 return 0;
1760}
1761
1762
1763static int wpa_supplicant_ctrl_iface_disable_network(
1764 struct wpa_supplicant *wpa_s, char *cmd)
1765{
1766 int id;
1767 struct wpa_ssid *ssid;
1768
1769 /* cmd: "<network id>" or "all" */
1770 if (os_strcmp(cmd, "all") == 0) {
1771 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
1772 ssid = NULL;
1773 } else {
1774 id = atoi(cmd);
1775 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
1776
1777 ssid = wpa_config_get_network(wpa_s->conf, id);
1778 if (ssid == NULL) {
1779 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1780 "network id=%d", id);
1781 return -1;
1782 }
1783 if (ssid->disabled == 2) {
1784 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1785 "DISABLE_NETWORK with persistent P2P "
1786 "group");
1787 return -1;
1788 }
1789 }
1790 wpa_supplicant_disable_network(wpa_s, ssid);
1791
1792 return 0;
1793}
1794
1795
1796static int wpa_supplicant_ctrl_iface_add_network(
1797 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1798{
1799 struct wpa_ssid *ssid;
1800 int ret;
1801
1802 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
1803
1804 ssid = wpa_config_add_network(wpa_s->conf);
1805 if (ssid == NULL)
1806 return -1;
1807
1808 wpas_notify_network_added(wpa_s, ssid);
1809
1810 ssid->disabled = 1;
1811 wpa_config_set_network_defaults(ssid);
1812
1813 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
1814 if (ret < 0 || (size_t) ret >= buflen)
1815 return -1;
1816 return ret;
1817}
1818
1819
1820static int wpa_supplicant_ctrl_iface_remove_network(
1821 struct wpa_supplicant *wpa_s, char *cmd)
1822{
1823 int id;
1824 struct wpa_ssid *ssid;
1825
1826 /* cmd: "<network id>" or "all" */
1827 if (os_strcmp(cmd, "all") == 0) {
1828 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
1829 ssid = wpa_s->conf->ssid;
1830 while (ssid) {
1831 struct wpa_ssid *remove_ssid = ssid;
1832 id = ssid->id;
1833 ssid = ssid->next;
1834 wpas_notify_network_removed(wpa_s, remove_ssid);
1835 wpa_config_remove_network(wpa_s->conf, id);
1836 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001837 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001838 if (wpa_s->current_ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001839#ifdef CONFIG_SME
1840 wpa_s->sme.prev_bssid_set = 0;
1841#endif /* CONFIG_SME */
Jouni Malinen75ecf522011-06-27 15:19:46 -07001842 wpa_sm_set_config(wpa_s->wpa, NULL);
1843 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001844 wpa_supplicant_disassociate(wpa_s,
1845 WLAN_REASON_DEAUTH_LEAVING);
1846 }
1847 return 0;
1848 }
1849
1850 id = atoi(cmd);
1851 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
1852
1853 ssid = wpa_config_get_network(wpa_s->conf, id);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001854 if (ssid)
1855 wpas_notify_network_removed(wpa_s, ssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001856 if (ssid == NULL ||
1857 wpa_config_remove_network(wpa_s->conf, id) < 0) {
1858 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1859 "id=%d", id);
1860 return -1;
1861 }
1862
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001863 if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001864#ifdef CONFIG_SME
1865 wpa_s->sme.prev_bssid_set = 0;
1866#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001867 /*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001868 * Invalidate the EAP session cache if the current or
1869 * previously used network is removed.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001870 */
1871 eapol_sm_invalidate_cached_session(wpa_s->eapol);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001872 }
1873
1874 if (ssid == wpa_s->current_ssid) {
Jouni Malinen75ecf522011-06-27 15:19:46 -07001875 wpa_sm_set_config(wpa_s->wpa, NULL);
1876 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001877
1878 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1879 }
1880
1881 return 0;
1882}
1883
1884
1885static int wpa_supplicant_ctrl_iface_set_network(
1886 struct wpa_supplicant *wpa_s, char *cmd)
1887{
1888 int id;
1889 struct wpa_ssid *ssid;
1890 char *name, *value;
1891
1892 /* cmd: "<network id> <variable name> <value>" */
1893 name = os_strchr(cmd, ' ');
1894 if (name == NULL)
1895 return -1;
1896 *name++ = '\0';
1897
1898 value = os_strchr(name, ' ');
1899 if (value == NULL)
1900 return -1;
1901 *value++ = '\0';
1902
1903 id = atoi(cmd);
1904 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
1905 id, name);
1906 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1907 (u8 *) value, os_strlen(value));
1908
1909 ssid = wpa_config_get_network(wpa_s->conf, id);
1910 if (ssid == NULL) {
1911 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1912 "id=%d", id);
1913 return -1;
1914 }
1915
1916 if (wpa_config_set(ssid, name, value, 0) < 0) {
1917 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
1918 "variable '%s'", name);
1919 return -1;
1920 }
1921
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001922 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
1923
1924 if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001925 /*
1926 * Invalidate the EAP session cache if anything in the current
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001927 * or previously used configuration changes.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001928 */
1929 eapol_sm_invalidate_cached_session(wpa_s->eapol);
1930 }
1931
1932 if ((os_strcmp(name, "psk") == 0 &&
1933 value[0] == '"' && ssid->ssid_len) ||
1934 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
1935 wpa_config_update_psk(ssid);
1936 else if (os_strcmp(name, "priority") == 0)
1937 wpa_config_update_prio_list(wpa_s->conf);
1938
1939 return 0;
1940}
1941
1942
1943static int wpa_supplicant_ctrl_iface_get_network(
1944 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1945{
1946 int id;
1947 size_t res;
1948 struct wpa_ssid *ssid;
1949 char *name, *value;
1950
1951 /* cmd: "<network id> <variable name>" */
1952 name = os_strchr(cmd, ' ');
1953 if (name == NULL || buflen == 0)
1954 return -1;
1955 *name++ = '\0';
1956
1957 id = atoi(cmd);
1958 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
1959 id, name);
1960
1961 ssid = wpa_config_get_network(wpa_s->conf, id);
1962 if (ssid == NULL) {
1963 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1964 "id=%d", id);
1965 return -1;
1966 }
1967
1968 value = wpa_config_get_no_key(ssid, name);
1969 if (value == NULL) {
1970 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
1971 "variable '%s'", name);
1972 return -1;
1973 }
1974
1975 res = os_strlcpy(buf, value, buflen);
1976 if (res >= buflen) {
1977 os_free(value);
1978 return -1;
1979 }
1980
1981 os_free(value);
1982
1983 return res;
1984}
1985
1986
Dmitry Shmidt04949592012-07-19 12:16:46 -07001987static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
1988 char *buf, size_t buflen)
1989{
1990 char *pos, *end;
1991 struct wpa_cred *cred;
1992 int ret;
1993
1994 pos = buf;
1995 end = buf + buflen;
1996 ret = os_snprintf(pos, end - pos,
1997 "cred id / realm / username / domain / imsi\n");
1998 if (ret < 0 || ret >= end - pos)
1999 return pos - buf;
2000 pos += ret;
2001
2002 cred = wpa_s->conf->cred;
2003 while (cred) {
2004 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
2005 cred->id, cred->realm ? cred->realm : "",
2006 cred->username ? cred->username : "",
2007 cred->domain ? cred->domain : "",
2008 cred->imsi ? cred->imsi : "");
2009 if (ret < 0 || ret >= end - pos)
2010 return pos - buf;
2011 pos += ret;
2012
2013 cred = cred->next;
2014 }
2015
2016 return pos - buf;
2017}
2018
2019
2020static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
2021 char *buf, size_t buflen)
2022{
2023 struct wpa_cred *cred;
2024 int ret;
2025
2026 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
2027
2028 cred = wpa_config_add_cred(wpa_s->conf);
2029 if (cred == NULL)
2030 return -1;
2031
2032 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
2033 if (ret < 0 || (size_t) ret >= buflen)
2034 return -1;
2035 return ret;
2036}
2037
2038
2039static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
2040 char *cmd)
2041{
2042 int id;
2043 struct wpa_cred *cred;
2044
2045 /* cmd: "<cred id>" or "all" */
2046 if (os_strcmp(cmd, "all") == 0) {
2047 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
2048 cred = wpa_s->conf->cred;
2049 while (cred) {
2050 id = cred->id;
2051 cred = cred->next;
2052 wpa_config_remove_cred(wpa_s->conf, id);
2053 }
2054 return 0;
2055 }
2056
2057 id = atoi(cmd);
2058 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
2059
2060 cred = wpa_config_get_cred(wpa_s->conf, id);
2061 if (cred == NULL ||
2062 wpa_config_remove_cred(wpa_s->conf, id) < 0) {
2063 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
2064 id);
2065 return -1;
2066 }
2067
2068 return 0;
2069}
2070
2071
2072static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
2073 char *cmd)
2074{
2075 int id;
2076 struct wpa_cred *cred;
2077 char *name, *value;
2078
2079 /* cmd: "<cred id> <variable name> <value>" */
2080 name = os_strchr(cmd, ' ');
2081 if (name == NULL)
2082 return -1;
2083 *name++ = '\0';
2084
2085 value = os_strchr(name, ' ');
2086 if (value == NULL)
2087 return -1;
2088 *value++ = '\0';
2089
2090 id = atoi(cmd);
2091 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
2092 id, name);
2093 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2094 (u8 *) value, os_strlen(value));
2095
2096 cred = wpa_config_get_cred(wpa_s->conf, id);
2097 if (cred == NULL) {
2098 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
2099 id);
2100 return -1;
2101 }
2102
2103 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
2104 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
2105 "variable '%s'", name);
2106 return -1;
2107 }
2108
2109 return 0;
2110}
2111
2112
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002113#ifndef CONFIG_NO_CONFIG_WRITE
2114static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
2115{
2116 int ret;
2117
2118 if (!wpa_s->conf->update_config) {
2119 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
2120 "to update configuration (update_config=0)");
2121 return -1;
2122 }
2123
2124 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2125 if (ret) {
2126 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
2127 "update configuration");
2128 } else {
2129 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
2130 " updated");
2131 }
2132
2133 return ret;
2134}
2135#endif /* CONFIG_NO_CONFIG_WRITE */
2136
2137
2138static int ctrl_iface_get_capability_pairwise(int res, char *strict,
2139 struct wpa_driver_capa *capa,
2140 char *buf, size_t buflen)
2141{
2142 int ret, first = 1;
2143 char *pos, *end;
2144 size_t len;
2145
2146 pos = buf;
2147 end = pos + buflen;
2148
2149 if (res < 0) {
2150 if (strict)
2151 return 0;
2152 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
2153 if (len >= buflen)
2154 return -1;
2155 return len;
2156 }
2157
2158 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2159 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2160 if (ret < 0 || ret >= end - pos)
2161 return pos - buf;
2162 pos += ret;
2163 first = 0;
2164 }
2165
2166 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2167 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2168 if (ret < 0 || ret >= end - pos)
2169 return pos - buf;
2170 pos += ret;
2171 first = 0;
2172 }
2173
2174 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2175 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
2176 if (ret < 0 || ret >= end - pos)
2177 return pos - buf;
2178 pos += ret;
2179 first = 0;
2180 }
2181
2182 return pos - buf;
2183}
2184
2185
2186static int ctrl_iface_get_capability_group(int res, char *strict,
2187 struct wpa_driver_capa *capa,
2188 char *buf, size_t buflen)
2189{
2190 int ret, first = 1;
2191 char *pos, *end;
2192 size_t len;
2193
2194 pos = buf;
2195 end = pos + buflen;
2196
2197 if (res < 0) {
2198 if (strict)
2199 return 0;
2200 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
2201 if (len >= buflen)
2202 return -1;
2203 return len;
2204 }
2205
2206 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2207 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2208 if (ret < 0 || ret >= end - pos)
2209 return pos - buf;
2210 pos += ret;
2211 first = 0;
2212 }
2213
2214 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2215 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2216 if (ret < 0 || ret >= end - pos)
2217 return pos - buf;
2218 pos += ret;
2219 first = 0;
2220 }
2221
2222 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2223 ret = os_snprintf(pos, end - pos, "%sWEP104",
2224 first ? "" : " ");
2225 if (ret < 0 || ret >= end - pos)
2226 return pos - buf;
2227 pos += ret;
2228 first = 0;
2229 }
2230
2231 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2232 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
2233 if (ret < 0 || ret >= end - pos)
2234 return pos - buf;
2235 pos += ret;
2236 first = 0;
2237 }
2238
2239 return pos - buf;
2240}
2241
2242
2243static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
2244 struct wpa_driver_capa *capa,
2245 char *buf, size_t buflen)
2246{
2247 int ret;
2248 char *pos, *end;
2249 size_t len;
2250
2251 pos = buf;
2252 end = pos + buflen;
2253
2254 if (res < 0) {
2255 if (strict)
2256 return 0;
2257 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
2258 "NONE", buflen);
2259 if (len >= buflen)
2260 return -1;
2261 return len;
2262 }
2263
2264 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
2265 if (ret < 0 || ret >= end - pos)
2266 return pos - buf;
2267 pos += ret;
2268
2269 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2270 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2271 ret = os_snprintf(pos, end - pos, " WPA-EAP");
2272 if (ret < 0 || ret >= end - pos)
2273 return pos - buf;
2274 pos += ret;
2275 }
2276
2277 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2278 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2279 ret = os_snprintf(pos, end - pos, " WPA-PSK");
2280 if (ret < 0 || ret >= end - pos)
2281 return pos - buf;
2282 pos += ret;
2283 }
2284
2285 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2286 ret = os_snprintf(pos, end - pos, " WPA-NONE");
2287 if (ret < 0 || ret >= end - pos)
2288 return pos - buf;
2289 pos += ret;
2290 }
2291
2292 return pos - buf;
2293}
2294
2295
2296static int ctrl_iface_get_capability_proto(int res, char *strict,
2297 struct wpa_driver_capa *capa,
2298 char *buf, size_t buflen)
2299{
2300 int ret, first = 1;
2301 char *pos, *end;
2302 size_t len;
2303
2304 pos = buf;
2305 end = pos + buflen;
2306
2307 if (res < 0) {
2308 if (strict)
2309 return 0;
2310 len = os_strlcpy(buf, "RSN WPA", buflen);
2311 if (len >= buflen)
2312 return -1;
2313 return len;
2314 }
2315
2316 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2317 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2318 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
2319 if (ret < 0 || ret >= end - pos)
2320 return pos - buf;
2321 pos += ret;
2322 first = 0;
2323 }
2324
2325 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2326 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2327 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
2328 if (ret < 0 || ret >= end - pos)
2329 return pos - buf;
2330 pos += ret;
2331 first = 0;
2332 }
2333
2334 return pos - buf;
2335}
2336
2337
2338static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
2339 struct wpa_driver_capa *capa,
2340 char *buf, size_t buflen)
2341{
2342 int ret, first = 1;
2343 char *pos, *end;
2344 size_t len;
2345
2346 pos = buf;
2347 end = pos + buflen;
2348
2349 if (res < 0) {
2350 if (strict)
2351 return 0;
2352 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
2353 if (len >= buflen)
2354 return -1;
2355 return len;
2356 }
2357
2358 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
2359 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
2360 if (ret < 0 || ret >= end - pos)
2361 return pos - buf;
2362 pos += ret;
2363 first = 0;
2364 }
2365
2366 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
2367 ret = os_snprintf(pos, end - pos, "%sSHARED",
2368 first ? "" : " ");
2369 if (ret < 0 || ret >= end - pos)
2370 return pos - buf;
2371 pos += ret;
2372 first = 0;
2373 }
2374
2375 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
2376 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
2377 if (ret < 0 || ret >= end - pos)
2378 return pos - buf;
2379 pos += ret;
2380 first = 0;
2381 }
2382
2383 return pos - buf;
2384}
2385
2386
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002387static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
2388 char *buf, size_t buflen)
2389{
2390 struct hostapd_channel_data *chnl;
2391 int ret, i, j;
2392 char *pos, *end, *hmode;
2393
2394 pos = buf;
2395 end = pos + buflen;
2396
2397 for (j = 0; j < wpa_s->hw.num_modes; j++) {
2398 switch (wpa_s->hw.modes[j].mode) {
2399 case HOSTAPD_MODE_IEEE80211B:
2400 hmode = "B";
2401 break;
2402 case HOSTAPD_MODE_IEEE80211G:
2403 hmode = "G";
2404 break;
2405 case HOSTAPD_MODE_IEEE80211A:
2406 hmode = "A";
2407 break;
2408 default:
2409 return pos - buf;
2410 }
2411 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
2412 if (ret < 0 || ret >= end - pos)
2413 return pos - buf;
2414 pos += ret;
2415 chnl = wpa_s->hw.modes[j].channels;
2416 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
2417 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
2418 if (ret < 0 || ret >= end - pos)
2419 return pos - buf;
2420 pos += ret;
2421 }
2422 ret = os_snprintf(pos, end - pos, "\n");
2423 if (ret < 0 || ret >= end - pos)
2424 return pos - buf;
2425 pos += ret;
2426 }
2427
2428 return pos - buf;
2429}
2430
2431
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002432static int wpa_supplicant_ctrl_iface_get_capability(
2433 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
2434 size_t buflen)
2435{
2436 struct wpa_driver_capa capa;
2437 int res;
2438 char *strict;
2439 char field[30];
2440 size_t len;
2441
2442 /* Determine whether or not strict checking was requested */
2443 len = os_strlcpy(field, _field, sizeof(field));
2444 if (len >= sizeof(field))
2445 return -1;
2446 strict = os_strchr(field, ' ');
2447 if (strict != NULL) {
2448 *strict++ = '\0';
2449 if (os_strcmp(strict, "strict") != 0)
2450 return -1;
2451 }
2452
2453 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
2454 field, strict ? strict : "");
2455
2456 if (os_strcmp(field, "eap") == 0) {
2457 return eap_get_names(buf, buflen);
2458 }
2459
2460 res = wpa_drv_get_capa(wpa_s, &capa);
2461
2462 if (os_strcmp(field, "pairwise") == 0)
2463 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
2464 buf, buflen);
2465
2466 if (os_strcmp(field, "group") == 0)
2467 return ctrl_iface_get_capability_group(res, strict, &capa,
2468 buf, buflen);
2469
2470 if (os_strcmp(field, "key_mgmt") == 0)
2471 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
2472 buf, buflen);
2473
2474 if (os_strcmp(field, "proto") == 0)
2475 return ctrl_iface_get_capability_proto(res, strict, &capa,
2476 buf, buflen);
2477
2478 if (os_strcmp(field, "auth_alg") == 0)
2479 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
2480 buf, buflen);
2481
Dmitry Shmidt0e6d08e2012-07-10 12:49:30 -07002482 if (os_strcmp(field, "channels") == 0)
2483 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
2484
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002485 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
2486 field);
2487
2488 return -1;
2489}
2490
2491
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002492#ifdef CONFIG_INTERWORKING
2493static char * anqp_add_hex(char *pos, char *end, const char *title,
2494 struct wpabuf *data)
2495{
2496 char *start = pos;
2497 size_t i;
2498 int ret;
2499 const u8 *d;
2500
2501 if (data == NULL)
2502 return start;
2503
2504 ret = os_snprintf(pos, end - pos, "%s=", title);
2505 if (ret < 0 || ret >= end - pos)
2506 return start;
2507 pos += ret;
2508
2509 d = wpabuf_head_u8(data);
2510 for (i = 0; i < wpabuf_len(data); i++) {
2511 ret = os_snprintf(pos, end - pos, "%02x", *d++);
2512 if (ret < 0 || ret >= end - pos)
2513 return start;
2514 pos += ret;
2515 }
2516
2517 ret = os_snprintf(pos, end - pos, "\n");
2518 if (ret < 0 || ret >= end - pos)
2519 return start;
2520 pos += ret;
2521
2522 return pos;
2523}
2524#endif /* CONFIG_INTERWORKING */
2525
2526
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002527static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
2528 unsigned long mask, char *buf, size_t buflen)
2529{
2530 size_t i;
2531 int ret;
2532 char *pos, *end;
2533 const u8 *ie, *ie2;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002534
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002535 pos = buf;
2536 end = buf + buflen;
2537
2538 if (mask & WPA_BSS_MASK_ID) {
2539 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
2540 if (ret < 0 || ret >= end - pos)
2541 return 0;
2542 pos += ret;
2543 }
2544
2545 if (mask & WPA_BSS_MASK_BSSID) {
2546 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
2547 MAC2STR(bss->bssid));
2548 if (ret < 0 || ret >= end - pos)
2549 return 0;
2550 pos += ret;
2551 }
2552
2553 if (mask & WPA_BSS_MASK_FREQ) {
2554 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
2555 if (ret < 0 || ret >= end - pos)
2556 return 0;
2557 pos += ret;
2558 }
2559
2560 if (mask & WPA_BSS_MASK_BEACON_INT) {
2561 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
2562 bss->beacon_int);
2563 if (ret < 0 || ret >= end - pos)
2564 return 0;
2565 pos += ret;
2566 }
2567
2568 if (mask & WPA_BSS_MASK_CAPABILITIES) {
2569 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
2570 bss->caps);
2571 if (ret < 0 || ret >= end - pos)
2572 return 0;
2573 pos += ret;
2574 }
2575
2576 if (mask & WPA_BSS_MASK_QUAL) {
2577 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
2578 if (ret < 0 || ret >= end - pos)
2579 return 0;
2580 pos += ret;
2581 }
2582
2583 if (mask & WPA_BSS_MASK_NOISE) {
2584 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
2585 if (ret < 0 || ret >= end - pos)
2586 return 0;
2587 pos += ret;
2588 }
2589
2590 if (mask & WPA_BSS_MASK_LEVEL) {
2591 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
2592 if (ret < 0 || ret >= end - pos)
2593 return 0;
2594 pos += ret;
2595 }
2596
2597 if (mask & WPA_BSS_MASK_TSF) {
2598 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
2599 (unsigned long long) bss->tsf);
2600 if (ret < 0 || ret >= end - pos)
2601 return 0;
2602 pos += ret;
2603 }
2604
2605 if (mask & WPA_BSS_MASK_AGE) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002606 struct os_time now;
2607
2608 os_get_time(&now);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002609 ret = os_snprintf(pos, end - pos, "age=%d\n",
2610 (int) (now.sec - bss->last_update.sec));
2611 if (ret < 0 || ret >= end - pos)
2612 return 0;
2613 pos += ret;
2614 }
2615
2616 if (mask & WPA_BSS_MASK_IE) {
2617 ret = os_snprintf(pos, end - pos, "ie=");
2618 if (ret < 0 || ret >= end - pos)
2619 return 0;
2620 pos += ret;
2621
2622 ie = (const u8 *) (bss + 1);
2623 for (i = 0; i < bss->ie_len; i++) {
2624 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
2625 if (ret < 0 || ret >= end - pos)
2626 return 0;
2627 pos += ret;
2628 }
2629
2630 ret = os_snprintf(pos, end - pos, "\n");
2631 if (ret < 0 || ret >= end - pos)
2632 return 0;
2633 pos += ret;
2634 }
2635
2636 if (mask & WPA_BSS_MASK_FLAGS) {
2637 ret = os_snprintf(pos, end - pos, "flags=");
2638 if (ret < 0 || ret >= end - pos)
2639 return 0;
2640 pos += ret;
2641
2642 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2643 if (ie)
2644 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
2645 2 + ie[1]);
2646 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
2647 if (ie2)
2648 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
2649 2 + ie2[1]);
2650 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
2651 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
2652 ret = os_snprintf(pos, end - pos, "[WEP]");
2653 if (ret < 0 || ret >= end - pos)
2654 return 0;
2655 pos += ret;
2656 }
2657 if (bss->caps & IEEE80211_CAP_IBSS) {
2658 ret = os_snprintf(pos, end - pos, "[IBSS]");
2659 if (ret < 0 || ret >= end - pos)
2660 return 0;
2661 pos += ret;
2662 }
2663 if (bss->caps & IEEE80211_CAP_ESS) {
2664 ret = os_snprintf(pos, end - pos, "[ESS]");
2665 if (ret < 0 || ret >= end - pos)
2666 return 0;
2667 pos += ret;
2668 }
2669 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
2670 ret = os_snprintf(pos, end - pos, "[P2P]");
2671 if (ret < 0 || ret >= end - pos)
2672 return 0;
2673 pos += ret;
2674 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002675#ifdef CONFIG_HS20
2676 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
2677 ret = os_snprintf(pos, end - pos, "[HS20]");
2678 if (ret < 0 || ret >= end - pos)
2679 return -1;
2680 pos += ret;
2681 }
2682#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002683
2684 ret = os_snprintf(pos, end - pos, "\n");
2685 if (ret < 0 || ret >= end - pos)
2686 return 0;
2687 pos += ret;
2688 }
2689
2690 if (mask & WPA_BSS_MASK_SSID) {
2691 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
2692 wpa_ssid_txt(bss->ssid, bss->ssid_len));
2693 if (ret < 0 || ret >= end - pos)
2694 return 0;
2695 pos += ret;
2696 }
2697
2698#ifdef CONFIG_WPS
2699 if (mask & WPA_BSS_MASK_WPS_SCAN) {
2700 ie = (const u8 *) (bss + 1);
2701 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
2702 if (ret < 0 || ret >= end - pos)
2703 return 0;
2704 pos += ret;
2705 }
2706#endif /* CONFIG_WPS */
2707
2708#ifdef CONFIG_P2P
2709 if (mask & WPA_BSS_MASK_P2P_SCAN) {
2710 ie = (const u8 *) (bss + 1);
2711 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
2712 if (ret < 0 || ret >= end - pos)
2713 return 0;
2714 pos += ret;
2715 }
2716#endif /* CONFIG_P2P */
2717
2718#ifdef CONFIG_INTERWORKING
2719 if (mask & WPA_BSS_MASK_INTERNETW) {
2720 pos = anqp_add_hex(pos, end, "anqp_venue_name",
2721 bss->anqp_venue_name);
2722 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
2723 bss->anqp_network_auth_type);
2724 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
2725 bss->anqp_roaming_consortium);
2726 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
2727 bss->anqp_ip_addr_type_availability);
2728 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
2729 bss->anqp_nai_realm);
2730 pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
2731 pos = anqp_add_hex(pos, end, "anqp_domain_name",
2732 bss->anqp_domain_name);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002733#ifdef CONFIG_HS20
2734 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
2735 bss->hs20_operator_friendly_name);
2736 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
2737 bss->hs20_wan_metrics);
2738 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
2739 bss->hs20_connection_capability);
2740#endif /* CONFIG_HS20 */
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002741 }
2742#endif /* CONFIG_INTERWORKING */
2743
Irfan Sheriffe2ea0082012-08-13 10:56:16 -07002744#ifdef ANDROID
2745 ret = os_snprintf(pos, end - pos, "====\n");
2746 if (ret < 0 || ret >= end - pos)
2747 return 0;
2748 pos += ret;
2749#endif
2750
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002751 return pos - buf;
2752}
2753
Dmitry Shmidt04949592012-07-19 12:16:46 -07002754
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002755static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
2756 const char *cmd, char *buf,
2757 size_t buflen)
2758{
2759 u8 bssid[ETH_ALEN];
2760 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002761 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002762 struct wpa_bss *bsslast = NULL;
2763 struct dl_list *next;
2764 int ret = 0;
2765 int len;
2766 char *ctmp;
2767 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002768
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002769 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
2770 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
2771 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002772 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002773 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
2774 list_id);
2775 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002776 unsigned int id1, id2;
2777
2778 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
2779 wpa_printf(MSG_INFO, "Wrong BSS range "
2780 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002781 return 0;
2782 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002783
2784 id1 = atoi(cmd + 6);
2785 bss = wpa_bss_get_id(wpa_s, id1);
2786 id2 = atoi(ctmp + 1);
2787 if (id2 == 0)
2788 bsslast = dl_list_last(&wpa_s->bss_id,
2789 struct wpa_bss,
2790 list_id);
2791 else {
2792 bsslast = wpa_bss_get_id(wpa_s, id2);
2793 if (bsslast == NULL && bss && id2 > id1) {
2794 struct wpa_bss *tmp = bss;
2795 for (;;) {
2796 next = tmp->list_id.next;
2797 if (next == &wpa_s->bss_id)
2798 break;
2799 tmp = dl_list_entry(
2800 next, struct wpa_bss,
2801 list_id);
2802 if (tmp->id > id2)
2803 break;
2804 bsslast = tmp;
2805 }
2806 }
2807 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002808 }
2809 } else if (os_strcmp(cmd, "FIRST") == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002810 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002811 else if (os_strncmp(cmd, "ID-", 3) == 0) {
2812 i = atoi(cmd + 3);
2813 bss = wpa_bss_get_id(wpa_s, i);
2814 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
2815 i = atoi(cmd + 5);
2816 bss = wpa_bss_get_id(wpa_s, i);
2817 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002818 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002819 if (next == &wpa_s->bss_id)
2820 bss = NULL;
2821 else
2822 bss = dl_list_entry(next, struct wpa_bss,
2823 list_id);
2824 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002825#ifdef CONFIG_P2P
2826 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
2827 if (hwaddr_aton(cmd + 13, bssid) == 0)
2828 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
2829 else
2830 bss = NULL;
2831#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002832 } else if (hwaddr_aton(cmd, bssid) == 0)
2833 bss = wpa_bss_get_bssid(wpa_s, bssid);
2834 else {
2835 struct wpa_bss *tmp;
2836 i = atoi(cmd);
2837 bss = NULL;
2838 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
2839 {
2840 if (i-- == 0) {
2841 bss = tmp;
2842 break;
2843 }
2844 }
2845 }
2846
Dmitry Shmidt04949592012-07-19 12:16:46 -07002847 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
2848 mask = strtoul(ctmp + 5, NULL, 0x10);
2849 if (mask == 0)
2850 mask = WPA_BSS_MASK_ALL;
2851 }
2852
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002853 if (bss == NULL)
2854 return 0;
2855
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002856 if (bsslast == NULL)
2857 bsslast = bss;
2858 do {
2859 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
2860 ret += len;
2861 buf += len;
2862 buflen -= len;
2863 if (bss == bsslast)
2864 break;
2865 next = bss->list_id.next;
2866 if (next == &wpa_s->bss_id)
2867 break;
2868 bss = dl_list_entry(next, struct wpa_bss, list_id);
2869 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002870
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002871 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002872}
2873
2874
2875static int wpa_supplicant_ctrl_iface_ap_scan(
2876 struct wpa_supplicant *wpa_s, char *cmd)
2877{
2878 int ap_scan = atoi(cmd);
2879 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
2880}
2881
2882
2883static int wpa_supplicant_ctrl_iface_scan_interval(
2884 struct wpa_supplicant *wpa_s, char *cmd)
2885{
2886 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002887 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002888}
2889
2890
2891static int wpa_supplicant_ctrl_iface_bss_expire_age(
2892 struct wpa_supplicant *wpa_s, char *cmd)
2893{
2894 int expire_age = atoi(cmd);
2895 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
2896}
2897
2898
2899static int wpa_supplicant_ctrl_iface_bss_expire_count(
2900 struct wpa_supplicant *wpa_s, char *cmd)
2901{
2902 int expire_count = atoi(cmd);
2903 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
2904}
2905
2906
2907static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
2908{
2909 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
2910 /* MLME-DELETEKEYS.request */
2911 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
2912 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
2913 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
2914 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
2915#ifdef CONFIG_IEEE80211W
2916 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
2917 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
2918#endif /* CONFIG_IEEE80211W */
2919
2920 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
2921 0);
2922 /* MLME-SETPROTECTION.request(None) */
2923 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
2924 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
2925 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
2926 wpa_sm_drop_sa(wpa_s->wpa);
2927}
2928
2929
2930static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
2931 char *addr)
2932{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002933#ifdef CONFIG_NO_SCAN_PROCESSING
2934 return -1;
2935#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002936 u8 bssid[ETH_ALEN];
2937 struct wpa_bss *bss;
2938 struct wpa_ssid *ssid = wpa_s->current_ssid;
2939
2940 if (hwaddr_aton(addr, bssid)) {
2941 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
2942 "address '%s'", addr);
2943 return -1;
2944 }
2945
2946 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
2947
2948 bss = wpa_bss_get_bssid(wpa_s, bssid);
2949 if (!bss) {
2950 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
2951 "from BSS table");
2952 return -1;
2953 }
2954
2955 /*
2956 * TODO: Find best network configuration block from configuration to
2957 * allow roaming to other networks
2958 */
2959
2960 if (!ssid) {
2961 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
2962 "configuration known for the target AP");
2963 return -1;
2964 }
2965
2966 wpa_s->reassociate = 1;
2967 wpa_supplicant_connect(wpa_s, bss, ssid);
2968
2969 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002970#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002971}
2972
2973
2974#ifdef CONFIG_P2P
2975static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
2976{
2977 unsigned int timeout = atoi(cmd);
2978 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002979 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
2980 char *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002981
2982 if (os_strstr(cmd, "type=social"))
2983 type = P2P_FIND_ONLY_SOCIAL;
2984 else if (os_strstr(cmd, "type=progressive"))
2985 type = P2P_FIND_PROGRESSIVE;
2986
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002987 pos = os_strstr(cmd, "dev_id=");
2988 if (pos) {
2989 pos += 7;
2990 if (hwaddr_aton(pos, dev_id))
2991 return -1;
2992 _dev_id = dev_id;
2993 }
2994
2995 return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002996}
2997
2998
2999static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
3000 char *buf, size_t buflen)
3001{
3002 u8 addr[ETH_ALEN];
3003 char *pos, *pos2;
3004 char *pin = NULL;
3005 enum p2p_wps_method wps_method;
3006 int new_pin;
3007 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003008 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003009 int join;
3010 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003011 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003012 int go_intent = -1;
3013 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003014 int pd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003015
Dmitry Shmidt04949592012-07-19 12:16:46 -07003016 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
3017 * [persistent|persistent=<network id>]
3018 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003019
3020 if (hwaddr_aton(cmd, addr))
3021 return -1;
3022
3023 pos = cmd + 17;
3024 if (*pos != ' ')
3025 return -1;
3026 pos++;
3027
3028 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003029 pos2 = os_strstr(pos, " persistent=");
3030 if (pos2) {
3031 struct wpa_ssid *ssid;
3032 persistent_id = atoi(pos2 + 12);
3033 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
3034 if (ssid == NULL || ssid->disabled != 2 ||
3035 ssid->mode != WPAS_MODE_P2P_GO) {
3036 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3037 "SSID id=%d for persistent P2P group (GO)",
3038 persistent_id);
3039 return -1;
3040 }
3041 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003042 join = os_strstr(pos, " join") != NULL;
3043 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003044 automatic = os_strstr(pos, " auto") != NULL;
3045 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003046
3047 pos2 = os_strstr(pos, " go_intent=");
3048 if (pos2) {
3049 pos2 += 11;
3050 go_intent = atoi(pos2);
3051 if (go_intent < 0 || go_intent > 15)
3052 return -1;
3053 }
3054
3055 pos2 = os_strstr(pos, " freq=");
3056 if (pos2) {
3057 pos2 += 6;
3058 freq = atoi(pos2);
3059 if (freq <= 0)
3060 return -1;
3061 }
3062
3063 if (os_strncmp(pos, "pin", 3) == 0) {
3064 /* Request random PIN (to be displayed) and enable the PIN */
3065 wps_method = WPS_PIN_DISPLAY;
3066 } else if (os_strncmp(pos, "pbc", 3) == 0) {
3067 wps_method = WPS_PBC;
3068 } else {
3069 pin = pos;
3070 pos = os_strchr(pin, ' ');
3071 wps_method = WPS_PIN_KEYPAD;
3072 if (pos) {
3073 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003074 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003075 wps_method = WPS_PIN_DISPLAY;
3076 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003077 if (!wps_pin_str_valid(pin)) {
3078 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
3079 return 17;
3080 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003081 }
3082
3083 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003084 persistent_group, automatic, join,
3085 auth, go_intent, freq, persistent_id, pd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003086 if (new_pin == -2) {
3087 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
3088 return 25;
3089 }
3090 if (new_pin == -3) {
3091 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
3092 return 25;
3093 }
3094 if (new_pin < 0)
3095 return -1;
3096 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
3097 ret = os_snprintf(buf, buflen, "%08d", new_pin);
3098 if (ret < 0 || (size_t) ret >= buflen)
3099 return -1;
3100 return ret;
3101 }
3102
3103 os_memcpy(buf, "OK\n", 3);
3104 return 3;
3105}
3106
3107
3108static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
3109{
3110 unsigned int timeout = atoi(cmd);
3111 return wpas_p2p_listen(wpa_s, timeout);
3112}
3113
3114
3115static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
3116{
3117 u8 addr[ETH_ALEN];
3118 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003119 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003120
Dmitry Shmidt04949592012-07-19 12:16:46 -07003121 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003122
3123 if (hwaddr_aton(cmd, addr))
3124 return -1;
3125
3126 pos = cmd + 17;
3127 if (*pos != ' ')
3128 return -1;
3129 pos++;
3130
Dmitry Shmidt04949592012-07-19 12:16:46 -07003131 if (os_strstr(pos, " join") != NULL)
3132 use = WPAS_P2P_PD_FOR_JOIN;
3133 else if (os_strstr(pos, " auto") != NULL)
3134 use = WPAS_P2P_PD_AUTO;
3135
3136 return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003137}
3138
3139
3140static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
3141 size_t buflen)
3142{
3143 struct wpa_ssid *ssid = wpa_s->current_ssid;
3144
3145 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
3146 ssid->passphrase == NULL)
3147 return -1;
3148
3149 os_strlcpy(buf, ssid->passphrase, buflen);
3150 return os_strlen(buf);
3151}
3152
3153
3154static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
3155 char *buf, size_t buflen)
3156{
3157 u64 ref;
3158 int res;
3159 u8 dst_buf[ETH_ALEN], *dst;
3160 struct wpabuf *tlvs;
3161 char *pos;
3162 size_t len;
3163
3164 if (hwaddr_aton(cmd, dst_buf))
3165 return -1;
3166 dst = dst_buf;
3167 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
3168 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
3169 dst = NULL;
3170 pos = cmd + 17;
3171 if (*pos != ' ')
3172 return -1;
3173 pos++;
3174
3175 if (os_strncmp(pos, "upnp ", 5) == 0) {
3176 u8 version;
3177 pos += 5;
3178 if (hexstr2bin(pos, &version, 1) < 0)
3179 return -1;
3180 pos += 2;
3181 if (*pos != ' ')
3182 return -1;
3183 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003184 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003185 } else {
3186 len = os_strlen(pos);
3187 if (len & 1)
3188 return -1;
3189 len /= 2;
3190 tlvs = wpabuf_alloc(len);
3191 if (tlvs == NULL)
3192 return -1;
3193 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
3194 wpabuf_free(tlvs);
3195 return -1;
3196 }
3197
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003198 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003199 wpabuf_free(tlvs);
3200 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003201 if (ref == 0)
3202 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003203 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
3204 if (res < 0 || (unsigned) res >= buflen)
3205 return -1;
3206 return res;
3207}
3208
3209
3210static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
3211 char *cmd)
3212{
3213 long long unsigned val;
3214 u64 req;
3215 if (sscanf(cmd, "%llx", &val) != 1)
3216 return -1;
3217 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003218 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003219}
3220
3221
3222static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
3223{
3224 int freq;
3225 u8 dst[ETH_ALEN];
3226 u8 dialog_token;
3227 struct wpabuf *resp_tlvs;
3228 char *pos, *pos2;
3229 size_t len;
3230
3231 pos = os_strchr(cmd, ' ');
3232 if (pos == NULL)
3233 return -1;
3234 *pos++ = '\0';
3235 freq = atoi(cmd);
3236 if (freq == 0)
3237 return -1;
3238
3239 if (hwaddr_aton(pos, dst))
3240 return -1;
3241 pos += 17;
3242 if (*pos != ' ')
3243 return -1;
3244 pos++;
3245
3246 pos2 = os_strchr(pos, ' ');
3247 if (pos2 == NULL)
3248 return -1;
3249 *pos2++ = '\0';
3250 dialog_token = atoi(pos);
3251
3252 len = os_strlen(pos2);
3253 if (len & 1)
3254 return -1;
3255 len /= 2;
3256 resp_tlvs = wpabuf_alloc(len);
3257 if (resp_tlvs == NULL)
3258 return -1;
3259 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
3260 wpabuf_free(resp_tlvs);
3261 return -1;
3262 }
3263
3264 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
3265 wpabuf_free(resp_tlvs);
3266 return 0;
3267}
3268
3269
3270static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
3271 char *cmd)
3272{
Dmitry Shmidt04949592012-07-19 12:16:46 -07003273 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
3274 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003275 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
3276 return 0;
3277}
3278
3279
3280static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
3281 char *cmd)
3282{
3283 char *pos;
3284 size_t len;
3285 struct wpabuf *query, *resp;
3286
3287 pos = os_strchr(cmd, ' ');
3288 if (pos == NULL)
3289 return -1;
3290 *pos++ = '\0';
3291
3292 len = os_strlen(cmd);
3293 if (len & 1)
3294 return -1;
3295 len /= 2;
3296 query = wpabuf_alloc(len);
3297 if (query == NULL)
3298 return -1;
3299 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3300 wpabuf_free(query);
3301 return -1;
3302 }
3303
3304 len = os_strlen(pos);
3305 if (len & 1) {
3306 wpabuf_free(query);
3307 return -1;
3308 }
3309 len /= 2;
3310 resp = wpabuf_alloc(len);
3311 if (resp == NULL) {
3312 wpabuf_free(query);
3313 return -1;
3314 }
3315 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
3316 wpabuf_free(query);
3317 wpabuf_free(resp);
3318 return -1;
3319 }
3320
3321 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
3322 wpabuf_free(query);
3323 wpabuf_free(resp);
3324 return -1;
3325 }
3326 return 0;
3327}
3328
3329
3330static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3331{
3332 char *pos;
3333 u8 version;
3334
3335 pos = os_strchr(cmd, ' ');
3336 if (pos == NULL)
3337 return -1;
3338 *pos++ = '\0';
3339
3340 if (hexstr2bin(cmd, &version, 1) < 0)
3341 return -1;
3342
3343 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
3344}
3345
3346
3347static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
3348{
3349 char *pos;
3350
3351 pos = os_strchr(cmd, ' ');
3352 if (pos == NULL)
3353 return -1;
3354 *pos++ = '\0';
3355
3356 if (os_strcmp(cmd, "bonjour") == 0)
3357 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
3358 if (os_strcmp(cmd, "upnp") == 0)
3359 return p2p_ctrl_service_add_upnp(wpa_s, pos);
3360 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3361 return -1;
3362}
3363
3364
3365static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
3366 char *cmd)
3367{
3368 size_t len;
3369 struct wpabuf *query;
3370 int ret;
3371
3372 len = os_strlen(cmd);
3373 if (len & 1)
3374 return -1;
3375 len /= 2;
3376 query = wpabuf_alloc(len);
3377 if (query == NULL)
3378 return -1;
3379 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3380 wpabuf_free(query);
3381 return -1;
3382 }
3383
3384 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
3385 wpabuf_free(query);
3386 return ret;
3387}
3388
3389
3390static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3391{
3392 char *pos;
3393 u8 version;
3394
3395 pos = os_strchr(cmd, ' ');
3396 if (pos == NULL)
3397 return -1;
3398 *pos++ = '\0';
3399
3400 if (hexstr2bin(cmd, &version, 1) < 0)
3401 return -1;
3402
3403 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
3404}
3405
3406
3407static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
3408{
3409 char *pos;
3410
3411 pos = os_strchr(cmd, ' ');
3412 if (pos == NULL)
3413 return -1;
3414 *pos++ = '\0';
3415
3416 if (os_strcmp(cmd, "bonjour") == 0)
3417 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
3418 if (os_strcmp(cmd, "upnp") == 0)
3419 return p2p_ctrl_service_del_upnp(wpa_s, pos);
3420 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3421 return -1;
3422}
3423
3424
3425static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
3426{
3427 u8 addr[ETH_ALEN];
3428
3429 /* <addr> */
3430
3431 if (hwaddr_aton(cmd, addr))
3432 return -1;
3433
3434 return wpas_p2p_reject(wpa_s, addr);
3435}
3436
3437
3438static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
3439{
3440 char *pos;
3441 int id;
3442 struct wpa_ssid *ssid;
3443 u8 peer[ETH_ALEN];
3444
3445 id = atoi(cmd);
3446 pos = os_strstr(cmd, " peer=");
3447 if (pos) {
3448 pos += 6;
3449 if (hwaddr_aton(pos, peer))
3450 return -1;
3451 }
3452 ssid = wpa_config_get_network(wpa_s->conf, id);
3453 if (ssid == NULL || ssid->disabled != 2) {
3454 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3455 "for persistent P2P group",
3456 id);
3457 return -1;
3458 }
3459
3460 return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
3461}
3462
3463
3464static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
3465{
3466 char *pos;
3467 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
3468
3469 pos = os_strstr(cmd, " peer=");
3470 if (!pos)
3471 return -1;
3472
3473 *pos = '\0';
3474 pos += 6;
3475 if (hwaddr_aton(pos, peer)) {
3476 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
3477 return -1;
3478 }
3479
3480 pos = os_strstr(pos, " go_dev_addr=");
3481 if (pos) {
3482 pos += 13;
3483 if (hwaddr_aton(pos, go_dev_addr)) {
3484 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
3485 pos);
3486 return -1;
3487 }
3488 go_dev = go_dev_addr;
3489 }
3490
3491 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
3492}
3493
3494
3495static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
3496{
3497 if (os_strncmp(cmd, "persistent=", 11) == 0)
3498 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
3499 if (os_strncmp(cmd, "group=", 6) == 0)
3500 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
3501
3502 return -1;
3503}
3504
3505
3506static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
3507 char *cmd, int freq)
3508{
3509 int id;
3510 struct wpa_ssid *ssid;
3511
3512 id = atoi(cmd);
3513 ssid = wpa_config_get_network(wpa_s->conf, id);
3514 if (ssid == NULL || ssid->disabled != 2) {
3515 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3516 "for persistent P2P group",
3517 id);
3518 return -1;
3519 }
3520
3521 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
3522}
3523
3524
3525static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
3526{
3527 int freq = 0;
3528 char *pos;
3529
3530 pos = os_strstr(cmd, "freq=");
3531 if (pos)
3532 freq = atoi(pos + 5);
3533
3534 if (os_strncmp(cmd, "persistent=", 11) == 0)
3535 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
3536 if (os_strcmp(cmd, "persistent") == 0 ||
3537 os_strncmp(cmd, "persistent ", 11) == 0)
3538 return wpas_p2p_group_add(wpa_s, 1, freq);
3539 if (os_strncmp(cmd, "freq=", 5) == 0)
3540 return wpas_p2p_group_add(wpa_s, 0, freq);
3541
3542 wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
3543 cmd);
3544 return -1;
3545}
3546
3547
3548static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
3549 char *buf, size_t buflen)
3550{
3551 u8 addr[ETH_ALEN], *addr_ptr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003552 int next, res;
3553 const struct p2p_peer_info *info;
3554 char *pos, *end;
3555 char devtype[WPS_DEV_TYPE_BUFSIZE];
3556 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557
3558 if (!wpa_s->global->p2p)
3559 return -1;
3560
3561 if (os_strcmp(cmd, "FIRST") == 0) {
3562 addr_ptr = NULL;
3563 next = 0;
3564 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
3565 if (hwaddr_aton(cmd + 5, addr) < 0)
3566 return -1;
3567 addr_ptr = addr;
3568 next = 1;
3569 } else {
3570 if (hwaddr_aton(cmd, addr) < 0)
3571 return -1;
3572 addr_ptr = addr;
3573 next = 0;
3574 }
3575
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003576 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
3577 if (info == NULL)
3578 return -1;
3579
3580 pos = buf;
3581 end = buf + buflen;
3582
3583 res = os_snprintf(pos, end - pos, MACSTR "\n"
3584 "pri_dev_type=%s\n"
3585 "device_name=%s\n"
3586 "manufacturer=%s\n"
3587 "model_name=%s\n"
3588 "model_number=%s\n"
3589 "serial_number=%s\n"
3590 "config_methods=0x%x\n"
3591 "dev_capab=0x%x\n"
3592 "group_capab=0x%x\n"
3593 "level=%d\n",
3594 MAC2STR(info->p2p_device_addr),
3595 wps_dev_type_bin2str(info->pri_dev_type,
3596 devtype, sizeof(devtype)),
3597 info->device_name,
3598 info->manufacturer,
3599 info->model_name,
3600 info->model_number,
3601 info->serial_number,
3602 info->config_methods,
3603 info->dev_capab,
3604 info->group_capab,
3605 info->level);
3606 if (res < 0 || res >= end - pos)
3607 return pos - buf;
3608 pos += res;
3609
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003610 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003611 if (ssid) {
3612 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
3613 if (res < 0 || res >= end - pos)
3614 return pos - buf;
3615 pos += res;
3616 }
3617
3618 res = p2p_get_peer_info_txt(info, pos, end - pos);
3619 if (res < 0)
3620 return pos - buf;
3621 pos += res;
3622
3623 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003624}
3625
3626
Dmitry Shmidt04949592012-07-19 12:16:46 -07003627static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
3628 const char *param)
3629{
3630 struct wpa_freq_range *freq = NULL, *n;
3631 unsigned int count = 0, i;
3632 const char *pos, *pos2, *pos3;
3633
3634 if (wpa_s->global->p2p == NULL)
3635 return -1;
3636
3637 /*
3638 * param includes comma separated frequency range.
3639 * For example: 2412-2432,2462,5000-6000
3640 */
3641 pos = param;
3642 while (pos && pos[0]) {
3643 n = os_realloc(freq,
3644 (count + 1) * sizeof(struct wpa_freq_range));
3645 if (n == NULL) {
3646 os_free(freq);
3647 return -1;
3648 }
3649 freq = n;
3650 freq[count].min = atoi(pos);
3651 pos2 = os_strchr(pos, '-');
3652 pos3 = os_strchr(pos, ',');
3653 if (pos2 && (!pos3 || pos2 < pos3)) {
3654 pos2++;
3655 freq[count].max = atoi(pos2);
3656 } else
3657 freq[count].max = freq[count].min;
3658 pos = pos3;
3659 if (pos)
3660 pos++;
3661 count++;
3662 }
3663
3664 for (i = 0; i < count; i++) {
3665 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
3666 freq[i].min, freq[i].max);
3667 }
3668
3669 os_free(wpa_s->global->p2p_disallow_freq);
3670 wpa_s->global->p2p_disallow_freq = freq;
3671 wpa_s->global->num_p2p_disallow_freq = count;
3672 wpas_p2p_update_channel_list(wpa_s);
3673 return 0;
3674}
3675
3676
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003677static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
3678{
3679 char *param;
3680
3681 if (wpa_s->global->p2p == NULL)
3682 return -1;
3683
3684 param = os_strchr(cmd, ' ');
3685 if (param == NULL)
3686 return -1;
3687 *param++ = '\0';
3688
3689 if (os_strcmp(cmd, "discoverability") == 0) {
3690 p2p_set_client_discoverability(wpa_s->global->p2p,
3691 atoi(param));
3692 return 0;
3693 }
3694
3695 if (os_strcmp(cmd, "managed") == 0) {
3696 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
3697 return 0;
3698 }
3699
3700 if (os_strcmp(cmd, "listen_channel") == 0) {
3701 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
3702 atoi(param));
3703 }
3704
3705 if (os_strcmp(cmd, "ssid_postfix") == 0) {
3706 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
3707 os_strlen(param));
3708 }
3709
3710 if (os_strcmp(cmd, "noa") == 0) {
3711 char *pos;
3712 int count, start, duration;
3713 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
3714 count = atoi(param);
3715 pos = os_strchr(param, ',');
3716 if (pos == NULL)
3717 return -1;
3718 pos++;
3719 start = atoi(pos);
3720 pos = os_strchr(pos, ',');
3721 if (pos == NULL)
3722 return -1;
3723 pos++;
3724 duration = atoi(pos);
3725 if (count < 0 || count > 255 || start < 0 || duration < 0)
3726 return -1;
3727 if (count == 0 && duration > 0)
3728 return -1;
3729 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
3730 "start=%d duration=%d", count, start, duration);
3731 return wpas_p2p_set_noa(wpa_s, count, start, duration);
3732 }
3733
3734 if (os_strcmp(cmd, "ps") == 0)
3735 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
3736
3737 if (os_strcmp(cmd, "oppps") == 0)
3738 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
3739
3740 if (os_strcmp(cmd, "ctwindow") == 0)
3741 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
3742
3743 if (os_strcmp(cmd, "disabled") == 0) {
3744 wpa_s->global->p2p_disabled = atoi(param);
3745 wpa_printf(MSG_DEBUG, "P2P functionality %s",
3746 wpa_s->global->p2p_disabled ?
3747 "disabled" : "enabled");
3748 if (wpa_s->global->p2p_disabled) {
3749 wpas_p2p_stop_find(wpa_s);
3750 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
3751 p2p_flush(wpa_s->global->p2p);
3752 }
3753 return 0;
3754 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003755
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003756 if (os_strcmp(cmd, "conc_pref") == 0) {
3757 if (os_strcmp(param, "sta") == 0)
3758 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
3759 else if (os_strcmp(param, "p2p") == 0)
3760 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003761 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003762 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003763 return -1;
3764 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003765 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07003766 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003767 return 0;
3768 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003769
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003770 if (os_strcmp(cmd, "force_long_sd") == 0) {
3771 wpa_s->force_long_sd = atoi(param);
3772 return 0;
3773 }
3774
3775 if (os_strcmp(cmd, "peer_filter") == 0) {
3776 u8 addr[ETH_ALEN];
3777 if (hwaddr_aton(param, addr))
3778 return -1;
3779 p2p_set_peer_filter(wpa_s->global->p2p, addr);
3780 return 0;
3781 }
3782
3783 if (os_strcmp(cmd, "cross_connect") == 0)
3784 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
3785
3786 if (os_strcmp(cmd, "go_apsd") == 0) {
3787 if (os_strcmp(param, "disable") == 0)
3788 wpa_s->set_ap_uapsd = 0;
3789 else {
3790 wpa_s->set_ap_uapsd = 1;
3791 wpa_s->ap_uapsd = atoi(param);
3792 }
3793 return 0;
3794 }
3795
3796 if (os_strcmp(cmd, "client_apsd") == 0) {
3797 if (os_strcmp(param, "disable") == 0)
3798 wpa_s->set_sta_uapsd = 0;
3799 else {
3800 int be, bk, vi, vo;
3801 char *pos;
3802 /* format: BE,BK,VI,VO;max SP Length */
3803 be = atoi(param);
3804 pos = os_strchr(param, ',');
3805 if (pos == NULL)
3806 return -1;
3807 pos++;
3808 bk = atoi(pos);
3809 pos = os_strchr(pos, ',');
3810 if (pos == NULL)
3811 return -1;
3812 pos++;
3813 vi = atoi(pos);
3814 pos = os_strchr(pos, ',');
3815 if (pos == NULL)
3816 return -1;
3817 pos++;
3818 vo = atoi(pos);
3819 /* ignore max SP Length for now */
3820
3821 wpa_s->set_sta_uapsd = 1;
3822 wpa_s->sta_uapsd = 0;
3823 if (be)
3824 wpa_s->sta_uapsd |= BIT(0);
3825 if (bk)
3826 wpa_s->sta_uapsd |= BIT(1);
3827 if (vi)
3828 wpa_s->sta_uapsd |= BIT(2);
3829 if (vo)
3830 wpa_s->sta_uapsd |= BIT(3);
3831 }
3832 return 0;
3833 }
3834
Dmitry Shmidt04949592012-07-19 12:16:46 -07003835 if (os_strcmp(cmd, "disallow_freq") == 0)
3836 return p2p_ctrl_disallow_freq(wpa_s, param);
3837
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003838 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
3839 cmd);
3840
3841 return -1;
3842}
3843
3844
3845static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
3846{
3847 char *pos, *pos2;
3848 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
3849
3850 if (cmd[0]) {
3851 pos = os_strchr(cmd, ' ');
3852 if (pos == NULL)
3853 return -1;
3854 *pos++ = '\0';
3855 dur1 = atoi(cmd);
3856
3857 pos2 = os_strchr(pos, ' ');
3858 if (pos2)
3859 *pos2++ = '\0';
3860 int1 = atoi(pos);
3861 } else
3862 pos2 = NULL;
3863
3864 if (pos2) {
3865 pos = os_strchr(pos2, ' ');
3866 if (pos == NULL)
3867 return -1;
3868 *pos++ = '\0';
3869 dur2 = atoi(pos2);
3870 int2 = atoi(pos);
3871 }
3872
3873 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
3874}
3875
3876
3877static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
3878{
3879 char *pos;
3880 unsigned int period = 0, interval = 0;
3881
3882 if (cmd[0]) {
3883 pos = os_strchr(cmd, ' ');
3884 if (pos == NULL)
3885 return -1;
3886 *pos++ = '\0';
3887 period = atoi(cmd);
3888 interval = atoi(pos);
3889 }
3890
3891 return wpas_p2p_ext_listen(wpa_s, period, interval);
3892}
3893
3894#endif /* CONFIG_P2P */
3895
3896
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003897#ifdef CONFIG_INTERWORKING
3898static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
3899{
3900 u8 bssid[ETH_ALEN];
3901 struct wpa_bss *bss;
3902
3903 if (hwaddr_aton(dst, bssid)) {
3904 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
3905 return -1;
3906 }
3907
3908 bss = wpa_bss_get_bssid(wpa_s, bssid);
3909 if (bss == NULL) {
3910 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
3911 MAC2STR(bssid));
3912 return -1;
3913 }
3914
3915 return interworking_connect(wpa_s, bss);
3916}
3917
3918
3919static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
3920{
3921 u8 dst_addr[ETH_ALEN];
3922 int used;
3923 char *pos;
3924#define MAX_ANQP_INFO_ID 100
3925 u16 id[MAX_ANQP_INFO_ID];
3926 size_t num_id = 0;
3927
3928 used = hwaddr_aton2(dst, dst_addr);
3929 if (used < 0)
3930 return -1;
3931 pos = dst + used;
3932 while (num_id < MAX_ANQP_INFO_ID) {
3933 id[num_id] = atoi(pos);
3934 if (id[num_id])
3935 num_id++;
3936 pos = os_strchr(pos + 1, ',');
3937 if (pos == NULL)
3938 break;
3939 pos++;
3940 }
3941
3942 if (num_id == 0)
3943 return -1;
3944
3945 return anqp_send_req(wpa_s, dst_addr, id, num_id);
3946}
3947#endif /* CONFIG_INTERWORKING */
3948
3949
Dmitry Shmidt04949592012-07-19 12:16:46 -07003950#ifdef CONFIG_HS20
3951
3952static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
3953{
3954 u8 dst_addr[ETH_ALEN];
3955 int used;
3956 char *pos;
3957 u32 subtypes = 0;
3958
3959 used = hwaddr_aton2(dst, dst_addr);
3960 if (used < 0)
3961 return -1;
3962 pos = dst + used;
3963 for (;;) {
3964 int num = atoi(pos);
3965 if (num <= 0 || num > 31)
3966 return -1;
3967 subtypes |= BIT(num);
3968 pos = os_strchr(pos + 1, ',');
3969 if (pos == NULL)
3970 break;
3971 pos++;
3972 }
3973
3974 if (subtypes == 0)
3975 return -1;
3976
3977 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
3978}
3979
3980
3981static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
3982 const u8 *addr, const char *realm)
3983{
3984 u8 *buf;
3985 size_t rlen, len;
3986 int ret;
3987
3988 rlen = os_strlen(realm);
3989 len = 3 + rlen;
3990 buf = os_malloc(len);
3991 if (buf == NULL)
3992 return -1;
3993 buf[0] = 1; /* NAI Home Realm Count */
3994 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
3995 buf[2] = rlen;
3996 os_memcpy(buf + 3, realm, rlen);
3997
3998 ret = hs20_anqp_send_req(wpa_s, addr,
3999 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4000 buf, len);
4001
4002 os_free(buf);
4003
4004 return ret;
4005}
4006
4007
4008static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4009 char *dst)
4010{
4011 struct wpa_cred *cred = wpa_s->conf->cred;
4012 u8 dst_addr[ETH_ALEN];
4013 int used;
4014 u8 *buf;
4015 size_t len;
4016 int ret;
4017
4018 used = hwaddr_aton2(dst, dst_addr);
4019 if (used < 0)
4020 return -1;
4021
4022 while (dst[used] == ' ')
4023 used++;
4024 if (os_strncmp(dst + used, "realm=", 6) == 0)
4025 return hs20_nai_home_realm_list(wpa_s, dst_addr,
4026 dst + used + 6);
4027
4028 len = os_strlen(dst + used);
4029
4030 if (len == 0 && cred && cred->realm)
4031 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
4032
4033 if (len % 1)
4034 return -1;
4035 len /= 2;
4036 buf = os_malloc(len);
4037 if (buf == NULL)
4038 return -1;
4039 if (hexstr2bin(dst + used, buf, len) < 0) {
4040 os_free(buf);
4041 return -1;
4042 }
4043
4044 ret = hs20_anqp_send_req(wpa_s, dst_addr,
4045 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4046 buf, len);
4047 os_free(buf);
4048
4049 return ret;
4050}
4051
4052#endif /* CONFIG_HS20 */
4053
4054
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004055static int wpa_supplicant_ctrl_iface_sta_autoconnect(
4056 struct wpa_supplicant *wpa_s, char *cmd)
4057{
4058 wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
4059 return 0;
4060}
4061
4062
Dmitry Shmidt04949592012-07-19 12:16:46 -07004063#ifdef CONFIG_AUTOSCAN
4064
4065static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
4066 char *cmd)
4067{
4068 enum wpa_states state = wpa_s->wpa_state;
4069 char *new_params = NULL;
4070
4071 if (os_strlen(cmd) > 0) {
4072 new_params = os_strdup(cmd);
4073 if (new_params == NULL)
4074 return -1;
4075 }
4076
4077 os_free(wpa_s->conf->autoscan);
4078 wpa_s->conf->autoscan = new_params;
4079
4080 if (wpa_s->conf->autoscan == NULL)
4081 autoscan_deinit(wpa_s);
4082 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
4083 autoscan_init(wpa_s, 1);
4084 else if (state == WPA_SCANNING)
4085 wpa_supplicant_reinit_autoscan(wpa_s);
4086
4087 return 0;
4088}
4089
4090#endif /* CONFIG_AUTOSCAN */
4091
4092
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004093static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
4094 size_t buflen)
4095{
4096 struct wpa_signal_info si;
4097 int ret;
4098
4099 ret = wpa_drv_signal_poll(wpa_s, &si);
4100 if (ret)
4101 return -1;
4102
4103 ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
4104 "NOISE=%d\nFREQUENCY=%u\n",
4105 si.current_signal, si.current_txrate / 1000,
4106 si.current_noise, si.frequency);
4107 if (ret < 0 || (unsigned int) ret > buflen)
4108 return -1;
4109 return ret;
4110}
4111
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004112static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
4113 size_t buflen)
4114{
4115 struct hostap_sta_driver_data sta;
4116 int ret;
4117
4118 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
4119 if (ret)
4120 return -1;
4121
4122 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
4123 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
4124 if (ret < 0 || (unsigned int) ret > buflen)
4125 return -1;
4126 return ret;
4127}
4128
4129
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004130#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004131static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
4132 char *buf, size_t buflen)
4133{
4134 int ret;
4135
4136 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
4137 if (ret == 0)
4138 ret = sprintf(buf, "%s\n", "OK");
4139 return ret;
4140}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004141#endif
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004142
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004143char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
4144 char *buf, size_t *resp_len)
4145{
4146 char *reply;
4147 const int reply_size = 4096;
4148 int ctrl_rsp = 0;
4149 int reply_len;
4150
4151 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
4152 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
4153 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
4154 (const u8 *) buf, os_strlen(buf));
4155 } else {
4156 int level = MSG_DEBUG;
4157 if (os_strcmp(buf, "PING") == 0)
4158 level = MSG_EXCESSIVE;
4159 wpa_hexdump_ascii(level, "RX ctrl_iface",
4160 (const u8 *) buf, os_strlen(buf));
4161 }
4162
4163 reply = os_malloc(reply_size);
4164 if (reply == NULL) {
4165 *resp_len = 1;
4166 return NULL;
4167 }
4168
4169 os_memcpy(reply, "OK\n", 3);
4170 reply_len = 3;
4171
4172 if (os_strcmp(buf, "PING") == 0) {
4173 os_memcpy(reply, "PONG\n", 5);
4174 reply_len = 5;
4175 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
4176 if (wpa_debug_reopen_file() < 0)
4177 reply_len = -1;
4178 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
4179 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
4180 } else if (os_strcmp(buf, "MIB") == 0) {
4181 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
4182 if (reply_len >= 0) {
4183 int res;
4184 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
4185 reply_size - reply_len);
4186 if (res < 0)
4187 reply_len = -1;
4188 else
4189 reply_len += res;
4190 }
4191 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
4192 reply_len = wpa_supplicant_ctrl_iface_status(
4193 wpa_s, buf + 6, reply, reply_size);
4194 } else if (os_strcmp(buf, "PMKSA") == 0) {
4195 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
4196 reply_size);
4197 } else if (os_strncmp(buf, "SET ", 4) == 0) {
4198 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
4199 reply_len = -1;
4200 } else if (os_strncmp(buf, "GET ", 4) == 0) {
4201 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
4202 reply, reply_size);
4203 } else if (os_strcmp(buf, "LOGON") == 0) {
4204 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
4205 } else if (os_strcmp(buf, "LOGOFF") == 0) {
4206 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
4207 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004208 wpa_s->normal_scans = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004209 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004210 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4211 reply_len = -1;
4212 else {
4213 wpa_s->disconnected = 0;
4214 wpa_s->reassociate = 1;
4215 wpa_supplicant_req_scan(wpa_s, 0, 0);
4216 }
4217 } else if (os_strcmp(buf, "RECONNECT") == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004218 wpa_s->normal_scans = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004219 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004220 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4221 reply_len = -1;
4222 else if (wpa_s->disconnected) {
4223 wpa_s->disconnected = 0;
4224 wpa_s->reassociate = 1;
4225 wpa_supplicant_req_scan(wpa_s, 0, 0);
4226 }
4227#ifdef IEEE8021X_EAPOL
4228 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
4229 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
4230 reply_len = -1;
4231#endif /* IEEE8021X_EAPOL */
4232#ifdef CONFIG_PEERKEY
4233 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
4234 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
4235 reply_len = -1;
4236#endif /* CONFIG_PEERKEY */
4237#ifdef CONFIG_IEEE80211R
4238 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
4239 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
4240 reply_len = -1;
4241#endif /* CONFIG_IEEE80211R */
4242#ifdef CONFIG_WPS
4243 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
4244 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
4245 if (res == -2) {
4246 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4247 reply_len = 17;
4248 } else if (res)
4249 reply_len = -1;
4250 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
4251 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
4252 if (res == -2) {
4253 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4254 reply_len = 17;
4255 } else if (res)
4256 reply_len = -1;
4257 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
4258 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
4259 reply,
4260 reply_size);
4261 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4262 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
4263 wpa_s, buf + 14, reply, reply_size);
4264 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4265 if (wpas_wps_cancel(wpa_s))
4266 reply_len = -1;
4267#ifdef CONFIG_WPS_OOB
4268 } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
4269 if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
4270 reply_len = -1;
4271#endif /* CONFIG_WPS_OOB */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004272#ifdef CONFIG_WPS_NFC
4273 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
4274 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
4275 reply_len = -1;
4276 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
4277 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
4278 reply_len = -1;
4279 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4280 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
4281 wpa_s, buf + 14, reply, reply_size);
4282 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4283 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
4284 buf + 17))
4285 reply_len = -1;
4286#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004287 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
4288 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
4289 reply_len = -1;
4290#ifdef CONFIG_AP
4291 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4292 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
4293 wpa_s, buf + 11, reply, reply_size);
4294#endif /* CONFIG_AP */
4295#ifdef CONFIG_WPS_ER
4296 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
4297 if (wpas_wps_er_start(wpa_s, NULL))
4298 reply_len = -1;
4299 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
4300 if (wpas_wps_er_start(wpa_s, buf + 13))
4301 reply_len = -1;
4302 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
4303 if (wpas_wps_er_stop(wpa_s))
4304 reply_len = -1;
4305 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
4306 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
4307 reply_len = -1;
4308 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
4309 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
4310 if (ret == -2) {
4311 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4312 reply_len = 17;
4313 } else if (ret == -3) {
4314 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
4315 reply_len = 18;
4316 } else if (ret == -4) {
4317 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
4318 reply_len = 20;
4319 } else if (ret)
4320 reply_len = -1;
4321 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
4322 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
4323 reply_len = -1;
4324 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
4325 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
4326 buf + 18))
4327 reply_len = -1;
4328 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
4329 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
4330 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004331#ifdef CONFIG_WPS_NFC
4332 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
4333 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
4334 wpa_s, buf + 24, reply, reply_size);
4335#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004336#endif /* CONFIG_WPS_ER */
4337#endif /* CONFIG_WPS */
4338#ifdef CONFIG_IBSS_RSN
4339 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
4340 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
4341 reply_len = -1;
4342#endif /* CONFIG_IBSS_RSN */
4343#ifdef CONFIG_P2P
4344 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
4345 if (p2p_ctrl_find(wpa_s, buf + 9))
4346 reply_len = -1;
4347 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
4348 if (p2p_ctrl_find(wpa_s, ""))
4349 reply_len = -1;
4350 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
4351 wpas_p2p_stop_find(wpa_s);
4352 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
4353 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
4354 reply_size);
4355 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
4356 if (p2p_ctrl_listen(wpa_s, buf + 11))
4357 reply_len = -1;
4358 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
4359 if (p2p_ctrl_listen(wpa_s, ""))
4360 reply_len = -1;
4361 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
4362 if (wpas_p2p_group_remove(wpa_s, buf + 17))
4363 reply_len = -1;
4364 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
4365 if (wpas_p2p_group_add(wpa_s, 0, 0))
4366 reply_len = -1;
4367 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
4368 if (p2p_ctrl_group_add(wpa_s, buf + 14))
4369 reply_len = -1;
4370 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
4371 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
4372 reply_len = -1;
4373 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
4374 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
4375 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
4376 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
4377 reply_size);
4378 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
4379 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
4380 reply_len = -1;
4381 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
4382 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
4383 reply_len = -1;
4384 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07004385#ifdef ANDROID_P2P
4386 wpas_p2p_sd_service_update(wpa_s, SRV_UPDATE);
4387#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004388 wpas_p2p_sd_service_update(wpa_s);
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07004389#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004390 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
4391 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
4392 reply_len = -1;
4393 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
4394 wpas_p2p_service_flush(wpa_s);
4395 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
4396 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
4397 reply_len = -1;
4398 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
4399 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
4400 reply_len = -1;
4401 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
4402 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
4403 reply_len = -1;
4404 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
4405 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
4406 reply_len = -1;
4407 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
4408 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
4409 reply_size);
4410 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
4411 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
4412 reply_len = -1;
4413 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
4414 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
4415 wpa_s->force_long_sd = 0;
4416 if (wpa_s->global->p2p)
4417 p2p_flush(wpa_s->global->p2p);
4418 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
4419 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
4420 reply_len = -1;
4421 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
4422 if (wpas_p2p_cancel(wpa_s))
4423 reply_len = -1;
4424 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
4425 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
4426 reply_len = -1;
4427 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
4428 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
4429 reply_len = -1;
4430 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
4431 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
4432 reply_len = -1;
4433 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
4434 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
4435 reply_len = -1;
4436#endif /* CONFIG_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004437#ifdef CONFIG_INTERWORKING
4438 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
4439 if (interworking_fetch_anqp(wpa_s) < 0)
4440 reply_len = -1;
4441 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
4442 interworking_stop_fetch_anqp(wpa_s);
4443 } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
4444 if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
4445 NULL) < 0)
4446 reply_len = -1;
4447 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
4448 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
4449 reply_len = -1;
4450 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
4451 if (get_anqp(wpa_s, buf + 9) < 0)
4452 reply_len = -1;
4453#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004454#ifdef CONFIG_HS20
4455 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
4456 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
4457 reply_len = -1;
4458 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
4459 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
4460 reply_len = -1;
4461#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004462 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
4463 {
4464 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
4465 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
4466 reply_len = -1;
4467 else
4468 ctrl_rsp = 1;
4469 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
4470 if (wpa_supplicant_reload_configuration(wpa_s))
4471 reply_len = -1;
4472 } else if (os_strcmp(buf, "TERMINATE") == 0) {
4473 wpa_supplicant_terminate_proc(wpa_s->global);
4474 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
4475 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
4476 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -07004477 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004478 reply_len = wpa_supplicant_ctrl_iface_blacklist(
4479 wpa_s, buf + 9, reply, reply_size);
4480 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
4481 reply_len = wpa_supplicant_ctrl_iface_log_level(
4482 wpa_s, buf + 9, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004483 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
4484 reply_len = wpa_supplicant_ctrl_iface_list_networks(
4485 wpa_s, reply, reply_size);
4486 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004487#ifdef CONFIG_SME
4488 wpa_s->sme.prev_bssid_set = 0;
4489#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004490 wpa_s->reassociate = 0;
4491 wpa_s->disconnected = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004492 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004493 wpa_supplicant_cancel_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004494 wpa_supplicant_deauthenticate(wpa_s,
4495 WLAN_REASON_DEAUTH_LEAVING);
4496 } else if (os_strcmp(buf, "SCAN") == 0) {
4497 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4498 reply_len = -1;
4499 else {
4500 if (!wpa_s->scanning &&
4501 ((wpa_s->wpa_state <= WPA_SCANNING) ||
4502 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004503 wpa_s->normal_scans = 0;
4504 wpa_s->scan_req = 2;
4505 wpa_supplicant_req_scan(wpa_s, 0, 0);
4506 } else if (wpa_s->sched_scanning) {
4507 wpa_printf(MSG_DEBUG, "Stop ongoing "
4508 "sched_scan to allow requested "
4509 "full scan to proceed");
4510 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004511 wpa_s->scan_req = 2;
4512 wpa_supplicant_req_scan(wpa_s, 0, 0);
4513 } else {
4514 wpa_printf(MSG_DEBUG, "Ongoing scan action - "
4515 "reject new request");
4516 reply_len = os_snprintf(reply, reply_size,
4517 "FAIL-BUSY\n");
4518 }
4519 }
4520 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
4521 reply_len = wpa_supplicant_ctrl_iface_scan_results(
4522 wpa_s, reply, reply_size);
4523 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
4524 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
4525 reply_len = -1;
4526 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
4527 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
4528 reply_len = -1;
4529 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
4530 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
4531 reply_len = -1;
4532 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
4533 reply_len = wpa_supplicant_ctrl_iface_add_network(
4534 wpa_s, reply, reply_size);
4535 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
4536 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
4537 reply_len = -1;
4538 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
4539 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
4540 reply_len = -1;
4541 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
4542 reply_len = wpa_supplicant_ctrl_iface_get_network(
4543 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004544 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
4545 reply_len = wpa_supplicant_ctrl_iface_list_creds(
4546 wpa_s, reply, reply_size);
4547 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
4548 reply_len = wpa_supplicant_ctrl_iface_add_cred(
4549 wpa_s, reply, reply_size);
4550 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
4551 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
4552 reply_len = -1;
4553 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
4554 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
4555 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004556#ifndef CONFIG_NO_CONFIG_WRITE
4557 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
4558 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
4559 reply_len = -1;
4560#endif /* CONFIG_NO_CONFIG_WRITE */
4561 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
4562 reply_len = wpa_supplicant_ctrl_iface_get_capability(
4563 wpa_s, buf + 15, reply, reply_size);
4564 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
4565 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
4566 reply_len = -1;
4567 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
4568 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
4569 reply_len = -1;
4570 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
4571 reply_len = wpa_supplicant_global_iface_list(
4572 wpa_s->global, reply, reply_size);
4573 } else if (os_strcmp(buf, "INTERFACES") == 0) {
4574 reply_len = wpa_supplicant_global_iface_interfaces(
4575 wpa_s->global, reply, reply_size);
4576 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
4577 reply_len = wpa_supplicant_ctrl_iface_bss(
4578 wpa_s, buf + 4, reply, reply_size);
4579#ifdef CONFIG_AP
4580 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
4581 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
4582 } else if (os_strncmp(buf, "STA ", 4) == 0) {
4583 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
4584 reply_size);
4585 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
4586 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
4587 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004588 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
4589 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
4590 reply_len = -1;
4591 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
4592 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
4593 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004594#endif /* CONFIG_AP */
4595 } else if (os_strcmp(buf, "SUSPEND") == 0) {
4596 wpas_notify_suspend(wpa_s->global);
4597 } else if (os_strcmp(buf, "RESUME") == 0) {
4598 wpas_notify_resume(wpa_s->global);
4599 } else if (os_strcmp(buf, "DROP_SA") == 0) {
4600 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
4601 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
4602 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
4603 reply_len = -1;
4604 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
4605 if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
4606 reply_len = -1;
4607 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
4608 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
4609 reply_len = -1;
4610 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
4611 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
4612 buf + 17))
4613 reply_len = -1;
4614#ifdef CONFIG_TDLS
4615 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
4616 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
4617 reply_len = -1;
4618 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
4619 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
4620 reply_len = -1;
4621 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
4622 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
4623 reply_len = -1;
4624#endif /* CONFIG_TDLS */
4625 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
4626 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
4627 reply_size);
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004628 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
4629 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
4630 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004631#ifdef CONFIG_AUTOSCAN
4632 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
4633 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
4634 reply_len = -1;
4635#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004636#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004637 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
4638 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
4639 reply_size);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004640#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004641 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
4642 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004643 } else {
4644 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
4645 reply_len = 16;
4646 }
4647
4648 if (reply_len < 0) {
4649 os_memcpy(reply, "FAIL\n", 5);
4650 reply_len = 5;
4651 }
4652
4653 if (ctrl_rsp)
4654 eapol_sm_notify_ctrl_response(wpa_s->eapol);
4655
4656 *resp_len = reply_len;
4657 return reply;
4658}
4659
4660
4661static int wpa_supplicant_global_iface_add(struct wpa_global *global,
4662 char *cmd)
4663{
4664 struct wpa_interface iface;
4665 char *pos;
4666
4667 /*
4668 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
4669 * TAB<bridge_ifname>
4670 */
4671 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
4672
4673 os_memset(&iface, 0, sizeof(iface));
4674
4675 do {
4676 iface.ifname = pos = cmd;
4677 pos = os_strchr(pos, '\t');
4678 if (pos)
4679 *pos++ = '\0';
4680 if (iface.ifname[0] == '\0')
4681 return -1;
4682 if (pos == NULL)
4683 break;
4684
4685 iface.confname = pos;
4686 pos = os_strchr(pos, '\t');
4687 if (pos)
4688 *pos++ = '\0';
4689 if (iface.confname[0] == '\0')
4690 iface.confname = NULL;
4691 if (pos == NULL)
4692 break;
4693
4694 iface.driver = pos;
4695 pos = os_strchr(pos, '\t');
4696 if (pos)
4697 *pos++ = '\0';
4698 if (iface.driver[0] == '\0')
4699 iface.driver = NULL;
4700 if (pos == NULL)
4701 break;
4702
4703 iface.ctrl_interface = pos;
4704 pos = os_strchr(pos, '\t');
4705 if (pos)
4706 *pos++ = '\0';
4707 if (iface.ctrl_interface[0] == '\0')
4708 iface.ctrl_interface = NULL;
4709 if (pos == NULL)
4710 break;
4711
4712 iface.driver_param = pos;
4713 pos = os_strchr(pos, '\t');
4714 if (pos)
4715 *pos++ = '\0';
4716 if (iface.driver_param[0] == '\0')
4717 iface.driver_param = NULL;
4718 if (pos == NULL)
4719 break;
4720
4721 iface.bridge_ifname = pos;
4722 pos = os_strchr(pos, '\t');
4723 if (pos)
4724 *pos++ = '\0';
4725 if (iface.bridge_ifname[0] == '\0')
4726 iface.bridge_ifname = NULL;
4727 if (pos == NULL)
4728 break;
4729 } while (0);
4730
4731 if (wpa_supplicant_get_iface(global, iface.ifname))
4732 return -1;
4733
4734 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
4735}
4736
4737
4738static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
4739 char *cmd)
4740{
4741 struct wpa_supplicant *wpa_s;
4742
4743 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
4744
4745 wpa_s = wpa_supplicant_get_iface(global, cmd);
4746 if (wpa_s == NULL)
4747 return -1;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07004748 return wpa_supplicant_remove_iface(global, wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004749}
4750
4751
4752static void wpa_free_iface_info(struct wpa_interface_info *iface)
4753{
4754 struct wpa_interface_info *prev;
4755
4756 while (iface) {
4757 prev = iface;
4758 iface = iface->next;
4759
4760 os_free(prev->ifname);
4761 os_free(prev->desc);
4762 os_free(prev);
4763 }
4764}
4765
4766
4767static int wpa_supplicant_global_iface_list(struct wpa_global *global,
4768 char *buf, int len)
4769{
4770 int i, res;
4771 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
4772 char *pos, *end;
4773
4774 for (i = 0; wpa_drivers[i]; i++) {
4775 struct wpa_driver_ops *drv = wpa_drivers[i];
4776 if (drv->get_interfaces == NULL)
4777 continue;
4778 tmp = drv->get_interfaces(global->drv_priv[i]);
4779 if (tmp == NULL)
4780 continue;
4781
4782 if (last == NULL)
4783 iface = last = tmp;
4784 else
4785 last->next = tmp;
4786 while (last->next)
4787 last = last->next;
4788 }
4789
4790 pos = buf;
4791 end = buf + len;
4792 for (tmp = iface; tmp; tmp = tmp->next) {
4793 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
4794 tmp->drv_name, tmp->ifname,
4795 tmp->desc ? tmp->desc : "");
4796 if (res < 0 || res >= end - pos) {
4797 *pos = '\0';
4798 break;
4799 }
4800 pos += res;
4801 }
4802
4803 wpa_free_iface_info(iface);
4804
4805 return pos - buf;
4806}
4807
4808
4809static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
4810 char *buf, int len)
4811{
4812 int res;
4813 char *pos, *end;
4814 struct wpa_supplicant *wpa_s;
4815
4816 wpa_s = global->ifaces;
4817 pos = buf;
4818 end = buf + len;
4819
4820 while (wpa_s) {
4821 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
4822 if (res < 0 || res >= end - pos) {
4823 *pos = '\0';
4824 break;
4825 }
4826 pos += res;
4827 wpa_s = wpa_s->next;
4828 }
4829 return pos - buf;
4830}
4831
4832
4833char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
4834 char *buf, size_t *resp_len)
4835{
4836 char *reply;
4837 const int reply_size = 2048;
4838 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004839 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004840
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004841 if (os_strcmp(buf, "PING") == 0)
4842 level = MSG_EXCESSIVE;
4843 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004844 (const u8 *) buf, os_strlen(buf));
4845
4846 reply = os_malloc(reply_size);
4847 if (reply == NULL) {
4848 *resp_len = 1;
4849 return NULL;
4850 }
4851
4852 os_memcpy(reply, "OK\n", 3);
4853 reply_len = 3;
4854
4855 if (os_strcmp(buf, "PING") == 0) {
4856 os_memcpy(reply, "PONG\n", 5);
4857 reply_len = 5;
4858 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
4859 if (wpa_supplicant_global_iface_add(global, buf + 14))
4860 reply_len = -1;
4861 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
4862 if (wpa_supplicant_global_iface_remove(global, buf + 17))
4863 reply_len = -1;
4864 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
4865 reply_len = wpa_supplicant_global_iface_list(
4866 global, reply, reply_size);
4867 } else if (os_strcmp(buf, "INTERFACES") == 0) {
4868 reply_len = wpa_supplicant_global_iface_interfaces(
4869 global, reply, reply_size);
4870 } else if (os_strcmp(buf, "TERMINATE") == 0) {
4871 wpa_supplicant_terminate_proc(global);
4872 } else if (os_strcmp(buf, "SUSPEND") == 0) {
4873 wpas_notify_suspend(global);
4874 } else if (os_strcmp(buf, "RESUME") == 0) {
4875 wpas_notify_resume(global);
4876 } else {
4877 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
4878 reply_len = 16;
4879 }
4880
4881 if (reply_len < 0) {
4882 os_memcpy(reply, "FAIL\n", 5);
4883 reply_len = 5;
4884 }
4885
4886 *resp_len = reply_len;
4887 return reply;
4888}