blob: 849633a9e82c05183c862c1414bd2842ed303490 [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
2744 return pos - buf;
2745}
2746
Dmitry Shmidt04949592012-07-19 12:16:46 -07002747
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002748static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
2749 const char *cmd, char *buf,
2750 size_t buflen)
2751{
2752 u8 bssid[ETH_ALEN];
2753 size_t i;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002754 struct wpa_bss *bss;
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002755 struct wpa_bss *bsslast = NULL;
2756 struct dl_list *next;
2757 int ret = 0;
2758 int len;
2759 char *ctmp;
2760 unsigned long mask = WPA_BSS_MASK_ALL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002761
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002762 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
2763 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
2764 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002765 list_id);
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002766 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
2767 list_id);
2768 } else { /* N1-N2 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002769 unsigned int id1, id2;
2770
2771 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
2772 wpa_printf(MSG_INFO, "Wrong BSS range "
2773 "format");
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002774 return 0;
2775 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002776
2777 id1 = atoi(cmd + 6);
2778 bss = wpa_bss_get_id(wpa_s, id1);
2779 id2 = atoi(ctmp + 1);
2780 if (id2 == 0)
2781 bsslast = dl_list_last(&wpa_s->bss_id,
2782 struct wpa_bss,
2783 list_id);
2784 else {
2785 bsslast = wpa_bss_get_id(wpa_s, id2);
2786 if (bsslast == NULL && bss && id2 > id1) {
2787 struct wpa_bss *tmp = bss;
2788 for (;;) {
2789 next = tmp->list_id.next;
2790 if (next == &wpa_s->bss_id)
2791 break;
2792 tmp = dl_list_entry(
2793 next, struct wpa_bss,
2794 list_id);
2795 if (tmp->id > id2)
2796 break;
2797 bsslast = tmp;
2798 }
2799 }
2800 }
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002801 }
2802 } else if (os_strcmp(cmd, "FIRST") == 0)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002803 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002804 else if (os_strncmp(cmd, "ID-", 3) == 0) {
2805 i = atoi(cmd + 3);
2806 bss = wpa_bss_get_id(wpa_s, i);
2807 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
2808 i = atoi(cmd + 5);
2809 bss = wpa_bss_get_id(wpa_s, i);
2810 if (bss) {
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002811 next = bss->list_id.next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002812 if (next == &wpa_s->bss_id)
2813 bss = NULL;
2814 else
2815 bss = dl_list_entry(next, struct wpa_bss,
2816 list_id);
2817 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002818#ifdef CONFIG_P2P
2819 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
2820 if (hwaddr_aton(cmd + 13, bssid) == 0)
2821 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
2822 else
2823 bss = NULL;
2824#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002825 } else if (hwaddr_aton(cmd, bssid) == 0)
2826 bss = wpa_bss_get_bssid(wpa_s, bssid);
2827 else {
2828 struct wpa_bss *tmp;
2829 i = atoi(cmd);
2830 bss = NULL;
2831 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
2832 {
2833 if (i-- == 0) {
2834 bss = tmp;
2835 break;
2836 }
2837 }
2838 }
2839
Dmitry Shmidt04949592012-07-19 12:16:46 -07002840 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
2841 mask = strtoul(ctmp + 5, NULL, 0x10);
2842 if (mask == 0)
2843 mask = WPA_BSS_MASK_ALL;
2844 }
2845
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002846 if (bss == NULL)
2847 return 0;
2848
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002849 if (bsslast == NULL)
2850 bsslast = bss;
2851 do {
2852 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
2853 ret += len;
2854 buf += len;
2855 buflen -= len;
2856 if (bss == bsslast)
2857 break;
2858 next = bss->list_id.next;
2859 if (next == &wpa_s->bss_id)
2860 break;
2861 bss = dl_list_entry(next, struct wpa_bss, list_id);
2862 } while (bss && len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002863
Dmitry Shmidtf2df2f22012-03-26 12:43:26 -07002864 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002865}
2866
2867
2868static int wpa_supplicant_ctrl_iface_ap_scan(
2869 struct wpa_supplicant *wpa_s, char *cmd)
2870{
2871 int ap_scan = atoi(cmd);
2872 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
2873}
2874
2875
2876static int wpa_supplicant_ctrl_iface_scan_interval(
2877 struct wpa_supplicant *wpa_s, char *cmd)
2878{
2879 int scan_int = atoi(cmd);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002880 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002881}
2882
2883
2884static int wpa_supplicant_ctrl_iface_bss_expire_age(
2885 struct wpa_supplicant *wpa_s, char *cmd)
2886{
2887 int expire_age = atoi(cmd);
2888 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
2889}
2890
2891
2892static int wpa_supplicant_ctrl_iface_bss_expire_count(
2893 struct wpa_supplicant *wpa_s, char *cmd)
2894{
2895 int expire_count = atoi(cmd);
2896 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
2897}
2898
2899
2900static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
2901{
2902 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
2903 /* MLME-DELETEKEYS.request */
2904 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
2905 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
2906 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
2907 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
2908#ifdef CONFIG_IEEE80211W
2909 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
2910 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
2911#endif /* CONFIG_IEEE80211W */
2912
2913 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
2914 0);
2915 /* MLME-SETPROTECTION.request(None) */
2916 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
2917 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
2918 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
2919 wpa_sm_drop_sa(wpa_s->wpa);
2920}
2921
2922
2923static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
2924 char *addr)
2925{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002926#ifdef CONFIG_NO_SCAN_PROCESSING
2927 return -1;
2928#else /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002929 u8 bssid[ETH_ALEN];
2930 struct wpa_bss *bss;
2931 struct wpa_ssid *ssid = wpa_s->current_ssid;
2932
2933 if (hwaddr_aton(addr, bssid)) {
2934 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
2935 "address '%s'", addr);
2936 return -1;
2937 }
2938
2939 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
2940
2941 bss = wpa_bss_get_bssid(wpa_s, bssid);
2942 if (!bss) {
2943 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
2944 "from BSS table");
2945 return -1;
2946 }
2947
2948 /*
2949 * TODO: Find best network configuration block from configuration to
2950 * allow roaming to other networks
2951 */
2952
2953 if (!ssid) {
2954 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
2955 "configuration known for the target AP");
2956 return -1;
2957 }
2958
2959 wpa_s->reassociate = 1;
2960 wpa_supplicant_connect(wpa_s, bss, ssid);
2961
2962 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002963#endif /* CONFIG_NO_SCAN_PROCESSING */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002964}
2965
2966
2967#ifdef CONFIG_P2P
2968static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
2969{
2970 unsigned int timeout = atoi(cmd);
2971 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002972 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
2973 char *pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002974
2975 if (os_strstr(cmd, "type=social"))
2976 type = P2P_FIND_ONLY_SOCIAL;
2977 else if (os_strstr(cmd, "type=progressive"))
2978 type = P2P_FIND_PROGRESSIVE;
2979
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002980 pos = os_strstr(cmd, "dev_id=");
2981 if (pos) {
2982 pos += 7;
2983 if (hwaddr_aton(pos, dev_id))
2984 return -1;
2985 _dev_id = dev_id;
2986 }
2987
2988 return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002989}
2990
2991
2992static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
2993 char *buf, size_t buflen)
2994{
2995 u8 addr[ETH_ALEN];
2996 char *pos, *pos2;
2997 char *pin = NULL;
2998 enum p2p_wps_method wps_method;
2999 int new_pin;
3000 int ret;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003001 int persistent_group, persistent_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003002 int join;
3003 int auth;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003004 int automatic;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003005 int go_intent = -1;
3006 int freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003007 int pd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003008
Dmitry Shmidt04949592012-07-19 12:16:46 -07003009 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
3010 * [persistent|persistent=<network id>]
3011 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003012
3013 if (hwaddr_aton(cmd, addr))
3014 return -1;
3015
3016 pos = cmd + 17;
3017 if (*pos != ' ')
3018 return -1;
3019 pos++;
3020
3021 persistent_group = os_strstr(pos, " persistent") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003022 pos2 = os_strstr(pos, " persistent=");
3023 if (pos2) {
3024 struct wpa_ssid *ssid;
3025 persistent_id = atoi(pos2 + 12);
3026 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
3027 if (ssid == NULL || ssid->disabled != 2 ||
3028 ssid->mode != WPAS_MODE_P2P_GO) {
3029 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3030 "SSID id=%d for persistent P2P group (GO)",
3031 persistent_id);
3032 return -1;
3033 }
3034 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003035 join = os_strstr(pos, " join") != NULL;
3036 auth = os_strstr(pos, " auth") != NULL;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003037 automatic = os_strstr(pos, " auto") != NULL;
3038 pd = os_strstr(pos, " provdisc") != NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003039
3040 pos2 = os_strstr(pos, " go_intent=");
3041 if (pos2) {
3042 pos2 += 11;
3043 go_intent = atoi(pos2);
3044 if (go_intent < 0 || go_intent > 15)
3045 return -1;
3046 }
3047
3048 pos2 = os_strstr(pos, " freq=");
3049 if (pos2) {
3050 pos2 += 6;
3051 freq = atoi(pos2);
3052 if (freq <= 0)
3053 return -1;
3054 }
3055
3056 if (os_strncmp(pos, "pin", 3) == 0) {
3057 /* Request random PIN (to be displayed) and enable the PIN */
3058 wps_method = WPS_PIN_DISPLAY;
3059 } else if (os_strncmp(pos, "pbc", 3) == 0) {
3060 wps_method = WPS_PBC;
3061 } else {
3062 pin = pos;
3063 pos = os_strchr(pin, ' ');
3064 wps_method = WPS_PIN_KEYPAD;
3065 if (pos) {
3066 *pos++ = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003067 if (os_strncmp(pos, "display", 7) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003068 wps_method = WPS_PIN_DISPLAY;
3069 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003070 if (!wps_pin_str_valid(pin)) {
3071 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
3072 return 17;
3073 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003074 }
3075
3076 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
Dmitry Shmidt04949592012-07-19 12:16:46 -07003077 persistent_group, automatic, join,
3078 auth, go_intent, freq, persistent_id, pd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003079 if (new_pin == -2) {
3080 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
3081 return 25;
3082 }
3083 if (new_pin == -3) {
3084 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
3085 return 25;
3086 }
3087 if (new_pin < 0)
3088 return -1;
3089 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
3090 ret = os_snprintf(buf, buflen, "%08d", new_pin);
3091 if (ret < 0 || (size_t) ret >= buflen)
3092 return -1;
3093 return ret;
3094 }
3095
3096 os_memcpy(buf, "OK\n", 3);
3097 return 3;
3098}
3099
3100
3101static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
3102{
3103 unsigned int timeout = atoi(cmd);
3104 return wpas_p2p_listen(wpa_s, timeout);
3105}
3106
3107
3108static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
3109{
3110 u8 addr[ETH_ALEN];
3111 char *pos;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003112 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003113
Dmitry Shmidt04949592012-07-19 12:16:46 -07003114 /* <addr> <config method> [join|auto] */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003115
3116 if (hwaddr_aton(cmd, addr))
3117 return -1;
3118
3119 pos = cmd + 17;
3120 if (*pos != ' ')
3121 return -1;
3122 pos++;
3123
Dmitry Shmidt04949592012-07-19 12:16:46 -07003124 if (os_strstr(pos, " join") != NULL)
3125 use = WPAS_P2P_PD_FOR_JOIN;
3126 else if (os_strstr(pos, " auto") != NULL)
3127 use = WPAS_P2P_PD_AUTO;
3128
3129 return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003130}
3131
3132
3133static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
3134 size_t buflen)
3135{
3136 struct wpa_ssid *ssid = wpa_s->current_ssid;
3137
3138 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
3139 ssid->passphrase == NULL)
3140 return -1;
3141
3142 os_strlcpy(buf, ssid->passphrase, buflen);
3143 return os_strlen(buf);
3144}
3145
3146
3147static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
3148 char *buf, size_t buflen)
3149{
3150 u64 ref;
3151 int res;
3152 u8 dst_buf[ETH_ALEN], *dst;
3153 struct wpabuf *tlvs;
3154 char *pos;
3155 size_t len;
3156
3157 if (hwaddr_aton(cmd, dst_buf))
3158 return -1;
3159 dst = dst_buf;
3160 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
3161 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
3162 dst = NULL;
3163 pos = cmd + 17;
3164 if (*pos != ' ')
3165 return -1;
3166 pos++;
3167
3168 if (os_strncmp(pos, "upnp ", 5) == 0) {
3169 u8 version;
3170 pos += 5;
3171 if (hexstr2bin(pos, &version, 1) < 0)
3172 return -1;
3173 pos += 2;
3174 if (*pos != ' ')
3175 return -1;
3176 pos++;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003177 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003178 } else {
3179 len = os_strlen(pos);
3180 if (len & 1)
3181 return -1;
3182 len /= 2;
3183 tlvs = wpabuf_alloc(len);
3184 if (tlvs == NULL)
3185 return -1;
3186 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
3187 wpabuf_free(tlvs);
3188 return -1;
3189 }
3190
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003191 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003192 wpabuf_free(tlvs);
3193 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003194 if (ref == 0)
3195 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003196 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
3197 if (res < 0 || (unsigned) res >= buflen)
3198 return -1;
3199 return res;
3200}
3201
3202
3203static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
3204 char *cmd)
3205{
3206 long long unsigned val;
3207 u64 req;
3208 if (sscanf(cmd, "%llx", &val) != 1)
3209 return -1;
3210 req = val;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003211 return wpas_p2p_sd_cancel_request(wpa_s, req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003212}
3213
3214
3215static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
3216{
3217 int freq;
3218 u8 dst[ETH_ALEN];
3219 u8 dialog_token;
3220 struct wpabuf *resp_tlvs;
3221 char *pos, *pos2;
3222 size_t len;
3223
3224 pos = os_strchr(cmd, ' ');
3225 if (pos == NULL)
3226 return -1;
3227 *pos++ = '\0';
3228 freq = atoi(cmd);
3229 if (freq == 0)
3230 return -1;
3231
3232 if (hwaddr_aton(pos, dst))
3233 return -1;
3234 pos += 17;
3235 if (*pos != ' ')
3236 return -1;
3237 pos++;
3238
3239 pos2 = os_strchr(pos, ' ');
3240 if (pos2 == NULL)
3241 return -1;
3242 *pos2++ = '\0';
3243 dialog_token = atoi(pos);
3244
3245 len = os_strlen(pos2);
3246 if (len & 1)
3247 return -1;
3248 len /= 2;
3249 resp_tlvs = wpabuf_alloc(len);
3250 if (resp_tlvs == NULL)
3251 return -1;
3252 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
3253 wpabuf_free(resp_tlvs);
3254 return -1;
3255 }
3256
3257 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
3258 wpabuf_free(resp_tlvs);
3259 return 0;
3260}
3261
3262
3263static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
3264 char *cmd)
3265{
Dmitry Shmidt04949592012-07-19 12:16:46 -07003266 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
3267 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003268 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
3269 return 0;
3270}
3271
3272
3273static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
3274 char *cmd)
3275{
3276 char *pos;
3277 size_t len;
3278 struct wpabuf *query, *resp;
3279
3280 pos = os_strchr(cmd, ' ');
3281 if (pos == NULL)
3282 return -1;
3283 *pos++ = '\0';
3284
3285 len = os_strlen(cmd);
3286 if (len & 1)
3287 return -1;
3288 len /= 2;
3289 query = wpabuf_alloc(len);
3290 if (query == NULL)
3291 return -1;
3292 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3293 wpabuf_free(query);
3294 return -1;
3295 }
3296
3297 len = os_strlen(pos);
3298 if (len & 1) {
3299 wpabuf_free(query);
3300 return -1;
3301 }
3302 len /= 2;
3303 resp = wpabuf_alloc(len);
3304 if (resp == NULL) {
3305 wpabuf_free(query);
3306 return -1;
3307 }
3308 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
3309 wpabuf_free(query);
3310 wpabuf_free(resp);
3311 return -1;
3312 }
3313
3314 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
3315 wpabuf_free(query);
3316 wpabuf_free(resp);
3317 return -1;
3318 }
3319 return 0;
3320}
3321
3322
3323static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3324{
3325 char *pos;
3326 u8 version;
3327
3328 pos = os_strchr(cmd, ' ');
3329 if (pos == NULL)
3330 return -1;
3331 *pos++ = '\0';
3332
3333 if (hexstr2bin(cmd, &version, 1) < 0)
3334 return -1;
3335
3336 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
3337}
3338
3339
3340static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
3341{
3342 char *pos;
3343
3344 pos = os_strchr(cmd, ' ');
3345 if (pos == NULL)
3346 return -1;
3347 *pos++ = '\0';
3348
3349 if (os_strcmp(cmd, "bonjour") == 0)
3350 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
3351 if (os_strcmp(cmd, "upnp") == 0)
3352 return p2p_ctrl_service_add_upnp(wpa_s, pos);
3353 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3354 return -1;
3355}
3356
3357
3358static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
3359 char *cmd)
3360{
3361 size_t len;
3362 struct wpabuf *query;
3363 int ret;
3364
3365 len = os_strlen(cmd);
3366 if (len & 1)
3367 return -1;
3368 len /= 2;
3369 query = wpabuf_alloc(len);
3370 if (query == NULL)
3371 return -1;
3372 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3373 wpabuf_free(query);
3374 return -1;
3375 }
3376
3377 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
3378 wpabuf_free(query);
3379 return ret;
3380}
3381
3382
3383static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3384{
3385 char *pos;
3386 u8 version;
3387
3388 pos = os_strchr(cmd, ' ');
3389 if (pos == NULL)
3390 return -1;
3391 *pos++ = '\0';
3392
3393 if (hexstr2bin(cmd, &version, 1) < 0)
3394 return -1;
3395
3396 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
3397}
3398
3399
3400static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
3401{
3402 char *pos;
3403
3404 pos = os_strchr(cmd, ' ');
3405 if (pos == NULL)
3406 return -1;
3407 *pos++ = '\0';
3408
3409 if (os_strcmp(cmd, "bonjour") == 0)
3410 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
3411 if (os_strcmp(cmd, "upnp") == 0)
3412 return p2p_ctrl_service_del_upnp(wpa_s, pos);
3413 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3414 return -1;
3415}
3416
3417
3418static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
3419{
3420 u8 addr[ETH_ALEN];
3421
3422 /* <addr> */
3423
3424 if (hwaddr_aton(cmd, addr))
3425 return -1;
3426
3427 return wpas_p2p_reject(wpa_s, addr);
3428}
3429
3430
3431static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
3432{
3433 char *pos;
3434 int id;
3435 struct wpa_ssid *ssid;
3436 u8 peer[ETH_ALEN];
3437
3438 id = atoi(cmd);
3439 pos = os_strstr(cmd, " peer=");
3440 if (pos) {
3441 pos += 6;
3442 if (hwaddr_aton(pos, peer))
3443 return -1;
3444 }
3445 ssid = wpa_config_get_network(wpa_s->conf, id);
3446 if (ssid == NULL || ssid->disabled != 2) {
3447 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3448 "for persistent P2P group",
3449 id);
3450 return -1;
3451 }
3452
3453 return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
3454}
3455
3456
3457static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
3458{
3459 char *pos;
3460 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
3461
3462 pos = os_strstr(cmd, " peer=");
3463 if (!pos)
3464 return -1;
3465
3466 *pos = '\0';
3467 pos += 6;
3468 if (hwaddr_aton(pos, peer)) {
3469 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
3470 return -1;
3471 }
3472
3473 pos = os_strstr(pos, " go_dev_addr=");
3474 if (pos) {
3475 pos += 13;
3476 if (hwaddr_aton(pos, go_dev_addr)) {
3477 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
3478 pos);
3479 return -1;
3480 }
3481 go_dev = go_dev_addr;
3482 }
3483
3484 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
3485}
3486
3487
3488static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
3489{
3490 if (os_strncmp(cmd, "persistent=", 11) == 0)
3491 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
3492 if (os_strncmp(cmd, "group=", 6) == 0)
3493 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
3494
3495 return -1;
3496}
3497
3498
3499static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
3500 char *cmd, int freq)
3501{
3502 int id;
3503 struct wpa_ssid *ssid;
3504
3505 id = atoi(cmd);
3506 ssid = wpa_config_get_network(wpa_s->conf, id);
3507 if (ssid == NULL || ssid->disabled != 2) {
3508 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3509 "for persistent P2P group",
3510 id);
3511 return -1;
3512 }
3513
3514 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
3515}
3516
3517
3518static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
3519{
3520 int freq = 0;
3521 char *pos;
3522
3523 pos = os_strstr(cmd, "freq=");
3524 if (pos)
3525 freq = atoi(pos + 5);
3526
3527 if (os_strncmp(cmd, "persistent=", 11) == 0)
3528 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
3529 if (os_strcmp(cmd, "persistent") == 0 ||
3530 os_strncmp(cmd, "persistent ", 11) == 0)
3531 return wpas_p2p_group_add(wpa_s, 1, freq);
3532 if (os_strncmp(cmd, "freq=", 5) == 0)
3533 return wpas_p2p_group_add(wpa_s, 0, freq);
3534
3535 wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
3536 cmd);
3537 return -1;
3538}
3539
3540
3541static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
3542 char *buf, size_t buflen)
3543{
3544 u8 addr[ETH_ALEN], *addr_ptr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003545 int next, res;
3546 const struct p2p_peer_info *info;
3547 char *pos, *end;
3548 char devtype[WPS_DEV_TYPE_BUFSIZE];
3549 struct wpa_ssid *ssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003550
3551 if (!wpa_s->global->p2p)
3552 return -1;
3553
3554 if (os_strcmp(cmd, "FIRST") == 0) {
3555 addr_ptr = NULL;
3556 next = 0;
3557 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
3558 if (hwaddr_aton(cmd + 5, addr) < 0)
3559 return -1;
3560 addr_ptr = addr;
3561 next = 1;
3562 } else {
3563 if (hwaddr_aton(cmd, addr) < 0)
3564 return -1;
3565 addr_ptr = addr;
3566 next = 0;
3567 }
3568
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003569 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
3570 if (info == NULL)
3571 return -1;
3572
3573 pos = buf;
3574 end = buf + buflen;
3575
3576 res = os_snprintf(pos, end - pos, MACSTR "\n"
3577 "pri_dev_type=%s\n"
3578 "device_name=%s\n"
3579 "manufacturer=%s\n"
3580 "model_name=%s\n"
3581 "model_number=%s\n"
3582 "serial_number=%s\n"
3583 "config_methods=0x%x\n"
3584 "dev_capab=0x%x\n"
3585 "group_capab=0x%x\n"
3586 "level=%d\n",
3587 MAC2STR(info->p2p_device_addr),
3588 wps_dev_type_bin2str(info->pri_dev_type,
3589 devtype, sizeof(devtype)),
3590 info->device_name,
3591 info->manufacturer,
3592 info->model_name,
3593 info->model_number,
3594 info->serial_number,
3595 info->config_methods,
3596 info->dev_capab,
3597 info->group_capab,
3598 info->level);
3599 if (res < 0 || res >= end - pos)
3600 return pos - buf;
3601 pos += res;
3602
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003603 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003604 if (ssid) {
3605 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
3606 if (res < 0 || res >= end - pos)
3607 return pos - buf;
3608 pos += res;
3609 }
3610
3611 res = p2p_get_peer_info_txt(info, pos, end - pos);
3612 if (res < 0)
3613 return pos - buf;
3614 pos += res;
3615
3616 return pos - buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003617}
3618
3619
Dmitry Shmidt04949592012-07-19 12:16:46 -07003620static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
3621 const char *param)
3622{
3623 struct wpa_freq_range *freq = NULL, *n;
3624 unsigned int count = 0, i;
3625 const char *pos, *pos2, *pos3;
3626
3627 if (wpa_s->global->p2p == NULL)
3628 return -1;
3629
3630 /*
3631 * param includes comma separated frequency range.
3632 * For example: 2412-2432,2462,5000-6000
3633 */
3634 pos = param;
3635 while (pos && pos[0]) {
3636 n = os_realloc(freq,
3637 (count + 1) * sizeof(struct wpa_freq_range));
3638 if (n == NULL) {
3639 os_free(freq);
3640 return -1;
3641 }
3642 freq = n;
3643 freq[count].min = atoi(pos);
3644 pos2 = os_strchr(pos, '-');
3645 pos3 = os_strchr(pos, ',');
3646 if (pos2 && (!pos3 || pos2 < pos3)) {
3647 pos2++;
3648 freq[count].max = atoi(pos2);
3649 } else
3650 freq[count].max = freq[count].min;
3651 pos = pos3;
3652 if (pos)
3653 pos++;
3654 count++;
3655 }
3656
3657 for (i = 0; i < count; i++) {
3658 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
3659 freq[i].min, freq[i].max);
3660 }
3661
3662 os_free(wpa_s->global->p2p_disallow_freq);
3663 wpa_s->global->p2p_disallow_freq = freq;
3664 wpa_s->global->num_p2p_disallow_freq = count;
3665 wpas_p2p_update_channel_list(wpa_s);
3666 return 0;
3667}
3668
3669
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003670static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
3671{
3672 char *param;
3673
3674 if (wpa_s->global->p2p == NULL)
3675 return -1;
3676
3677 param = os_strchr(cmd, ' ');
3678 if (param == NULL)
3679 return -1;
3680 *param++ = '\0';
3681
3682 if (os_strcmp(cmd, "discoverability") == 0) {
3683 p2p_set_client_discoverability(wpa_s->global->p2p,
3684 atoi(param));
3685 return 0;
3686 }
3687
3688 if (os_strcmp(cmd, "managed") == 0) {
3689 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
3690 return 0;
3691 }
3692
3693 if (os_strcmp(cmd, "listen_channel") == 0) {
3694 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
3695 atoi(param));
3696 }
3697
3698 if (os_strcmp(cmd, "ssid_postfix") == 0) {
3699 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
3700 os_strlen(param));
3701 }
3702
3703 if (os_strcmp(cmd, "noa") == 0) {
3704 char *pos;
3705 int count, start, duration;
3706 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
3707 count = atoi(param);
3708 pos = os_strchr(param, ',');
3709 if (pos == NULL)
3710 return -1;
3711 pos++;
3712 start = atoi(pos);
3713 pos = os_strchr(pos, ',');
3714 if (pos == NULL)
3715 return -1;
3716 pos++;
3717 duration = atoi(pos);
3718 if (count < 0 || count > 255 || start < 0 || duration < 0)
3719 return -1;
3720 if (count == 0 && duration > 0)
3721 return -1;
3722 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
3723 "start=%d duration=%d", count, start, duration);
3724 return wpas_p2p_set_noa(wpa_s, count, start, duration);
3725 }
3726
3727 if (os_strcmp(cmd, "ps") == 0)
3728 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
3729
3730 if (os_strcmp(cmd, "oppps") == 0)
3731 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
3732
3733 if (os_strcmp(cmd, "ctwindow") == 0)
3734 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
3735
3736 if (os_strcmp(cmd, "disabled") == 0) {
3737 wpa_s->global->p2p_disabled = atoi(param);
3738 wpa_printf(MSG_DEBUG, "P2P functionality %s",
3739 wpa_s->global->p2p_disabled ?
3740 "disabled" : "enabled");
3741 if (wpa_s->global->p2p_disabled) {
3742 wpas_p2p_stop_find(wpa_s);
3743 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
3744 p2p_flush(wpa_s->global->p2p);
3745 }
3746 return 0;
3747 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003748
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003749 if (os_strcmp(cmd, "conc_pref") == 0) {
3750 if (os_strcmp(param, "sta") == 0)
3751 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
3752 else if (os_strcmp(param, "p2p") == 0)
3753 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003754 else {
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003755 wpa_printf(MSG_INFO, "Invalid conc_pref value");
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003756 return -1;
3757 }
Dmitry Shmidt2fb777c2012-05-02 12:29:53 -07003758 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
Dmitry Shmidt04949592012-07-19 12:16:46 -07003759 "%s", param);
Dmitry Shmidt687922c2012-03-26 14:02:32 -07003760 return 0;
3761 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07003762
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003763 if (os_strcmp(cmd, "force_long_sd") == 0) {
3764 wpa_s->force_long_sd = atoi(param);
3765 return 0;
3766 }
3767
3768 if (os_strcmp(cmd, "peer_filter") == 0) {
3769 u8 addr[ETH_ALEN];
3770 if (hwaddr_aton(param, addr))
3771 return -1;
3772 p2p_set_peer_filter(wpa_s->global->p2p, addr);
3773 return 0;
3774 }
3775
3776 if (os_strcmp(cmd, "cross_connect") == 0)
3777 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
3778
3779 if (os_strcmp(cmd, "go_apsd") == 0) {
3780 if (os_strcmp(param, "disable") == 0)
3781 wpa_s->set_ap_uapsd = 0;
3782 else {
3783 wpa_s->set_ap_uapsd = 1;
3784 wpa_s->ap_uapsd = atoi(param);
3785 }
3786 return 0;
3787 }
3788
3789 if (os_strcmp(cmd, "client_apsd") == 0) {
3790 if (os_strcmp(param, "disable") == 0)
3791 wpa_s->set_sta_uapsd = 0;
3792 else {
3793 int be, bk, vi, vo;
3794 char *pos;
3795 /* format: BE,BK,VI,VO;max SP Length */
3796 be = atoi(param);
3797 pos = os_strchr(param, ',');
3798 if (pos == NULL)
3799 return -1;
3800 pos++;
3801 bk = atoi(pos);
3802 pos = os_strchr(pos, ',');
3803 if (pos == NULL)
3804 return -1;
3805 pos++;
3806 vi = atoi(pos);
3807 pos = os_strchr(pos, ',');
3808 if (pos == NULL)
3809 return -1;
3810 pos++;
3811 vo = atoi(pos);
3812 /* ignore max SP Length for now */
3813
3814 wpa_s->set_sta_uapsd = 1;
3815 wpa_s->sta_uapsd = 0;
3816 if (be)
3817 wpa_s->sta_uapsd |= BIT(0);
3818 if (bk)
3819 wpa_s->sta_uapsd |= BIT(1);
3820 if (vi)
3821 wpa_s->sta_uapsd |= BIT(2);
3822 if (vo)
3823 wpa_s->sta_uapsd |= BIT(3);
3824 }
3825 return 0;
3826 }
3827
Dmitry Shmidt04949592012-07-19 12:16:46 -07003828 if (os_strcmp(cmd, "disallow_freq") == 0)
3829 return p2p_ctrl_disallow_freq(wpa_s, param);
3830
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003831 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
3832 cmd);
3833
3834 return -1;
3835}
3836
3837
3838static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
3839{
3840 char *pos, *pos2;
3841 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
3842
3843 if (cmd[0]) {
3844 pos = os_strchr(cmd, ' ');
3845 if (pos == NULL)
3846 return -1;
3847 *pos++ = '\0';
3848 dur1 = atoi(cmd);
3849
3850 pos2 = os_strchr(pos, ' ');
3851 if (pos2)
3852 *pos2++ = '\0';
3853 int1 = atoi(pos);
3854 } else
3855 pos2 = NULL;
3856
3857 if (pos2) {
3858 pos = os_strchr(pos2, ' ');
3859 if (pos == NULL)
3860 return -1;
3861 *pos++ = '\0';
3862 dur2 = atoi(pos2);
3863 int2 = atoi(pos);
3864 }
3865
3866 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
3867}
3868
3869
3870static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
3871{
3872 char *pos;
3873 unsigned int period = 0, interval = 0;
3874
3875 if (cmd[0]) {
3876 pos = os_strchr(cmd, ' ');
3877 if (pos == NULL)
3878 return -1;
3879 *pos++ = '\0';
3880 period = atoi(cmd);
3881 interval = atoi(pos);
3882 }
3883
3884 return wpas_p2p_ext_listen(wpa_s, period, interval);
3885}
3886
3887#endif /* CONFIG_P2P */
3888
3889
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003890#ifdef CONFIG_INTERWORKING
3891static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
3892{
3893 u8 bssid[ETH_ALEN];
3894 struct wpa_bss *bss;
3895
3896 if (hwaddr_aton(dst, bssid)) {
3897 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
3898 return -1;
3899 }
3900
3901 bss = wpa_bss_get_bssid(wpa_s, bssid);
3902 if (bss == NULL) {
3903 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
3904 MAC2STR(bssid));
3905 return -1;
3906 }
3907
3908 return interworking_connect(wpa_s, bss);
3909}
3910
3911
3912static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
3913{
3914 u8 dst_addr[ETH_ALEN];
3915 int used;
3916 char *pos;
3917#define MAX_ANQP_INFO_ID 100
3918 u16 id[MAX_ANQP_INFO_ID];
3919 size_t num_id = 0;
3920
3921 used = hwaddr_aton2(dst, dst_addr);
3922 if (used < 0)
3923 return -1;
3924 pos = dst + used;
3925 while (num_id < MAX_ANQP_INFO_ID) {
3926 id[num_id] = atoi(pos);
3927 if (id[num_id])
3928 num_id++;
3929 pos = os_strchr(pos + 1, ',');
3930 if (pos == NULL)
3931 break;
3932 pos++;
3933 }
3934
3935 if (num_id == 0)
3936 return -1;
3937
3938 return anqp_send_req(wpa_s, dst_addr, id, num_id);
3939}
3940#endif /* CONFIG_INTERWORKING */
3941
3942
Dmitry Shmidt04949592012-07-19 12:16:46 -07003943#ifdef CONFIG_HS20
3944
3945static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
3946{
3947 u8 dst_addr[ETH_ALEN];
3948 int used;
3949 char *pos;
3950 u32 subtypes = 0;
3951
3952 used = hwaddr_aton2(dst, dst_addr);
3953 if (used < 0)
3954 return -1;
3955 pos = dst + used;
3956 for (;;) {
3957 int num = atoi(pos);
3958 if (num <= 0 || num > 31)
3959 return -1;
3960 subtypes |= BIT(num);
3961 pos = os_strchr(pos + 1, ',');
3962 if (pos == NULL)
3963 break;
3964 pos++;
3965 }
3966
3967 if (subtypes == 0)
3968 return -1;
3969
3970 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
3971}
3972
3973
3974static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
3975 const u8 *addr, const char *realm)
3976{
3977 u8 *buf;
3978 size_t rlen, len;
3979 int ret;
3980
3981 rlen = os_strlen(realm);
3982 len = 3 + rlen;
3983 buf = os_malloc(len);
3984 if (buf == NULL)
3985 return -1;
3986 buf[0] = 1; /* NAI Home Realm Count */
3987 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
3988 buf[2] = rlen;
3989 os_memcpy(buf + 3, realm, rlen);
3990
3991 ret = hs20_anqp_send_req(wpa_s, addr,
3992 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
3993 buf, len);
3994
3995 os_free(buf);
3996
3997 return ret;
3998}
3999
4000
4001static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4002 char *dst)
4003{
4004 struct wpa_cred *cred = wpa_s->conf->cred;
4005 u8 dst_addr[ETH_ALEN];
4006 int used;
4007 u8 *buf;
4008 size_t len;
4009 int ret;
4010
4011 used = hwaddr_aton2(dst, dst_addr);
4012 if (used < 0)
4013 return -1;
4014
4015 while (dst[used] == ' ')
4016 used++;
4017 if (os_strncmp(dst + used, "realm=", 6) == 0)
4018 return hs20_nai_home_realm_list(wpa_s, dst_addr,
4019 dst + used + 6);
4020
4021 len = os_strlen(dst + used);
4022
4023 if (len == 0 && cred && cred->realm)
4024 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
4025
4026 if (len % 1)
4027 return -1;
4028 len /= 2;
4029 buf = os_malloc(len);
4030 if (buf == NULL)
4031 return -1;
4032 if (hexstr2bin(dst + used, buf, len) < 0) {
4033 os_free(buf);
4034 return -1;
4035 }
4036
4037 ret = hs20_anqp_send_req(wpa_s, dst_addr,
4038 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4039 buf, len);
4040 os_free(buf);
4041
4042 return ret;
4043}
4044
4045#endif /* CONFIG_HS20 */
4046
4047
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004048static int wpa_supplicant_ctrl_iface_sta_autoconnect(
4049 struct wpa_supplicant *wpa_s, char *cmd)
4050{
4051 wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
4052 return 0;
4053}
4054
4055
Dmitry Shmidt04949592012-07-19 12:16:46 -07004056#ifdef CONFIG_AUTOSCAN
4057
4058static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
4059 char *cmd)
4060{
4061 enum wpa_states state = wpa_s->wpa_state;
4062 char *new_params = NULL;
4063
4064 if (os_strlen(cmd) > 0) {
4065 new_params = os_strdup(cmd);
4066 if (new_params == NULL)
4067 return -1;
4068 }
4069
4070 os_free(wpa_s->conf->autoscan);
4071 wpa_s->conf->autoscan = new_params;
4072
4073 if (wpa_s->conf->autoscan == NULL)
4074 autoscan_deinit(wpa_s);
4075 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
4076 autoscan_init(wpa_s, 1);
4077 else if (state == WPA_SCANNING)
4078 wpa_supplicant_reinit_autoscan(wpa_s);
4079
4080 return 0;
4081}
4082
4083#endif /* CONFIG_AUTOSCAN */
4084
4085
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004086static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
4087 size_t buflen)
4088{
4089 struct wpa_signal_info si;
4090 int ret;
4091
4092 ret = wpa_drv_signal_poll(wpa_s, &si);
4093 if (ret)
4094 return -1;
4095
4096 ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
4097 "NOISE=%d\nFREQUENCY=%u\n",
4098 si.current_signal, si.current_txrate / 1000,
4099 si.current_noise, si.frequency);
4100 if (ret < 0 || (unsigned int) ret > buflen)
4101 return -1;
4102 return ret;
4103}
4104
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004105static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
4106 size_t buflen)
4107{
4108 struct hostap_sta_driver_data sta;
4109 int ret;
4110
4111 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
4112 if (ret)
4113 return -1;
4114
4115 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
4116 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
4117 if (ret < 0 || (unsigned int) ret > buflen)
4118 return -1;
4119 return ret;
4120}
4121
4122
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004123#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004124static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
4125 char *buf, size_t buflen)
4126{
4127 int ret;
4128
4129 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
4130 if (ret == 0)
4131 ret = sprintf(buf, "%s\n", "OK");
4132 return ret;
4133}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004134#endif
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004135
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004136char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
4137 char *buf, size_t *resp_len)
4138{
4139 char *reply;
4140 const int reply_size = 4096;
4141 int ctrl_rsp = 0;
4142 int reply_len;
4143
4144 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
4145 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
4146 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
4147 (const u8 *) buf, os_strlen(buf));
4148 } else {
4149 int level = MSG_DEBUG;
4150 if (os_strcmp(buf, "PING") == 0)
4151 level = MSG_EXCESSIVE;
4152 wpa_hexdump_ascii(level, "RX ctrl_iface",
4153 (const u8 *) buf, os_strlen(buf));
4154 }
4155
4156 reply = os_malloc(reply_size);
4157 if (reply == NULL) {
4158 *resp_len = 1;
4159 return NULL;
4160 }
4161
4162 os_memcpy(reply, "OK\n", 3);
4163 reply_len = 3;
4164
4165 if (os_strcmp(buf, "PING") == 0) {
4166 os_memcpy(reply, "PONG\n", 5);
4167 reply_len = 5;
4168 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
4169 if (wpa_debug_reopen_file() < 0)
4170 reply_len = -1;
4171 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
4172 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
4173 } else if (os_strcmp(buf, "MIB") == 0) {
4174 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
4175 if (reply_len >= 0) {
4176 int res;
4177 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
4178 reply_size - reply_len);
4179 if (res < 0)
4180 reply_len = -1;
4181 else
4182 reply_len += res;
4183 }
4184 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
4185 reply_len = wpa_supplicant_ctrl_iface_status(
4186 wpa_s, buf + 6, reply, reply_size);
4187 } else if (os_strcmp(buf, "PMKSA") == 0) {
4188 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
4189 reply_size);
4190 } else if (os_strncmp(buf, "SET ", 4) == 0) {
4191 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
4192 reply_len = -1;
4193 } else if (os_strncmp(buf, "GET ", 4) == 0) {
4194 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
4195 reply, reply_size);
4196 } else if (os_strcmp(buf, "LOGON") == 0) {
4197 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
4198 } else if (os_strcmp(buf, "LOGOFF") == 0) {
4199 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
4200 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004201 wpa_s->normal_scans = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004202 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004203 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4204 reply_len = -1;
4205 else {
4206 wpa_s->disconnected = 0;
4207 wpa_s->reassociate = 1;
4208 wpa_supplicant_req_scan(wpa_s, 0, 0);
4209 }
4210 } else if (os_strcmp(buf, "RECONNECT") == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004211 wpa_s->normal_scans = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004212 wpa_supplicant_reinit_autoscan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004213 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4214 reply_len = -1;
4215 else if (wpa_s->disconnected) {
4216 wpa_s->disconnected = 0;
4217 wpa_s->reassociate = 1;
4218 wpa_supplicant_req_scan(wpa_s, 0, 0);
4219 }
4220#ifdef IEEE8021X_EAPOL
4221 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
4222 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
4223 reply_len = -1;
4224#endif /* IEEE8021X_EAPOL */
4225#ifdef CONFIG_PEERKEY
4226 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
4227 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
4228 reply_len = -1;
4229#endif /* CONFIG_PEERKEY */
4230#ifdef CONFIG_IEEE80211R
4231 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
4232 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
4233 reply_len = -1;
4234#endif /* CONFIG_IEEE80211R */
4235#ifdef CONFIG_WPS
4236 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
4237 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
4238 if (res == -2) {
4239 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4240 reply_len = 17;
4241 } else if (res)
4242 reply_len = -1;
4243 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
4244 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
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_PIN ", 8) == 0) {
4251 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
4252 reply,
4253 reply_size);
4254 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4255 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
4256 wpa_s, buf + 14, reply, reply_size);
4257 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4258 if (wpas_wps_cancel(wpa_s))
4259 reply_len = -1;
4260#ifdef CONFIG_WPS_OOB
4261 } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
4262 if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
4263 reply_len = -1;
4264#endif /* CONFIG_WPS_OOB */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004265#ifdef CONFIG_WPS_NFC
4266 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
4267 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
4268 reply_len = -1;
4269 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
4270 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
4271 reply_len = -1;
4272 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4273 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
4274 wpa_s, buf + 14, reply, reply_size);
4275 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4276 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
4277 buf + 17))
4278 reply_len = -1;
4279#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004280 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
4281 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
4282 reply_len = -1;
4283#ifdef CONFIG_AP
4284 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4285 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
4286 wpa_s, buf + 11, reply, reply_size);
4287#endif /* CONFIG_AP */
4288#ifdef CONFIG_WPS_ER
4289 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
4290 if (wpas_wps_er_start(wpa_s, NULL))
4291 reply_len = -1;
4292 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
4293 if (wpas_wps_er_start(wpa_s, buf + 13))
4294 reply_len = -1;
4295 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
4296 if (wpas_wps_er_stop(wpa_s))
4297 reply_len = -1;
4298 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
4299 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
4300 reply_len = -1;
4301 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
4302 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
4303 if (ret == -2) {
4304 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4305 reply_len = 17;
4306 } else if (ret == -3) {
4307 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
4308 reply_len = 18;
4309 } else if (ret == -4) {
4310 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
4311 reply_len = 20;
4312 } else if (ret)
4313 reply_len = -1;
4314 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
4315 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
4316 reply_len = -1;
4317 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
4318 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
4319 buf + 18))
4320 reply_len = -1;
4321 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
4322 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
4323 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004324#ifdef CONFIG_WPS_NFC
4325 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
4326 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
4327 wpa_s, buf + 24, reply, reply_size);
4328#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004329#endif /* CONFIG_WPS_ER */
4330#endif /* CONFIG_WPS */
4331#ifdef CONFIG_IBSS_RSN
4332 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
4333 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
4334 reply_len = -1;
4335#endif /* CONFIG_IBSS_RSN */
4336#ifdef CONFIG_P2P
4337 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
4338 if (p2p_ctrl_find(wpa_s, buf + 9))
4339 reply_len = -1;
4340 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
4341 if (p2p_ctrl_find(wpa_s, ""))
4342 reply_len = -1;
4343 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
4344 wpas_p2p_stop_find(wpa_s);
4345 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
4346 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
4347 reply_size);
4348 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
4349 if (p2p_ctrl_listen(wpa_s, buf + 11))
4350 reply_len = -1;
4351 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
4352 if (p2p_ctrl_listen(wpa_s, ""))
4353 reply_len = -1;
4354 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
4355 if (wpas_p2p_group_remove(wpa_s, buf + 17))
4356 reply_len = -1;
4357 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
4358 if (wpas_p2p_group_add(wpa_s, 0, 0))
4359 reply_len = -1;
4360 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
4361 if (p2p_ctrl_group_add(wpa_s, buf + 14))
4362 reply_len = -1;
4363 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
4364 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
4365 reply_len = -1;
4366 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
4367 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
4368 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
4369 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
4370 reply_size);
4371 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
4372 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
4373 reply_len = -1;
4374 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
4375 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
4376 reply_len = -1;
4377 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07004378#ifdef ANDROID_P2P
4379 wpas_p2p_sd_service_update(wpa_s, SRV_UPDATE);
4380#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004381 wpas_p2p_sd_service_update(wpa_s);
Dmitry Shmidtb5e8f062012-08-08 10:56:33 -07004382#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004383 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
4384 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
4385 reply_len = -1;
4386 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
4387 wpas_p2p_service_flush(wpa_s);
4388 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
4389 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
4390 reply_len = -1;
4391 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
4392 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
4393 reply_len = -1;
4394 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
4395 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
4396 reply_len = -1;
4397 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
4398 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
4399 reply_len = -1;
4400 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
4401 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
4402 reply_size);
4403 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
4404 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
4405 reply_len = -1;
4406 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
4407 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
4408 wpa_s->force_long_sd = 0;
4409 if (wpa_s->global->p2p)
4410 p2p_flush(wpa_s->global->p2p);
4411 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
4412 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
4413 reply_len = -1;
4414 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
4415 if (wpas_p2p_cancel(wpa_s))
4416 reply_len = -1;
4417 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
4418 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
4419 reply_len = -1;
4420 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
4421 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
4422 reply_len = -1;
4423 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
4424 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
4425 reply_len = -1;
4426 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
4427 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
4428 reply_len = -1;
4429#endif /* CONFIG_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004430#ifdef CONFIG_INTERWORKING
4431 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
4432 if (interworking_fetch_anqp(wpa_s) < 0)
4433 reply_len = -1;
4434 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
4435 interworking_stop_fetch_anqp(wpa_s);
4436 } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
4437 if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
4438 NULL) < 0)
4439 reply_len = -1;
4440 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
4441 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
4442 reply_len = -1;
4443 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
4444 if (get_anqp(wpa_s, buf + 9) < 0)
4445 reply_len = -1;
4446#endif /* CONFIG_INTERWORKING */
Dmitry Shmidt04949592012-07-19 12:16:46 -07004447#ifdef CONFIG_HS20
4448 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
4449 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
4450 reply_len = -1;
4451 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
4452 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
4453 reply_len = -1;
4454#endif /* CONFIG_HS20 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004455 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
4456 {
4457 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
4458 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
4459 reply_len = -1;
4460 else
4461 ctrl_rsp = 1;
4462 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
4463 if (wpa_supplicant_reload_configuration(wpa_s))
4464 reply_len = -1;
4465 } else if (os_strcmp(buf, "TERMINATE") == 0) {
4466 wpa_supplicant_terminate_proc(wpa_s->global);
4467 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
4468 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
4469 reply_len = -1;
Dmitry Shmidte19501d2011-03-16 14:32:18 -07004470 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004471 reply_len = wpa_supplicant_ctrl_iface_blacklist(
4472 wpa_s, buf + 9, reply, reply_size);
4473 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
4474 reply_len = wpa_supplicant_ctrl_iface_log_level(
4475 wpa_s, buf + 9, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004476 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
4477 reply_len = wpa_supplicant_ctrl_iface_list_networks(
4478 wpa_s, reply, reply_size);
4479 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004480#ifdef CONFIG_SME
4481 wpa_s->sme.prev_bssid_set = 0;
4482#endif /* CONFIG_SME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004483 wpa_s->reassociate = 0;
4484 wpa_s->disconnected = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004485 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004486 wpa_supplicant_cancel_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004487 wpa_supplicant_deauthenticate(wpa_s,
4488 WLAN_REASON_DEAUTH_LEAVING);
4489 } else if (os_strcmp(buf, "SCAN") == 0) {
4490 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4491 reply_len = -1;
4492 else {
4493 if (!wpa_s->scanning &&
4494 ((wpa_s->wpa_state <= WPA_SCANNING) ||
4495 (wpa_s->wpa_state == WPA_COMPLETED))) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07004496 wpa_s->normal_scans = 0;
4497 wpa_s->scan_req = 2;
4498 wpa_supplicant_req_scan(wpa_s, 0, 0);
4499 } else if (wpa_s->sched_scanning) {
4500 wpa_printf(MSG_DEBUG, "Stop ongoing "
4501 "sched_scan to allow requested "
4502 "full scan to proceed");
4503 wpa_supplicant_cancel_sched_scan(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004504 wpa_s->scan_req = 2;
4505 wpa_supplicant_req_scan(wpa_s, 0, 0);
4506 } else {
4507 wpa_printf(MSG_DEBUG, "Ongoing scan action - "
4508 "reject new request");
4509 reply_len = os_snprintf(reply, reply_size,
4510 "FAIL-BUSY\n");
4511 }
4512 }
4513 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
4514 reply_len = wpa_supplicant_ctrl_iface_scan_results(
4515 wpa_s, reply, reply_size);
4516 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
4517 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
4518 reply_len = -1;
4519 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
4520 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
4521 reply_len = -1;
4522 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
4523 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
4524 reply_len = -1;
4525 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
4526 reply_len = wpa_supplicant_ctrl_iface_add_network(
4527 wpa_s, reply, reply_size);
4528 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
4529 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
4530 reply_len = -1;
4531 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
4532 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
4533 reply_len = -1;
4534 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
4535 reply_len = wpa_supplicant_ctrl_iface_get_network(
4536 wpa_s, buf + 12, reply, reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004537 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
4538 reply_len = wpa_supplicant_ctrl_iface_list_creds(
4539 wpa_s, reply, reply_size);
4540 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
4541 reply_len = wpa_supplicant_ctrl_iface_add_cred(
4542 wpa_s, reply, reply_size);
4543 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
4544 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
4545 reply_len = -1;
4546 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
4547 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
4548 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004549#ifndef CONFIG_NO_CONFIG_WRITE
4550 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
4551 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
4552 reply_len = -1;
4553#endif /* CONFIG_NO_CONFIG_WRITE */
4554 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
4555 reply_len = wpa_supplicant_ctrl_iface_get_capability(
4556 wpa_s, buf + 15, reply, reply_size);
4557 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
4558 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
4559 reply_len = -1;
4560 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
4561 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
4562 reply_len = -1;
4563 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
4564 reply_len = wpa_supplicant_global_iface_list(
4565 wpa_s->global, reply, reply_size);
4566 } else if (os_strcmp(buf, "INTERFACES") == 0) {
4567 reply_len = wpa_supplicant_global_iface_interfaces(
4568 wpa_s->global, reply, reply_size);
4569 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
4570 reply_len = wpa_supplicant_ctrl_iface_bss(
4571 wpa_s, buf + 4, reply, reply_size);
4572#ifdef CONFIG_AP
4573 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
4574 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
4575 } else if (os_strncmp(buf, "STA ", 4) == 0) {
4576 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
4577 reply_size);
4578 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
4579 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
4580 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004581 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
4582 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
4583 reply_len = -1;
4584 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
4585 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
4586 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004587#endif /* CONFIG_AP */
4588 } else if (os_strcmp(buf, "SUSPEND") == 0) {
4589 wpas_notify_suspend(wpa_s->global);
4590 } else if (os_strcmp(buf, "RESUME") == 0) {
4591 wpas_notify_resume(wpa_s->global);
4592 } else if (os_strcmp(buf, "DROP_SA") == 0) {
4593 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
4594 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
4595 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
4596 reply_len = -1;
4597 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
4598 if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
4599 reply_len = -1;
4600 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
4601 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
4602 reply_len = -1;
4603 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
4604 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
4605 buf + 17))
4606 reply_len = -1;
4607#ifdef CONFIG_TDLS
4608 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
4609 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
4610 reply_len = -1;
4611 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
4612 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
4613 reply_len = -1;
4614 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
4615 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
4616 reply_len = -1;
4617#endif /* CONFIG_TDLS */
4618 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
4619 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
4620 reply_size);
Yuhao Zhengfcd6f212012-07-27 10:37:52 -07004621 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
4622 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
4623 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004624#ifdef CONFIG_AUTOSCAN
4625 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
4626 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
4627 reply_len = -1;
4628#endif /* CONFIG_AUTOSCAN */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004629#ifdef ANDROID
Dmitry Shmidtbd567ad2011-05-09 14:17:09 -07004630 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
4631 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
4632 reply_size);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004633#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004634 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
4635 eapol_sm_request_reauth(wpa_s->eapol);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004636 } else {
4637 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
4638 reply_len = 16;
4639 }
4640
4641 if (reply_len < 0) {
4642 os_memcpy(reply, "FAIL\n", 5);
4643 reply_len = 5;
4644 }
4645
4646 if (ctrl_rsp)
4647 eapol_sm_notify_ctrl_response(wpa_s->eapol);
4648
4649 *resp_len = reply_len;
4650 return reply;
4651}
4652
4653
4654static int wpa_supplicant_global_iface_add(struct wpa_global *global,
4655 char *cmd)
4656{
4657 struct wpa_interface iface;
4658 char *pos;
4659
4660 /*
4661 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
4662 * TAB<bridge_ifname>
4663 */
4664 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
4665
4666 os_memset(&iface, 0, sizeof(iface));
4667
4668 do {
4669 iface.ifname = pos = cmd;
4670 pos = os_strchr(pos, '\t');
4671 if (pos)
4672 *pos++ = '\0';
4673 if (iface.ifname[0] == '\0')
4674 return -1;
4675 if (pos == NULL)
4676 break;
4677
4678 iface.confname = pos;
4679 pos = os_strchr(pos, '\t');
4680 if (pos)
4681 *pos++ = '\0';
4682 if (iface.confname[0] == '\0')
4683 iface.confname = NULL;
4684 if (pos == NULL)
4685 break;
4686
4687 iface.driver = pos;
4688 pos = os_strchr(pos, '\t');
4689 if (pos)
4690 *pos++ = '\0';
4691 if (iface.driver[0] == '\0')
4692 iface.driver = NULL;
4693 if (pos == NULL)
4694 break;
4695
4696 iface.ctrl_interface = pos;
4697 pos = os_strchr(pos, '\t');
4698 if (pos)
4699 *pos++ = '\0';
4700 if (iface.ctrl_interface[0] == '\0')
4701 iface.ctrl_interface = NULL;
4702 if (pos == NULL)
4703 break;
4704
4705 iface.driver_param = pos;
4706 pos = os_strchr(pos, '\t');
4707 if (pos)
4708 *pos++ = '\0';
4709 if (iface.driver_param[0] == '\0')
4710 iface.driver_param = NULL;
4711 if (pos == NULL)
4712 break;
4713
4714 iface.bridge_ifname = pos;
4715 pos = os_strchr(pos, '\t');
4716 if (pos)
4717 *pos++ = '\0';
4718 if (iface.bridge_ifname[0] == '\0')
4719 iface.bridge_ifname = NULL;
4720 if (pos == NULL)
4721 break;
4722 } while (0);
4723
4724 if (wpa_supplicant_get_iface(global, iface.ifname))
4725 return -1;
4726
4727 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
4728}
4729
4730
4731static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
4732 char *cmd)
4733{
4734 struct wpa_supplicant *wpa_s;
4735
4736 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
4737
4738 wpa_s = wpa_supplicant_get_iface(global, cmd);
4739 if (wpa_s == NULL)
4740 return -1;
Dmitry Shmidte15c7b52011-08-03 15:04:35 -07004741 return wpa_supplicant_remove_iface(global, wpa_s, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004742}
4743
4744
4745static void wpa_free_iface_info(struct wpa_interface_info *iface)
4746{
4747 struct wpa_interface_info *prev;
4748
4749 while (iface) {
4750 prev = iface;
4751 iface = iface->next;
4752
4753 os_free(prev->ifname);
4754 os_free(prev->desc);
4755 os_free(prev);
4756 }
4757}
4758
4759
4760static int wpa_supplicant_global_iface_list(struct wpa_global *global,
4761 char *buf, int len)
4762{
4763 int i, res;
4764 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
4765 char *pos, *end;
4766
4767 for (i = 0; wpa_drivers[i]; i++) {
4768 struct wpa_driver_ops *drv = wpa_drivers[i];
4769 if (drv->get_interfaces == NULL)
4770 continue;
4771 tmp = drv->get_interfaces(global->drv_priv[i]);
4772 if (tmp == NULL)
4773 continue;
4774
4775 if (last == NULL)
4776 iface = last = tmp;
4777 else
4778 last->next = tmp;
4779 while (last->next)
4780 last = last->next;
4781 }
4782
4783 pos = buf;
4784 end = buf + len;
4785 for (tmp = iface; tmp; tmp = tmp->next) {
4786 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
4787 tmp->drv_name, tmp->ifname,
4788 tmp->desc ? tmp->desc : "");
4789 if (res < 0 || res >= end - pos) {
4790 *pos = '\0';
4791 break;
4792 }
4793 pos += res;
4794 }
4795
4796 wpa_free_iface_info(iface);
4797
4798 return pos - buf;
4799}
4800
4801
4802static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
4803 char *buf, int len)
4804{
4805 int res;
4806 char *pos, *end;
4807 struct wpa_supplicant *wpa_s;
4808
4809 wpa_s = global->ifaces;
4810 pos = buf;
4811 end = buf + len;
4812
4813 while (wpa_s) {
4814 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
4815 if (res < 0 || res >= end - pos) {
4816 *pos = '\0';
4817 break;
4818 }
4819 pos += res;
4820 wpa_s = wpa_s->next;
4821 }
4822 return pos - buf;
4823}
4824
4825
4826char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
4827 char *buf, size_t *resp_len)
4828{
4829 char *reply;
4830 const int reply_size = 2048;
4831 int reply_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004832 int level = MSG_DEBUG;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004833
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004834 if (os_strcmp(buf, "PING") == 0)
4835 level = MSG_EXCESSIVE;
4836 wpa_hexdump_ascii(level, "RX global ctrl_iface",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004837 (const u8 *) buf, os_strlen(buf));
4838
4839 reply = os_malloc(reply_size);
4840 if (reply == NULL) {
4841 *resp_len = 1;
4842 return NULL;
4843 }
4844
4845 os_memcpy(reply, "OK\n", 3);
4846 reply_len = 3;
4847
4848 if (os_strcmp(buf, "PING") == 0) {
4849 os_memcpy(reply, "PONG\n", 5);
4850 reply_len = 5;
4851 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
4852 if (wpa_supplicant_global_iface_add(global, buf + 14))
4853 reply_len = -1;
4854 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
4855 if (wpa_supplicant_global_iface_remove(global, buf + 17))
4856 reply_len = -1;
4857 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
4858 reply_len = wpa_supplicant_global_iface_list(
4859 global, reply, reply_size);
4860 } else if (os_strcmp(buf, "INTERFACES") == 0) {
4861 reply_len = wpa_supplicant_global_iface_interfaces(
4862 global, reply, reply_size);
4863 } else if (os_strcmp(buf, "TERMINATE") == 0) {
4864 wpa_supplicant_terminate_proc(global);
4865 } else if (os_strcmp(buf, "SUSPEND") == 0) {
4866 wpas_notify_suspend(global);
4867 } else if (os_strcmp(buf, "RESUME") == 0) {
4868 wpas_notify_resume(global);
4869 } else {
4870 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
4871 reply_len = 16;
4872 }
4873
4874 if (reply_len < 0) {
4875 os_memcpy(reply, "FAIL\n", 5);
4876 reply_len = 5;
4877 }
4878
4879 *resp_len = reply_len;
4880 return reply;
4881}