Fixed build without CONFIG_IEEE8021X_EAPOL, but with CONFIG_CTRL_IFACE
[libeap.git] / wpa_supplicant / ctrl_iface.c
1 /*
2  * WPA Supplicant / Control interface (shared code for all backends)
3  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eloop.h"
19 #include "wpa.h"
20 #include "config.h"
21 #include "eapol_supp/eapol_supp_sm.h"
22 #include "wpa_supplicant_i.h"
23 #include "ctrl_iface.h"
24 #include "l2_packet/l2_packet.h"
25 #include "preauth.h"
26 #include "pmksa_cache.h"
27 #include "wpa_ctrl.h"
28 #include "eap_peer/eap.h"
29 #include "ieee802_11_defs.h"
30
31
32 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
33                                                   char *buf, int len);
34
35
36 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
37                                          char *cmd)
38 {
39         char *value;
40         int ret = 0;
41
42         value = os_strchr(cmd, ' ');
43         if (value == NULL)
44                 return -1;
45         *value++ = '\0';
46
47         wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
48         if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
49                 eapol_sm_configure(wpa_s->eapol,
50                                    atoi(value), -1, -1, -1);
51         } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
52                 eapol_sm_configure(wpa_s->eapol,
53                                    -1, atoi(value), -1, -1);
54         } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
55                 eapol_sm_configure(wpa_s->eapol,
56                                    -1, -1, atoi(value), -1);
57         } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
58                 eapol_sm_configure(wpa_s->eapol,
59                                    -1, -1, -1, atoi(value));
60         } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
61                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
62                                      atoi(value)))
63                         ret = -1;
64         } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
65                    0) {
66                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
67                                      atoi(value)))
68                         ret = -1;
69         } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
70                 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
71                         ret = -1;
72         } else
73                 ret = -1;
74
75         return ret;
76 }
77
78
79 #ifdef IEEE8021X_EAPOL
80 static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
81                                              char *addr)
82 {
83         u8 bssid[ETH_ALEN];
84         struct wpa_ssid *ssid = wpa_s->current_ssid;
85
86         if (hwaddr_aton(addr, bssid)) {
87                 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
88                            "'%s'", addr);
89                 return -1;
90         }
91
92         wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
93         rsn_preauth_deinit(wpa_s->wpa);
94         if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
95                 return -1;
96
97         return 0;
98 }
99 #endif /* IEEE8021X_EAPOL */
100
101
102 #ifdef CONFIG_PEERKEY
103 /* MLME-STKSTART.request(peer) */
104 static int wpa_supplicant_ctrl_iface_stkstart(
105         struct wpa_supplicant *wpa_s, char *addr)
106 {
107         u8 peer[ETH_ALEN];
108
109         if (hwaddr_aton(addr, peer)) {
110                 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
111                            "address '%s'", peer);
112                 return -1;
113         }
114
115         wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
116                    MAC2STR(peer));
117
118         return wpa_sm_stkstart(wpa_s->wpa, peer);
119 }
120 #endif /* CONFIG_PEERKEY */
121
122
123 #ifdef CONFIG_IEEE80211R
124 static int wpa_supplicant_ctrl_iface_ft_ds(
125         struct wpa_supplicant *wpa_s, char *addr)
126 {
127         u8 target_ap[ETH_ALEN];
128
129         if (hwaddr_aton(addr, target_ap)) {
130                 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
131                            "address '%s'", target_ap);
132                 return -1;
133         }
134
135         wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
136
137         return wpa_ft_start_over_ds(wpa_s->wpa, target_ap);
138 }
139 #endif /* CONFIG_IEEE80211R */
140
141
142 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
143                                               char *rsp)
144 {
145 #ifdef IEEE8021X_EAPOL
146         char *pos, *id_pos;
147         int id;
148         struct wpa_ssid *ssid;
149         struct eap_peer_config *eap;
150
151         pos = os_strchr(rsp, '-');
152         if (pos == NULL)
153                 return -1;
154         *pos++ = '\0';
155         id_pos = pos;
156         pos = os_strchr(pos, ':');
157         if (pos == NULL)
158                 return -1;
159         *pos++ = '\0';
160         id = atoi(id_pos);
161         wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
162         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
163                               (u8 *) pos, os_strlen(pos));
164
165         ssid = wpa_config_get_network(wpa_s->conf, id);
166         if (ssid == NULL) {
167                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
168                            "to update", id);
169                 return -1;
170         }
171         eap = &ssid->eap;
172
173         if (os_strcmp(rsp, "IDENTITY") == 0) {
174                 os_free(eap->identity);
175                 eap->identity = (u8 *) os_strdup(pos);
176                 eap->identity_len = os_strlen(pos);
177                 eap->pending_req_identity = 0;
178                 if (ssid == wpa_s->current_ssid)
179                         wpa_s->reassociate = 1;
180         } else if (os_strcmp(rsp, "PASSWORD") == 0) {
181                 os_free(eap->password);
182                 eap->password = (u8 *) os_strdup(pos);
183                 eap->password_len = os_strlen(pos);
184                 eap->pending_req_password = 0;
185                 if (ssid == wpa_s->current_ssid)
186                         wpa_s->reassociate = 1;
187         } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
188                 os_free(eap->new_password);
189                 eap->new_password = (u8 *) os_strdup(pos);
190                 eap->new_password_len = os_strlen(pos);
191                 eap->pending_req_new_password = 0;
192                 if (ssid == wpa_s->current_ssid)
193                         wpa_s->reassociate = 1;
194         } else if (os_strcmp(rsp, "PIN") == 0) {
195                 os_free(eap->pin);
196                 eap->pin = os_strdup(pos);
197                 eap->pending_req_pin = 0;
198                 if (ssid == wpa_s->current_ssid)
199                         wpa_s->reassociate = 1;
200         } else if (os_strcmp(rsp, "OTP") == 0) {
201                 os_free(eap->otp);
202                 eap->otp = (u8 *) os_strdup(pos);
203                 eap->otp_len = os_strlen(pos);
204                 os_free(eap->pending_req_otp);
205                 eap->pending_req_otp = NULL;
206                 eap->pending_req_otp_len = 0;
207         } else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
208                 os_free(eap->private_key_passwd);
209                 eap->private_key_passwd = (u8 *) os_strdup(pos);
210                 eap->pending_req_passphrase = 0;
211                 if (ssid == wpa_s->current_ssid)
212                         wpa_s->reassociate = 1;
213         } else {
214                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
215                 return -1;
216         }
217
218         return 0;
219 #else /* IEEE8021X_EAPOL */
220         wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
221         return -1;
222 #endif /* IEEE8021X_EAPOL */
223 }
224
225
226 static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
227                                             const char *params,
228                                             char *buf, size_t buflen)
229 {
230         char *pos, *end, tmp[30];
231         int res, verbose, ret;
232
233         verbose = os_strcmp(params, "-VERBOSE") == 0;
234         pos = buf;
235         end = buf + buflen;
236         if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
237                 struct wpa_ssid *ssid = wpa_s->current_ssid;
238                 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
239                                   MAC2STR(wpa_s->bssid));
240                 if (ret < 0 || ret >= end - pos)
241                         return pos - buf;
242                 pos += ret;
243                 if (ssid) {
244                         u8 *_ssid = ssid->ssid;
245                         size_t ssid_len = ssid->ssid_len;
246                         u8 ssid_buf[MAX_SSID_LEN];
247                         if (ssid_len == 0) {
248                                 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
249                                 if (_res < 0)
250                                         ssid_len = 0;
251                                 else
252                                         ssid_len = _res;
253                                 _ssid = ssid_buf;
254                         }
255                         ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
256                                           wpa_ssid_txt(_ssid, ssid_len),
257                                           ssid->id);
258                         if (ret < 0 || ret >= end - pos)
259                                 return pos - buf;
260                         pos += ret;
261
262                         if (ssid->id_str) {
263                                 ret = os_snprintf(pos, end - pos,
264                                                   "id_str=%s\n",
265                                                   ssid->id_str);
266                                 if (ret < 0 || ret >= end - pos)
267                                         return pos - buf;
268                                 pos += ret;
269                         }
270                 }
271
272                 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
273         }
274         ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
275                           wpa_supplicant_state_txt(wpa_s->wpa_state));
276         if (ret < 0 || ret >= end - pos)
277                 return pos - buf;
278         pos += ret;
279
280         if (wpa_s->l2 &&
281             l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
282                 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
283                 if (ret < 0 || ret >= end - pos)
284                         return pos - buf;
285                 pos += ret;
286         }
287
288         if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
289             wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
290             wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
291                 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
292                                           verbose);
293                 if (res >= 0)
294                         pos += res;
295         }
296
297         res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
298         if (res >= 0)
299                 pos += res;
300
301         return pos - buf;
302 }
303
304
305 static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
306                                            char *cmd)
307 {
308         char *pos;
309         int id;
310         struct wpa_ssid *ssid;
311         u8 bssid[ETH_ALEN];
312
313         /* cmd: "<network id> <BSSID>" */
314         pos = os_strchr(cmd, ' ');
315         if (pos == NULL)
316                 return -1;
317         *pos++ = '\0';
318         id = atoi(cmd);
319         wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
320         if (hwaddr_aton(pos, bssid)) {
321                 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
322                 return -1;
323         }
324
325         ssid = wpa_config_get_network(wpa_s->conf, id);
326         if (ssid == NULL) {
327                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
328                            "to update", id);
329                 return -1;
330         }
331
332         os_memcpy(ssid->bssid, bssid, ETH_ALEN);
333         ssid->bssid_set =
334                 os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
335                 
336
337         return 0;
338 }
339
340
341 static int wpa_supplicant_ctrl_iface_list_networks(
342         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
343 {
344         char *pos, *end;
345         struct wpa_ssid *ssid;
346         int ret;
347
348         pos = buf;
349         end = buf + buflen;
350         ret = os_snprintf(pos, end - pos,
351                           "network id / ssid / bssid / flags\n");
352         if (ret < 0 || ret >= end - pos)
353                 return pos - buf;
354         pos += ret;
355
356         ssid = wpa_s->conf->ssid;
357         while (ssid) {
358                 ret = os_snprintf(pos, end - pos, "%d\t%s",
359                                   ssid->id,
360                                   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
361                 if (ret < 0 || ret >= end - pos)
362                         return pos - buf;
363                 pos += ret;
364                 if (ssid->bssid_set) {
365                         ret = os_snprintf(pos, end - pos, "\t" MACSTR,
366                                           MAC2STR(ssid->bssid));
367                 } else {
368                         ret = os_snprintf(pos, end - pos, "\tany");
369                 }
370                 if (ret < 0 || ret >= end - pos)
371                         return pos - buf;
372                 pos += ret;
373                 ret = os_snprintf(pos, end - pos, "\t%s%s",
374                                   ssid == wpa_s->current_ssid ?
375                                   "[CURRENT]" : "",
376                                   ssid->disabled ? "[DISABLED]" : "");
377                 if (ret < 0 || ret >= end - pos)
378                         return pos - buf;
379                 pos += ret;
380                 ret = os_snprintf(pos, end - pos, "\n");
381                 if (ret < 0 || ret >= end - pos)
382                         return pos - buf;
383                 pos += ret;
384
385                 ssid = ssid->next;
386         }
387
388         return pos - buf;
389 }
390
391
392 static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
393 {
394         int first = 1, ret;
395         ret = os_snprintf(pos, end - pos, "-");
396         if (ret < 0 || ret >= end - pos)
397                 return pos;
398         pos += ret;
399         if (cipher & WPA_CIPHER_NONE) {
400                 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
401                 if (ret < 0 || ret >= end - pos)
402                         return pos;
403                 pos += ret;
404                 first = 0;
405         }
406         if (cipher & WPA_CIPHER_WEP40) {
407                 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
408                 if (ret < 0 || ret >= end - pos)
409                         return pos;
410                 pos += ret;
411                 first = 0;
412         }
413         if (cipher & WPA_CIPHER_WEP104) {
414                 ret = os_snprintf(pos, end - pos, "%sWEP104",
415                                   first ? "" : "+");
416                 if (ret < 0 || ret >= end - pos)
417                         return pos;
418                 pos += ret;
419                 first = 0;
420         }
421         if (cipher & WPA_CIPHER_TKIP) {
422                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
423                 if (ret < 0 || ret >= end - pos)
424                         return pos;
425                 pos += ret;
426                 first = 0;
427         }
428         if (cipher & WPA_CIPHER_CCMP) {
429                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
430                 if (ret < 0 || ret >= end - pos)
431                         return pos;
432                 pos += ret;
433                 first = 0;
434         }
435         return pos;
436 }
437
438
439 static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
440                                     const u8 *ie, size_t ie_len)
441 {
442         struct wpa_ie_data data;
443         int first, ret;
444
445         ret = os_snprintf(pos, end - pos, "[%s-", proto);
446         if (ret < 0 || ret >= end - pos)
447                 return pos;
448         pos += ret;
449
450         if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
451                 ret = os_snprintf(pos, end - pos, "?]");
452                 if (ret < 0 || ret >= end - pos)
453                         return pos;
454                 pos += ret;
455                 return pos;
456         }
457
458         first = 1;
459         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
460                 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
461                 if (ret < 0 || ret >= end - pos)
462                         return pos;
463                 pos += ret;
464                 first = 0;
465         }
466         if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
467                 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
468                 if (ret < 0 || ret >= end - pos)
469                         return pos;
470                 pos += ret;
471                 first = 0;
472         }
473         if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
474                 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
475                 if (ret < 0 || ret >= end - pos)
476                         return pos;
477                 pos += ret;
478                 first = 0;
479         }
480 #ifdef CONFIG_IEEE80211R
481         if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
482                 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
483                                   first ? "" : "+");
484                 if (ret < 0 || ret >= end - pos)
485                         return pos;
486                 pos += ret;
487                 first = 0;
488         }
489         if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
490                 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
491                                   first ? "" : "+");
492                 if (ret < 0 || ret >= end - pos)
493                         return pos;
494                 pos += ret;
495                 first = 0;
496         }
497 #endif /* CONFIG_IEEE80211R */
498
499         pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
500
501         if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
502                 ret = os_snprintf(pos, end - pos, "-preauth");
503                 if (ret < 0 || ret >= end - pos)
504                         return pos;
505                 pos += ret;
506         }
507
508         ret = os_snprintf(pos, end - pos, "]");
509         if (ret < 0 || ret >= end - pos)
510                 return pos;
511         pos += ret;
512
513         return pos;
514 }
515
516
517 /* Format one result on one text line into a buffer. */
518 static int wpa_supplicant_ctrl_iface_scan_result(
519         const struct wpa_scan_res *res, char *buf, size_t buflen)
520 {
521         char *pos, *end;
522         int ret;
523         const u8 *ie, *ie2;
524
525         pos = buf;
526         end = buf + buflen;
527
528         ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
529                           MAC2STR(res->bssid), res->freq, res->level);
530         if (ret < 0 || ret >= end - pos)
531                 return pos - buf;
532         pos += ret;
533         ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
534         if (ie)
535                 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
536         ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
537         if (ie2)
538                 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
539         if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
540                 ret = os_snprintf(pos, end - pos, "[WEP]");
541                 if (ret < 0 || ret >= end - pos)
542                         return pos - buf;
543                 pos += ret;
544         }
545         if (res->caps & IEEE80211_CAP_IBSS) {
546                 ret = os_snprintf(pos, end - pos, "[IBSS]");
547                 if (ret < 0 || ret >= end - pos)
548                         return pos - buf;
549                 pos += ret;
550         }
551
552         ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
553         ret = os_snprintf(pos, end - pos, "\t%s",
554                           ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
555         if (ret < 0 || ret >= end - pos)
556                 return pos - buf;
557         pos += ret;
558
559         ret = os_snprintf(pos, end - pos, "\n");
560         if (ret < 0 || ret >= end - pos)
561                 return pos - buf;
562         pos += ret;
563
564         return pos - buf;
565 }
566
567
568 static int wpa_supplicant_ctrl_iface_scan_results(
569         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
570 {
571         char *pos, *end;
572         struct wpa_scan_res *res;
573         int ret;
574         size_t i;
575
576         if (wpa_s->scan_res == NULL &&
577             wpa_supplicant_get_scan_results(wpa_s) < 0)
578                 return 0;
579
580         pos = buf;
581         end = buf + buflen;
582         ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
583                           "flags / ssid\n");
584         if (ret < 0 || ret >= end - pos)
585                 return pos - buf;
586         pos += ret;
587
588         for (i = 0; i < wpa_s->scan_res->num; i++) {
589                 res = wpa_s->scan_res->res[i];
590                 ret = wpa_supplicant_ctrl_iface_scan_result(res, pos,
591                                                             end - pos);
592                 if (ret < 0 || ret >= end - pos)
593                         return pos - buf;
594                 pos += ret;
595         }
596
597         return pos - buf;
598 }
599
600
601 static int wpa_supplicant_ctrl_iface_select_network(
602         struct wpa_supplicant *wpa_s, char *cmd)
603 {
604         int id;
605         struct wpa_ssid *ssid;
606
607         /* cmd: "<network id>" or "any" */
608         if (os_strcmp(cmd, "any") == 0) {
609                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
610                 ssid = wpa_s->conf->ssid;
611                 while (ssid) {
612                         ssid->disabled = 0;
613                         ssid = ssid->next;
614                 }
615                 wpa_s->reassociate = 1;
616                 wpa_supplicant_req_scan(wpa_s, 0, 0);
617                 return 0;
618         }
619
620         id = atoi(cmd);
621         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
622
623         ssid = wpa_config_get_network(wpa_s->conf, id);
624         if (ssid == NULL) {
625                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
626                            "id=%d", id);
627                 return -1;
628         }
629
630         if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
631                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
632
633         /* Mark all other networks disabled and trigger reassociation */
634         ssid = wpa_s->conf->ssid;
635         while (ssid) {
636                 ssid->disabled = id != ssid->id;
637                 ssid = ssid->next;
638         }
639         wpa_s->reassociate = 1;
640         wpa_supplicant_req_scan(wpa_s, 0, 0);
641
642         return 0;
643 }
644
645
646 static int wpa_supplicant_ctrl_iface_enable_network(
647         struct wpa_supplicant *wpa_s, char *cmd)
648 {
649         int id;
650         struct wpa_ssid *ssid;
651
652         /* cmd: "<network id>" or "all" */
653         if (os_strcmp(cmd, "all") == 0) {
654                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
655                 ssid = wpa_s->conf->ssid;
656                 while (ssid) {
657                         if (ssid == wpa_s->current_ssid && ssid->disabled)
658                                 wpa_s->reassociate = 1;
659                         ssid->disabled = 0;
660                         ssid = ssid->next;
661                 }
662                 if (wpa_s->reassociate)
663                         wpa_supplicant_req_scan(wpa_s, 0, 0);
664                 return 0;
665         }
666
667         id = atoi(cmd);
668         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
669
670         ssid = wpa_config_get_network(wpa_s->conf, id);
671         if (ssid == NULL) {
672                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
673                            "id=%d", id);
674                 return -1;
675         }
676
677         if (wpa_s->current_ssid == NULL && ssid->disabled) {
678                 /*
679                  * Try to reassociate since there is no current configuration
680                  * and a new network was made available. */
681                 wpa_s->reassociate = 1;
682                 wpa_supplicant_req_scan(wpa_s, 0, 0);
683         }
684         ssid->disabled = 0;
685
686         return 0;
687 }
688
689
690 static int wpa_supplicant_ctrl_iface_disable_network(
691         struct wpa_supplicant *wpa_s, char *cmd)
692 {
693         int id;
694         struct wpa_ssid *ssid;
695
696         /* cmd: "<network id>" or "all" */
697         if (os_strcmp(cmd, "all") == 0) {
698                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
699                 ssid = wpa_s->conf->ssid;
700                 while (ssid) {
701                         ssid->disabled = 1;
702                         ssid = ssid->next;
703                 }
704                 if (wpa_s->current_ssid)
705                         wpa_supplicant_disassociate(wpa_s,
706                                                     WLAN_REASON_DEAUTH_LEAVING);
707                 return 0;
708         }
709
710         id = atoi(cmd);
711         wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
712
713         ssid = wpa_config_get_network(wpa_s->conf, id);
714         if (ssid == NULL) {
715                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
716                            "id=%d", id);
717                 return -1;
718         }
719
720         if (ssid == wpa_s->current_ssid)
721                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
722         ssid->disabled = 1;
723
724         return 0;
725 }
726
727
728 static int wpa_supplicant_ctrl_iface_add_network(
729         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
730 {
731         struct wpa_ssid *ssid;
732         int ret;
733
734         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
735
736         ssid = wpa_config_add_network(wpa_s->conf);
737         if (ssid == NULL)
738                 return -1;
739         ssid->disabled = 1;
740         wpa_config_set_network_defaults(ssid);
741
742         ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
743         if (ret < 0 || (size_t) ret >= buflen)
744                 return -1;
745         return ret;
746 }
747
748
749 static int wpa_supplicant_ctrl_iface_remove_network(
750         struct wpa_supplicant *wpa_s, char *cmd)
751 {
752         int id;
753         struct wpa_ssid *ssid;
754
755         /* cmd: "<network id>" or "all" */
756         if (os_strcmp(cmd, "all") == 0) {
757                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
758                 ssid = wpa_s->conf->ssid;
759                 while (ssid) {
760                         id = ssid->id;
761                         ssid = ssid->next;
762                         wpa_config_remove_network(wpa_s->conf, id);
763                 }
764                 if (wpa_s->current_ssid) {
765                         eapol_sm_invalidate_cached_session(wpa_s->eapol);
766                         wpa_supplicant_disassociate(wpa_s,
767                                                     WLAN_REASON_DEAUTH_LEAVING);
768                 }
769                 return 0;
770         }
771
772         id = atoi(cmd);
773         wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
774
775         ssid = wpa_config_get_network(wpa_s->conf, id);
776         if (ssid == NULL ||
777             wpa_config_remove_network(wpa_s->conf, id) < 0) {
778                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
779                            "id=%d", id);
780                 return -1;
781         }
782
783         if (ssid == wpa_s->current_ssid) {
784                 /*
785                  * Invalidate the EAP session cache if the current network is
786                  * removed.
787                  */
788                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
789
790                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
791         }
792
793         return 0;
794 }
795
796
797 static int wpa_supplicant_ctrl_iface_set_network(
798         struct wpa_supplicant *wpa_s, char *cmd)
799 {
800         int id;
801         struct wpa_ssid *ssid;
802         char *name, *value;
803
804         /* cmd: "<network id> <variable name> <value>" */
805         name = os_strchr(cmd, ' ');
806         if (name == NULL)
807                 return -1;
808         *name++ = '\0';
809
810         value = os_strchr(name, ' ');
811         if (value == NULL)
812                 return -1;
813         *value++ = '\0';
814
815         id = atoi(cmd);
816         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
817                    id, name);
818         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
819                               (u8 *) value, os_strlen(value));
820
821         ssid = wpa_config_get_network(wpa_s->conf, id);
822         if (ssid == NULL) {
823                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
824                            "id=%d", id);
825                 return -1;
826         }
827
828         if (wpa_config_set(ssid, name, value, 0) < 0) {
829                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
830                            "variable '%s'", name);
831                 return -1;
832         }
833
834         if (wpa_s->current_ssid == ssid) {
835                 /*
836                  * Invalidate the EAP session cache if anything in the current
837                  * configuration changes.
838                  */
839                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
840         }
841
842         if ((os_strcmp(name, "psk") == 0 &&
843              value[0] == '"' && ssid->ssid_len) ||
844             (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
845                 wpa_config_update_psk(ssid);
846
847         return 0;
848 }
849
850
851 static int wpa_supplicant_ctrl_iface_get_network(
852         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
853 {
854         int id;
855         size_t res;
856         struct wpa_ssid *ssid;
857         char *name, *value;
858
859         /* cmd: "<network id> <variable name>" */
860         name = os_strchr(cmd, ' ');
861         if (name == NULL || buflen == 0)
862                 return -1;
863         *name++ = '\0';
864
865         id = atoi(cmd);
866         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
867                    id, name);
868
869         ssid = wpa_config_get_network(wpa_s->conf, id);
870         if (ssid == NULL) {
871                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
872                            "id=%d", id);
873                 return -1;
874         }
875
876         value = wpa_config_get_no_key(ssid, name);
877         if (value == NULL) {
878                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
879                            "variable '%s'", name);
880                 return -1;
881         }
882
883         res = os_strlcpy(buf, value, buflen);
884         if (res >= buflen) {
885                 os_free(value);
886                 return -1;
887         }
888
889         os_free(value);
890
891         return res;
892 }
893
894
895 #ifndef CONFIG_NO_CONFIG_WRITE
896 static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
897 {
898         int ret;
899
900         if (!wpa_s->conf->update_config) {
901                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
902                            "to update configuration (update_config=0)");
903                 return -1;
904         }
905
906         ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
907         if (ret) {
908                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
909                            "update configuration");
910         } else {
911                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
912                            " updated");
913         }
914
915         return ret;
916 }
917 #endif /* CONFIG_NO_CONFIG_WRITE */
918
919
920 static int ctrl_iface_get_capability_pairwise(int res, char *strict,
921                                               struct wpa_driver_capa *capa,
922                                               char *buf, size_t buflen)
923 {
924         int ret, first = 1;
925         char *pos, *end;
926         size_t len;
927
928         pos = buf;
929         end = pos + buflen;
930
931         if (res < 0) {
932                 if (strict)
933                         return 0;
934                 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
935                 if (len >= buflen)
936                         return -1;
937                 return len;
938         }
939
940         if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
941                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
942                 if (ret < 0 || ret >= end - pos)
943                         return pos - buf;
944                 pos += ret;
945                 first = 0;
946         }
947
948         if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
949                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
950                 if (ret < 0 || ret >= end - pos)
951                         return pos - buf;
952                 pos += ret;
953                 first = 0;
954         }
955
956         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
957                 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
958                 if (ret < 0 || ret >= end - pos)
959                         return pos - buf;
960                 pos += ret;
961                 first = 0;
962         }
963
964         return pos - buf;
965 }
966
967
968 static int ctrl_iface_get_capability_group(int res, char *strict,
969                                            struct wpa_driver_capa *capa,
970                                            char *buf, size_t buflen)
971 {
972         int ret, first = 1;
973         char *pos, *end;
974         size_t len;
975
976         pos = buf;
977         end = pos + buflen;
978
979         if (res < 0) {
980                 if (strict)
981                         return 0;
982                 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
983                 if (len >= buflen)
984                         return -1;
985                 return len;
986         }
987
988         if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
989                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
990                 if (ret < 0 || ret >= end - pos)
991                         return pos - buf;
992                 pos += ret;
993                 first = 0;
994         }
995
996         if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
997                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
998                 if (ret < 0 || ret >= end - pos)
999                         return pos - buf;
1000                 pos += ret;
1001                 first = 0;
1002         }
1003
1004         if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1005                 ret = os_snprintf(pos, end - pos, "%sWEP104",
1006                                   first ? "" : " ");
1007                 if (ret < 0 || ret >= end - pos)
1008                         return pos - buf;
1009                 pos += ret;
1010                 first = 0;
1011         }
1012
1013         if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1014                 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
1015                 if (ret < 0 || ret >= end - pos)
1016                         return pos - buf;
1017                 pos += ret;
1018                 first = 0;
1019         }
1020
1021         return pos - buf;
1022 }
1023
1024
1025 static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
1026                                               struct wpa_driver_capa *capa,
1027                                               char *buf, size_t buflen)
1028 {
1029         int ret;
1030         char *pos, *end;
1031         size_t len;
1032
1033         pos = buf;
1034         end = pos + buflen;
1035
1036         if (res < 0) {
1037                 if (strict)
1038                         return 0;
1039                 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
1040                                  "NONE", buflen);
1041                 if (len >= buflen)
1042                         return -1;
1043                 return len;
1044         }
1045
1046         ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1047         if (ret < 0 || ret >= end - pos)
1048                 return pos - buf;
1049         pos += ret;
1050
1051         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1052                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1053                 ret = os_snprintf(pos, end - pos, " WPA-EAP");
1054                 if (ret < 0 || ret >= end - pos)
1055                         return pos - buf;
1056                 pos += ret;
1057         }
1058
1059         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1060                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1061                 ret = os_snprintf(pos, end - pos, " WPA-PSK");
1062                 if (ret < 0 || ret >= end - pos)
1063                         return pos - buf;
1064                 pos += ret;
1065         }
1066
1067         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1068                 ret = os_snprintf(pos, end - pos, " WPA-NONE");
1069                 if (ret < 0 || ret >= end - pos)
1070                         return pos - buf;
1071                 pos += ret;
1072         }
1073
1074         return pos - buf;
1075 }
1076
1077
1078 static int ctrl_iface_get_capability_proto(int res, char *strict,
1079                                            struct wpa_driver_capa *capa,
1080                                            char *buf, size_t buflen)
1081 {
1082         int ret, first = 1;
1083         char *pos, *end;
1084         size_t len;
1085
1086         pos = buf;
1087         end = pos + buflen;
1088
1089         if (res < 0) {
1090                 if (strict)
1091                         return 0;
1092                 len = os_strlcpy(buf, "RSN WPA", buflen);
1093                 if (len >= buflen)
1094                         return -1;
1095                 return len;
1096         }
1097
1098         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1099                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1100                 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
1101                 if (ret < 0 || ret >= end - pos)
1102                         return pos - buf;
1103                 pos += ret;
1104                 first = 0;
1105         }
1106
1107         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1108                               WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1109                 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
1110                 if (ret < 0 || ret >= end - pos)
1111                         return pos - buf;
1112                 pos += ret;
1113                 first = 0;
1114         }
1115
1116         return pos - buf;
1117 }
1118
1119
1120 static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
1121                                               struct wpa_driver_capa *capa,
1122                                               char *buf, size_t buflen)
1123 {
1124         int ret, first = 1;
1125         char *pos, *end;
1126         size_t len;
1127
1128         pos = buf;
1129         end = pos + buflen;
1130
1131         if (res < 0) {
1132                 if (strict)
1133                         return 0;
1134                 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
1135                 if (len >= buflen)
1136                         return -1;
1137                 return len;
1138         }
1139
1140         if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
1141                 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
1142                 if (ret < 0 || ret >= end - pos)
1143                         return pos - buf;
1144                 pos += ret;
1145                 first = 0;
1146         }
1147
1148         if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
1149                 ret = os_snprintf(pos, end - pos, "%sSHARED",
1150                                   first ? "" : " ");
1151                 if (ret < 0 || ret >= end - pos)
1152                         return pos - buf;
1153                 pos += ret;
1154                 first = 0;
1155         }
1156
1157         if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
1158                 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
1159                 if (ret < 0 || ret >= end - pos)
1160                         return pos - buf;
1161                 pos += ret;
1162                 first = 0;
1163         }
1164
1165         return pos - buf;
1166 }
1167
1168
1169 static int wpa_supplicant_ctrl_iface_get_capability(
1170         struct wpa_supplicant *wpa_s, const char *_field, char *buf,
1171         size_t buflen)
1172 {
1173         struct wpa_driver_capa capa;
1174         int res;
1175         char *strict;
1176         char field[30];
1177         size_t len;
1178
1179         /* Determine whether or not strict checking was requested */
1180         len = os_strlcpy(field, _field, sizeof(field));
1181         if (len >= sizeof(field))
1182                 return -1;
1183         strict = os_strchr(field, ' ');
1184         if (strict != NULL) {
1185                 *strict++ = '\0';
1186                 if (os_strcmp(strict, "strict") != 0)
1187                         return -1;
1188         }
1189
1190         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
1191                 field, strict ? strict : "");
1192
1193         if (os_strcmp(field, "eap") == 0) {
1194                 return eap_get_names(buf, buflen);
1195         }
1196
1197         res = wpa_drv_get_capa(wpa_s, &capa);
1198
1199         if (os_strcmp(field, "pairwise") == 0)
1200                 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
1201                                                           buf, buflen);
1202
1203         if (os_strcmp(field, "group") == 0)
1204                 return ctrl_iface_get_capability_group(res, strict, &capa,
1205                                                        buf, buflen);
1206
1207         if (os_strcmp(field, "key_mgmt") == 0)
1208                 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
1209                                                           buf, buflen);
1210
1211         if (os_strcmp(field, "proto") == 0)
1212                 return ctrl_iface_get_capability_proto(res, strict, &capa,
1213                                                        buf, buflen);
1214
1215         if (os_strcmp(field, "auth_alg") == 0)
1216                 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
1217                                                           buf, buflen);
1218
1219         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1220                    field);
1221
1222         return -1;
1223 }
1224
1225
1226 static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
1227                                          const char *cmd, char *buf,
1228                                          size_t buflen)
1229 {
1230         u8 bssid[ETH_ALEN];
1231         size_t i;
1232         struct wpa_scan_results *results;
1233         struct wpa_scan_res *bss;
1234         int ret;
1235         char *pos, *end;
1236         const u8 *ie, *ie2;
1237
1238         results = wpa_s->scan_res;
1239         if (results == NULL)
1240                 return 0;
1241
1242         if (hwaddr_aton(cmd, bssid) == 0) {
1243                 for (i = 0; i < results->num; i++) {
1244                         if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN)
1245                             == 0)
1246                                 break;
1247                 }
1248         } else
1249                 i = atoi(cmd);
1250
1251         if (i >= results->num || results->res[i] == NULL)
1252                 return 0; /* no match found */
1253
1254         bss = results->res[i];
1255         pos = buf;
1256         end = buf + buflen;
1257         ret = snprintf(pos, end - pos,
1258                        "bssid=" MACSTR "\n"
1259                        "freq=%d\n"
1260                        "beacon_int=%d\n"
1261                        "capabilities=0x%04x\n"
1262                        "qual=%d\n"
1263                        "noise=%d\n"
1264                        "level=%d\n"
1265                        "tsf=%016llu\n"
1266                        "ie=",
1267                        MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
1268                        bss->caps, bss->qual, bss->noise, bss->level,
1269                        (unsigned long long) bss->tsf);
1270         if (ret < 0 || ret >= end - pos)
1271                 return pos - buf;
1272         pos += ret;
1273
1274         ie = (const u8 *) (bss + 1);
1275         for (i = 0; i < bss->ie_len; i++) {
1276                 ret = snprintf(pos, end - pos, "%02x", *ie++);
1277                 if (ret < 0 || ret >= end - pos)
1278                         return pos - buf;
1279                 pos += ret;
1280         }
1281
1282         ret = snprintf(pos, end - pos, "\n");
1283         if (ret < 0 || ret >= end - pos)
1284                 return pos - buf;
1285         pos += ret;
1286
1287         ret = os_snprintf(pos, end - pos, "flags=");
1288         if (ret < 0 || ret >= end - pos)
1289                 return pos - buf;
1290         pos += ret;
1291
1292         ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1293         if (ie)
1294                 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1295         ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN);
1296         if (ie2)
1297                 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1298         if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1299                 ret = os_snprintf(pos, end - pos, "[WEP]");
1300                 if (ret < 0 || ret >= end - pos)
1301                         return pos - buf;
1302                 pos += ret;
1303         }
1304         if (bss->caps & IEEE80211_CAP_IBSS) {
1305                 ret = os_snprintf(pos, end - pos, "[IBSS]");
1306                 if (ret < 0 || ret >= end - pos)
1307                         return pos - buf;
1308                 pos += ret;
1309         }
1310
1311         ret = snprintf(pos, end - pos, "\n");
1312         if (ret < 0 || ret >= end - pos)
1313                 return pos - buf;
1314         pos += ret;
1315
1316         ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
1317         ret = os_snprintf(pos, end - pos, "ssid=%s\n",
1318                           ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
1319         if (ret < 0 || ret >= end - pos)
1320                 return pos - buf;
1321         pos += ret;
1322
1323         return pos - buf;
1324 }
1325
1326
1327 static int wpa_supplicant_ctrl_iface_ap_scan(
1328         struct wpa_supplicant *wpa_s, char *cmd)
1329 {
1330         int ap_scan = atoi(cmd);
1331
1332         if (ap_scan < 0 || ap_scan > 2)
1333                 return -1;
1334         wpa_s->conf->ap_scan = ap_scan;
1335         return 0;
1336 }
1337
1338
1339 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1340                                          char *buf, size_t *resp_len)
1341 {
1342         char *reply;
1343         const int reply_size = 2048;
1344         int ctrl_rsp = 0;
1345         int reply_len;
1346
1347         if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1348             os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1349                 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1350                                       (const u8 *) buf, os_strlen(buf));
1351         } else {
1352                 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1353                                   (const u8 *) buf, os_strlen(buf));
1354         }
1355
1356         reply = os_malloc(reply_size);
1357         if (reply == NULL) {
1358                 *resp_len = 1;
1359                 return NULL;
1360         }
1361
1362         os_memcpy(reply, "OK\n", 3);
1363         reply_len = 3;
1364
1365         if (os_strcmp(buf, "PING") == 0) {
1366                 os_memcpy(reply, "PONG\n", 5);
1367                 reply_len = 5;
1368         } else if (os_strcmp(buf, "MIB") == 0) {
1369                 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1370                 if (reply_len >= 0) {
1371                         int res;
1372                         res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1373                                                reply_size - reply_len);
1374                         if (res < 0)
1375                                 reply_len = -1;
1376                         else
1377                                 reply_len += res;
1378                 }
1379         } else if (os_strncmp(buf, "STATUS", 6) == 0) {
1380                 reply_len = wpa_supplicant_ctrl_iface_status(
1381                         wpa_s, buf + 6, reply, reply_size);
1382         } else if (os_strcmp(buf, "PMKSA") == 0) {
1383                 reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
1384         } else if (os_strncmp(buf, "SET ", 4) == 0) {
1385                 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1386                         reply_len = -1;
1387         } else if (os_strcmp(buf, "LOGON") == 0) {
1388                 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1389         } else if (os_strcmp(buf, "LOGOFF") == 0) {
1390                 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1391         } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
1392                 wpa_s->disconnected = 0;
1393                 wpa_s->reassociate = 1;
1394                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1395         } else if (os_strcmp(buf, "RECONNECT") == 0) {
1396                 if (wpa_s->disconnected) {
1397                         wpa_s->disconnected = 0;
1398                         wpa_s->reassociate = 1;
1399                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1400                 }
1401 #ifdef IEEE8021X_EAPOL
1402         } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1403                 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1404                         reply_len = -1;
1405 #endif /* IEEE8021X_EAPOL */
1406 #ifdef CONFIG_PEERKEY
1407         } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1408                 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1409                         reply_len = -1;
1410 #endif /* CONFIG_PEERKEY */
1411 #ifdef CONFIG_IEEE80211R
1412         } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
1413                 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
1414                         reply_len = -1;
1415 #endif /* CONFIG_IEEE80211R */
1416         } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1417         {
1418                 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1419                             wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1420                         reply_len = -1;
1421                 else
1422                         ctrl_rsp = 1;
1423         } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1424                 if (wpa_supplicant_reload_configuration(wpa_s))
1425                         reply_len = -1;
1426         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1427                 eloop_terminate();
1428         } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1429                 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1430                         reply_len = -1;
1431         } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1432                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
1433                         wpa_s, reply, reply_size);
1434         } else if (os_strcmp(buf, "DISCONNECT") == 0) {
1435                 wpa_s->reassociate = 0;
1436                 wpa_s->disconnected = 1;
1437                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1438         } else if (os_strcmp(buf, "SCAN") == 0) {
1439                 wpa_s->scan_req = 2;
1440                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1441         } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1442                 reply_len = wpa_supplicant_ctrl_iface_scan_results(
1443                         wpa_s, reply, reply_size);
1444         } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1445                 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1446                         reply_len = -1;
1447         } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1448                 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1449                         reply_len = -1;
1450         } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1451                 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1452                         reply_len = -1;
1453         } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1454                 reply_len = wpa_supplicant_ctrl_iface_add_network(
1455                         wpa_s, reply, reply_size);
1456         } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1457                 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1458                         reply_len = -1;
1459         } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1460                 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1461                         reply_len = -1;
1462         } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1463                 reply_len = wpa_supplicant_ctrl_iface_get_network(
1464                         wpa_s, buf + 12, reply, reply_size);
1465 #ifndef CONFIG_NO_CONFIG_WRITE
1466         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1467                 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1468                         reply_len = -1;
1469 #endif /* CONFIG_NO_CONFIG_WRITE */
1470         } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1471                 reply_len = wpa_supplicant_ctrl_iface_get_capability(
1472                         wpa_s, buf + 15, reply, reply_size);
1473         } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1474                 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1475                         reply_len = -1;
1476         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1477                 reply_len = wpa_supplicant_global_iface_interfaces(
1478                         wpa_s->global, reply, reply_size);
1479         } else if (os_strncmp(buf, "BSS ", 4) == 0) {
1480                 reply_len = wpa_supplicant_ctrl_iface_bss(
1481                         wpa_s, buf + 4, reply, reply_size);
1482         } else {
1483                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1484                 reply_len = 16;
1485         }
1486
1487         if (reply_len < 0) {
1488                 os_memcpy(reply, "FAIL\n", 5);
1489                 reply_len = 5;
1490         }
1491
1492         if (ctrl_rsp)
1493                 eapol_sm_notify_ctrl_response(wpa_s->eapol);
1494
1495         *resp_len = reply_len;
1496         return reply;
1497 }
1498
1499
1500 static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1501                                            char *cmd)
1502 {
1503         struct wpa_interface iface;
1504         char *pos;
1505
1506         /*
1507          * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1508          * TAB<bridge_ifname>
1509          */
1510         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1511
1512         os_memset(&iface, 0, sizeof(iface));
1513
1514         do {
1515                 iface.ifname = pos = cmd;
1516                 pos = os_strchr(pos, '\t');
1517                 if (pos)
1518                         *pos++ = '\0';
1519                 if (iface.ifname[0] == '\0')
1520                         return -1;
1521                 if (pos == NULL)
1522                         break;
1523
1524                 iface.confname = pos;
1525                 pos = os_strchr(pos, '\t');
1526                 if (pos)
1527                         *pos++ = '\0';
1528                 if (iface.confname[0] == '\0')
1529                         iface.confname = NULL;
1530                 if (pos == NULL)
1531                         break;
1532
1533                 iface.driver = pos;
1534                 pos = os_strchr(pos, '\t');
1535                 if (pos)
1536                         *pos++ = '\0';
1537                 if (iface.driver[0] == '\0')
1538                         iface.driver = NULL;
1539                 if (pos == NULL)
1540                         break;
1541
1542                 iface.ctrl_interface = pos;
1543                 pos = os_strchr(pos, '\t');
1544                 if (pos)
1545                         *pos++ = '\0';
1546                 if (iface.ctrl_interface[0] == '\0')
1547                         iface.ctrl_interface = NULL;
1548                 if (pos == NULL)
1549                         break;
1550
1551                 iface.driver_param = pos;
1552                 pos = os_strchr(pos, '\t');
1553                 if (pos)
1554                         *pos++ = '\0';
1555                 if (iface.driver_param[0] == '\0')
1556                         iface.driver_param = NULL;
1557                 if (pos == NULL)
1558                         break;
1559
1560                 iface.bridge_ifname = pos;
1561                 pos = os_strchr(pos, '\t');
1562                 if (pos)
1563                         *pos++ = '\0';
1564                 if (iface.bridge_ifname[0] == '\0')
1565                         iface.bridge_ifname = NULL;
1566                 if (pos == NULL)
1567                         break;
1568         } while (0);
1569
1570         if (wpa_supplicant_get_iface(global, iface.ifname))
1571                 return -1;
1572
1573         return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1574 }
1575
1576
1577 static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1578                                               char *cmd)
1579 {
1580         struct wpa_supplicant *wpa_s;
1581
1582         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1583
1584         wpa_s = wpa_supplicant_get_iface(global, cmd);
1585         if (wpa_s == NULL)
1586                 return -1;
1587         return wpa_supplicant_remove_iface(global, wpa_s);
1588 }
1589
1590
1591 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1592                                                   char *buf, int len)
1593 {
1594         int res;
1595         char *pos, *end;
1596         struct wpa_supplicant *wpa_s;
1597
1598         wpa_s = global->ifaces;
1599         pos = buf;
1600         end = buf + len;
1601
1602         while (wpa_s) {
1603                 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1604                 if (res < 0 || res >= end - pos) {
1605                         *pos = '\0';
1606                         break;
1607                 }
1608                 pos += res;
1609                 wpa_s = wpa_s->next;
1610         }
1611         return pos - buf;
1612 }
1613
1614
1615 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1616                                                 char *buf, size_t *resp_len)
1617 {
1618         char *reply;
1619         const int reply_size = 2048;
1620         int reply_len;
1621
1622         wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1623                           (const u8 *) buf, os_strlen(buf));
1624
1625         reply = os_malloc(reply_size);
1626         if (reply == NULL) {
1627                 *resp_len = 1;
1628                 return NULL;
1629         }
1630
1631         os_memcpy(reply, "OK\n", 3);
1632         reply_len = 3;
1633
1634         if (os_strcmp(buf, "PING") == 0) {
1635                 os_memcpy(reply, "PONG\n", 5);
1636                 reply_len = 5;
1637         } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1638                 if (wpa_supplicant_global_iface_add(global, buf + 14))
1639                         reply_len = -1;
1640         } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1641                 if (wpa_supplicant_global_iface_remove(global, buf + 17))
1642                         reply_len = -1;
1643         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1644                 reply_len = wpa_supplicant_global_iface_interfaces(
1645                         global, reply, reply_size);
1646         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1647                 eloop_terminate();
1648         } else {
1649                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1650                 reply_len = 16;
1651         }
1652
1653         if (reply_len < 0) {
1654                 os_memcpy(reply, "FAIL\n", 5);
1655                 reply_len = 5;
1656         }
1657
1658         *resp_len = reply_len;
1659         return reply;
1660 }