98ac08f1e73ade3f51971482310ba4960c766d54
[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 = !is_zero_ether_addr(bssid);
334
335         return 0;
336 }
337
338
339 static int wpa_supplicant_ctrl_iface_list_networks(
340         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
341 {
342         char *pos, *end;
343         struct wpa_ssid *ssid;
344         int ret;
345
346         pos = buf;
347         end = buf + buflen;
348         ret = os_snprintf(pos, end - pos,
349                           "network id / ssid / bssid / flags\n");
350         if (ret < 0 || ret >= end - pos)
351                 return pos - buf;
352         pos += ret;
353
354         ssid = wpa_s->conf->ssid;
355         while (ssid) {
356                 ret = os_snprintf(pos, end - pos, "%d\t%s",
357                                   ssid->id,
358                                   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
359                 if (ret < 0 || ret >= end - pos)
360                         return pos - buf;
361                 pos += ret;
362                 if (ssid->bssid_set) {
363                         ret = os_snprintf(pos, end - pos, "\t" MACSTR,
364                                           MAC2STR(ssid->bssid));
365                 } else {
366                         ret = os_snprintf(pos, end - pos, "\tany");
367                 }
368                 if (ret < 0 || ret >= end - pos)
369                         return pos - buf;
370                 pos += ret;
371                 ret = os_snprintf(pos, end - pos, "\t%s%s",
372                                   ssid == wpa_s->current_ssid ?
373                                   "[CURRENT]" : "",
374                                   ssid->disabled ? "[DISABLED]" : "");
375                 if (ret < 0 || ret >= end - pos)
376                         return pos - buf;
377                 pos += ret;
378                 ret = os_snprintf(pos, end - pos, "\n");
379                 if (ret < 0 || ret >= end - pos)
380                         return pos - buf;
381                 pos += ret;
382
383                 ssid = ssid->next;
384         }
385
386         return pos - buf;
387 }
388
389
390 static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
391 {
392         int first = 1, ret;
393         ret = os_snprintf(pos, end - pos, "-");
394         if (ret < 0 || ret >= end - pos)
395                 return pos;
396         pos += ret;
397         if (cipher & WPA_CIPHER_NONE) {
398                 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
399                 if (ret < 0 || ret >= end - pos)
400                         return pos;
401                 pos += ret;
402                 first = 0;
403         }
404         if (cipher & WPA_CIPHER_WEP40) {
405                 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
406                 if (ret < 0 || ret >= end - pos)
407                         return pos;
408                 pos += ret;
409                 first = 0;
410         }
411         if (cipher & WPA_CIPHER_WEP104) {
412                 ret = os_snprintf(pos, end - pos, "%sWEP104",
413                                   first ? "" : "+");
414                 if (ret < 0 || ret >= end - pos)
415                         return pos;
416                 pos += ret;
417                 first = 0;
418         }
419         if (cipher & WPA_CIPHER_TKIP) {
420                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
421                 if (ret < 0 || ret >= end - pos)
422                         return pos;
423                 pos += ret;
424                 first = 0;
425         }
426         if (cipher & WPA_CIPHER_CCMP) {
427                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
428                 if (ret < 0 || ret >= end - pos)
429                         return pos;
430                 pos += ret;
431                 first = 0;
432         }
433         return pos;
434 }
435
436
437 static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
438                                     const u8 *ie, size_t ie_len)
439 {
440         struct wpa_ie_data data;
441         int first, ret;
442
443         ret = os_snprintf(pos, end - pos, "[%s-", proto);
444         if (ret < 0 || ret >= end - pos)
445                 return pos;
446         pos += ret;
447
448         if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
449                 ret = os_snprintf(pos, end - pos, "?]");
450                 if (ret < 0 || ret >= end - pos)
451                         return pos;
452                 pos += ret;
453                 return pos;
454         }
455
456         first = 1;
457         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
458                 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
459                 if (ret < 0 || ret >= end - pos)
460                         return pos;
461                 pos += ret;
462                 first = 0;
463         }
464         if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
465                 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
466                 if (ret < 0 || ret >= end - pos)
467                         return pos;
468                 pos += ret;
469                 first = 0;
470         }
471         if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
472                 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
473                 if (ret < 0 || ret >= end - pos)
474                         return pos;
475                 pos += ret;
476                 first = 0;
477         }
478 #ifdef CONFIG_IEEE80211R
479         if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
480                 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
481                                   first ? "" : "+");
482                 if (ret < 0 || ret >= end - pos)
483                         return pos;
484                 pos += ret;
485                 first = 0;
486         }
487         if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
488                 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
489                                   first ? "" : "+");
490                 if (ret < 0 || ret >= end - pos)
491                         return pos;
492                 pos += ret;
493                 first = 0;
494         }
495 #endif /* CONFIG_IEEE80211R */
496
497         pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
498
499         if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
500                 ret = os_snprintf(pos, end - pos, "-preauth");
501                 if (ret < 0 || ret >= end - pos)
502                         return pos;
503                 pos += ret;
504         }
505
506         ret = os_snprintf(pos, end - pos, "]");
507         if (ret < 0 || ret >= end - pos)
508                 return pos;
509         pos += ret;
510
511         return pos;
512 }
513
514
515 /* Format one result on one text line into a buffer. */
516 static int wpa_supplicant_ctrl_iface_scan_result(
517         const struct wpa_scan_res *res, char *buf, size_t buflen)
518 {
519         char *pos, *end;
520         int ret;
521         const u8 *ie, *ie2;
522
523         pos = buf;
524         end = buf + buflen;
525
526         ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
527                           MAC2STR(res->bssid), res->freq, res->level);
528         if (ret < 0 || ret >= end - pos)
529                 return pos - buf;
530         pos += ret;
531         ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
532         if (ie)
533                 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
534         ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
535         if (ie2)
536                 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
537         if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
538                 ret = os_snprintf(pos, end - pos, "[WEP]");
539                 if (ret < 0 || ret >= end - pos)
540                         return pos - buf;
541                 pos += ret;
542         }
543         if (res->caps & IEEE80211_CAP_IBSS) {
544                 ret = os_snprintf(pos, end - pos, "[IBSS]");
545                 if (ret < 0 || ret >= end - pos)
546                         return pos - buf;
547                 pos += ret;
548         }
549
550         ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
551         ret = os_snprintf(pos, end - pos, "\t%s",
552                           ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
553         if (ret < 0 || ret >= end - pos)
554                 return pos - buf;
555         pos += ret;
556
557         ret = os_snprintf(pos, end - pos, "\n");
558         if (ret < 0 || ret >= end - pos)
559                 return pos - buf;
560         pos += ret;
561
562         return pos - buf;
563 }
564
565
566 static int wpa_supplicant_ctrl_iface_scan_results(
567         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
568 {
569         char *pos, *end;
570         struct wpa_scan_res *res;
571         int ret;
572         size_t i;
573
574         if (wpa_s->scan_res == NULL &&
575             wpa_supplicant_get_scan_results(wpa_s) < 0)
576                 return 0;
577
578         pos = buf;
579         end = buf + buflen;
580         ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
581                           "flags / ssid\n");
582         if (ret < 0 || ret >= end - pos)
583                 return pos - buf;
584         pos += ret;
585
586         for (i = 0; i < wpa_s->scan_res->num; i++) {
587                 res = wpa_s->scan_res->res[i];
588                 ret = wpa_supplicant_ctrl_iface_scan_result(res, pos,
589                                                             end - pos);
590                 if (ret < 0 || ret >= end - pos)
591                         return pos - buf;
592                 pos += ret;
593         }
594
595         return pos - buf;
596 }
597
598
599 static int wpa_supplicant_ctrl_iface_select_network(
600         struct wpa_supplicant *wpa_s, char *cmd)
601 {
602         int id;
603         struct wpa_ssid *ssid;
604
605         /* cmd: "<network id>" or "any" */
606         if (os_strcmp(cmd, "any") == 0) {
607                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
608                 ssid = wpa_s->conf->ssid;
609                 while (ssid) {
610                         ssid->disabled = 0;
611                         ssid = ssid->next;
612                 }
613                 wpa_s->reassociate = 1;
614                 wpa_supplicant_req_scan(wpa_s, 0, 0);
615                 return 0;
616         }
617
618         id = atoi(cmd);
619         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
620
621         ssid = wpa_config_get_network(wpa_s->conf, id);
622         if (ssid == NULL) {
623                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
624                            "id=%d", id);
625                 return -1;
626         }
627
628         if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
629                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
630
631         /* Mark all other networks disabled and trigger reassociation */
632         ssid = wpa_s->conf->ssid;
633         while (ssid) {
634                 ssid->disabled = id != ssid->id;
635                 ssid = ssid->next;
636         }
637         wpa_s->reassociate = 1;
638         wpa_supplicant_req_scan(wpa_s, 0, 0);
639
640         return 0;
641 }
642
643
644 static int wpa_supplicant_ctrl_iface_enable_network(
645         struct wpa_supplicant *wpa_s, char *cmd)
646 {
647         int id;
648         struct wpa_ssid *ssid;
649
650         /* cmd: "<network id>" or "all" */
651         if (os_strcmp(cmd, "all") == 0) {
652                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
653                 ssid = wpa_s->conf->ssid;
654                 while (ssid) {
655                         if (ssid == wpa_s->current_ssid && ssid->disabled)
656                                 wpa_s->reassociate = 1;
657                         ssid->disabled = 0;
658                         ssid = ssid->next;
659                 }
660                 if (wpa_s->reassociate)
661                         wpa_supplicant_req_scan(wpa_s, 0, 0);
662                 return 0;
663         }
664
665         id = atoi(cmd);
666         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
667
668         ssid = wpa_config_get_network(wpa_s->conf, id);
669         if (ssid == NULL) {
670                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
671                            "id=%d", id);
672                 return -1;
673         }
674
675         if (wpa_s->current_ssid == NULL && ssid->disabled) {
676                 /*
677                  * Try to reassociate since there is no current configuration
678                  * and a new network was made available. */
679                 wpa_s->reassociate = 1;
680                 wpa_supplicant_req_scan(wpa_s, 0, 0);
681         }
682         ssid->disabled = 0;
683
684         return 0;
685 }
686
687
688 static int wpa_supplicant_ctrl_iface_disable_network(
689         struct wpa_supplicant *wpa_s, char *cmd)
690 {
691         int id;
692         struct wpa_ssid *ssid;
693
694         /* cmd: "<network id>" or "all" */
695         if (os_strcmp(cmd, "all") == 0) {
696                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
697                 ssid = wpa_s->conf->ssid;
698                 while (ssid) {
699                         ssid->disabled = 1;
700                         ssid = ssid->next;
701                 }
702                 if (wpa_s->current_ssid)
703                         wpa_supplicant_disassociate(wpa_s,
704                                                     WLAN_REASON_DEAUTH_LEAVING);
705                 return 0;
706         }
707
708         id = atoi(cmd);
709         wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
710
711         ssid = wpa_config_get_network(wpa_s->conf, id);
712         if (ssid == NULL) {
713                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
714                            "id=%d", id);
715                 return -1;
716         }
717
718         if (ssid == wpa_s->current_ssid)
719                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
720         ssid->disabled = 1;
721
722         return 0;
723 }
724
725
726 static int wpa_supplicant_ctrl_iface_add_network(
727         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
728 {
729         struct wpa_ssid *ssid;
730         int ret;
731
732         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
733
734         ssid = wpa_config_add_network(wpa_s->conf);
735         if (ssid == NULL)
736                 return -1;
737         ssid->disabled = 1;
738         wpa_config_set_network_defaults(ssid);
739
740         ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
741         if (ret < 0 || (size_t) ret >= buflen)
742                 return -1;
743         return ret;
744 }
745
746
747 static int wpa_supplicant_ctrl_iface_remove_network(
748         struct wpa_supplicant *wpa_s, char *cmd)
749 {
750         int id;
751         struct wpa_ssid *ssid;
752
753         /* cmd: "<network id>" or "all" */
754         if (os_strcmp(cmd, "all") == 0) {
755                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
756                 ssid = wpa_s->conf->ssid;
757                 while (ssid) {
758                         id = ssid->id;
759                         ssid = ssid->next;
760                         wpa_config_remove_network(wpa_s->conf, id);
761                 }
762                 if (wpa_s->current_ssid) {
763                         eapol_sm_invalidate_cached_session(wpa_s->eapol);
764                         wpa_supplicant_disassociate(wpa_s,
765                                                     WLAN_REASON_DEAUTH_LEAVING);
766                 }
767                 return 0;
768         }
769
770         id = atoi(cmd);
771         wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
772
773         ssid = wpa_config_get_network(wpa_s->conf, id);
774         if (ssid == NULL ||
775             wpa_config_remove_network(wpa_s->conf, id) < 0) {
776                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
777                            "id=%d", id);
778                 return -1;
779         }
780
781         if (ssid == wpa_s->current_ssid) {
782                 /*
783                  * Invalidate the EAP session cache if the current network is
784                  * removed.
785                  */
786                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
787
788                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
789         }
790
791         return 0;
792 }
793
794
795 static int wpa_supplicant_ctrl_iface_set_network(
796         struct wpa_supplicant *wpa_s, char *cmd)
797 {
798         int id;
799         struct wpa_ssid *ssid;
800         char *name, *value;
801
802         /* cmd: "<network id> <variable name> <value>" */
803         name = os_strchr(cmd, ' ');
804         if (name == NULL)
805                 return -1;
806         *name++ = '\0';
807
808         value = os_strchr(name, ' ');
809         if (value == NULL)
810                 return -1;
811         *value++ = '\0';
812
813         id = atoi(cmd);
814         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
815                    id, name);
816         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
817                               (u8 *) value, os_strlen(value));
818
819         ssid = wpa_config_get_network(wpa_s->conf, id);
820         if (ssid == NULL) {
821                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
822                            "id=%d", id);
823                 return -1;
824         }
825
826         if (wpa_config_set(ssid, name, value, 0) < 0) {
827                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
828                            "variable '%s'", name);
829                 return -1;
830         }
831
832         if (wpa_s->current_ssid == ssid) {
833                 /*
834                  * Invalidate the EAP session cache if anything in the current
835                  * configuration changes.
836                  */
837                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
838         }
839
840         if ((os_strcmp(name, "psk") == 0 &&
841              value[0] == '"' && ssid->ssid_len) ||
842             (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
843                 wpa_config_update_psk(ssid);
844
845         return 0;
846 }
847
848
849 static int wpa_supplicant_ctrl_iface_get_network(
850         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
851 {
852         int id;
853         size_t res;
854         struct wpa_ssid *ssid;
855         char *name, *value;
856
857         /* cmd: "<network id> <variable name>" */
858         name = os_strchr(cmd, ' ');
859         if (name == NULL || buflen == 0)
860                 return -1;
861         *name++ = '\0';
862
863         id = atoi(cmd);
864         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
865                    id, name);
866
867         ssid = wpa_config_get_network(wpa_s->conf, id);
868         if (ssid == NULL) {
869                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
870                            "id=%d", id);
871                 return -1;
872         }
873
874         value = wpa_config_get_no_key(ssid, name);
875         if (value == NULL) {
876                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
877                            "variable '%s'", name);
878                 return -1;
879         }
880
881         res = os_strlcpy(buf, value, buflen);
882         if (res >= buflen) {
883                 os_free(value);
884                 return -1;
885         }
886
887         os_free(value);
888
889         return res;
890 }
891
892
893 #ifndef CONFIG_NO_CONFIG_WRITE
894 static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
895 {
896         int ret;
897
898         if (!wpa_s->conf->update_config) {
899                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
900                            "to update configuration (update_config=0)");
901                 return -1;
902         }
903
904         ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
905         if (ret) {
906                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
907                            "update configuration");
908         } else {
909                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
910                            " updated");
911         }
912
913         return ret;
914 }
915 #endif /* CONFIG_NO_CONFIG_WRITE */
916
917
918 static int ctrl_iface_get_capability_pairwise(int res, char *strict,
919                                               struct wpa_driver_capa *capa,
920                                               char *buf, size_t buflen)
921 {
922         int ret, first = 1;
923         char *pos, *end;
924         size_t len;
925
926         pos = buf;
927         end = pos + buflen;
928
929         if (res < 0) {
930                 if (strict)
931                         return 0;
932                 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
933                 if (len >= buflen)
934                         return -1;
935                 return len;
936         }
937
938         if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
939                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
940                 if (ret < 0 || ret >= end - pos)
941                         return pos - buf;
942                 pos += ret;
943                 first = 0;
944         }
945
946         if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
947                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
948                 if (ret < 0 || ret >= end - pos)
949                         return pos - buf;
950                 pos += ret;
951                 first = 0;
952         }
953
954         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
955                 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
956                 if (ret < 0 || ret >= end - pos)
957                         return pos - buf;
958                 pos += ret;
959                 first = 0;
960         }
961
962         return pos - buf;
963 }
964
965
966 static int ctrl_iface_get_capability_group(int res, char *strict,
967                                            struct wpa_driver_capa *capa,
968                                            char *buf, size_t buflen)
969 {
970         int ret, first = 1;
971         char *pos, *end;
972         size_t len;
973
974         pos = buf;
975         end = pos + buflen;
976
977         if (res < 0) {
978                 if (strict)
979                         return 0;
980                 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
981                 if (len >= buflen)
982                         return -1;
983                 return len;
984         }
985
986         if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
987                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
988                 if (ret < 0 || ret >= end - pos)
989                         return pos - buf;
990                 pos += ret;
991                 first = 0;
992         }
993
994         if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
995                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
996                 if (ret < 0 || ret >= end - pos)
997                         return pos - buf;
998                 pos += ret;
999                 first = 0;
1000         }
1001
1002         if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1003                 ret = os_snprintf(pos, end - pos, "%sWEP104",
1004                                   first ? "" : " ");
1005                 if (ret < 0 || ret >= end - pos)
1006                         return pos - buf;
1007                 pos += ret;
1008                 first = 0;
1009         }
1010
1011         if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1012                 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
1013                 if (ret < 0 || ret >= end - pos)
1014                         return pos - buf;
1015                 pos += ret;
1016                 first = 0;
1017         }
1018
1019         return pos - buf;
1020 }
1021
1022
1023 static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
1024                                               struct wpa_driver_capa *capa,
1025                                               char *buf, size_t buflen)
1026 {
1027         int ret;
1028         char *pos, *end;
1029         size_t len;
1030
1031         pos = buf;
1032         end = pos + buflen;
1033
1034         if (res < 0) {
1035                 if (strict)
1036                         return 0;
1037                 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
1038                                  "NONE", buflen);
1039                 if (len >= buflen)
1040                         return -1;
1041                 return len;
1042         }
1043
1044         ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1045         if (ret < 0 || ret >= end - pos)
1046                 return pos - buf;
1047         pos += ret;
1048
1049         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1050                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1051                 ret = os_snprintf(pos, end - pos, " WPA-EAP");
1052                 if (ret < 0 || ret >= end - pos)
1053                         return pos - buf;
1054                 pos += ret;
1055         }
1056
1057         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1058                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1059                 ret = os_snprintf(pos, end - pos, " WPA-PSK");
1060                 if (ret < 0 || ret >= end - pos)
1061                         return pos - buf;
1062                 pos += ret;
1063         }
1064
1065         if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1066                 ret = os_snprintf(pos, end - pos, " WPA-NONE");
1067                 if (ret < 0 || ret >= end - pos)
1068                         return pos - buf;
1069                 pos += ret;
1070         }
1071
1072         return pos - buf;
1073 }
1074
1075
1076 static int ctrl_iface_get_capability_proto(int res, char *strict,
1077                                            struct wpa_driver_capa *capa,
1078                                            char *buf, size_t buflen)
1079 {
1080         int ret, first = 1;
1081         char *pos, *end;
1082         size_t len;
1083
1084         pos = buf;
1085         end = pos + buflen;
1086
1087         if (res < 0) {
1088                 if (strict)
1089                         return 0;
1090                 len = os_strlcpy(buf, "RSN WPA", buflen);
1091                 if (len >= buflen)
1092                         return -1;
1093                 return len;
1094         }
1095
1096         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1097                               WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1098                 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
1099                 if (ret < 0 || ret >= end - pos)
1100                         return pos - buf;
1101                 pos += ret;
1102                 first = 0;
1103         }
1104
1105         if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1106                               WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1107                 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
1108                 if (ret < 0 || ret >= end - pos)
1109                         return pos - buf;
1110                 pos += ret;
1111                 first = 0;
1112         }
1113
1114         return pos - buf;
1115 }
1116
1117
1118 static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
1119                                               struct wpa_driver_capa *capa,
1120                                               char *buf, size_t buflen)
1121 {
1122         int ret, first = 1;
1123         char *pos, *end;
1124         size_t len;
1125
1126         pos = buf;
1127         end = pos + buflen;
1128
1129         if (res < 0) {
1130                 if (strict)
1131                         return 0;
1132                 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
1133                 if (len >= buflen)
1134                         return -1;
1135                 return len;
1136         }
1137
1138         if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
1139                 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
1140                 if (ret < 0 || ret >= end - pos)
1141                         return pos - buf;
1142                 pos += ret;
1143                 first = 0;
1144         }
1145
1146         if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
1147                 ret = os_snprintf(pos, end - pos, "%sSHARED",
1148                                   first ? "" : " ");
1149                 if (ret < 0 || ret >= end - pos)
1150                         return pos - buf;
1151                 pos += ret;
1152                 first = 0;
1153         }
1154
1155         if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
1156                 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
1157                 if (ret < 0 || ret >= end - pos)
1158                         return pos - buf;
1159                 pos += ret;
1160                 first = 0;
1161         }
1162
1163         return pos - buf;
1164 }
1165
1166
1167 static int wpa_supplicant_ctrl_iface_get_capability(
1168         struct wpa_supplicant *wpa_s, const char *_field, char *buf,
1169         size_t buflen)
1170 {
1171         struct wpa_driver_capa capa;
1172         int res;
1173         char *strict;
1174         char field[30];
1175         size_t len;
1176
1177         /* Determine whether or not strict checking was requested */
1178         len = os_strlcpy(field, _field, sizeof(field));
1179         if (len >= sizeof(field))
1180                 return -1;
1181         strict = os_strchr(field, ' ');
1182         if (strict != NULL) {
1183                 *strict++ = '\0';
1184                 if (os_strcmp(strict, "strict") != 0)
1185                         return -1;
1186         }
1187
1188         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
1189                 field, strict ? strict : "");
1190
1191         if (os_strcmp(field, "eap") == 0) {
1192                 return eap_get_names(buf, buflen);
1193         }
1194
1195         res = wpa_drv_get_capa(wpa_s, &capa);
1196
1197         if (os_strcmp(field, "pairwise") == 0)
1198                 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
1199                                                           buf, buflen);
1200
1201         if (os_strcmp(field, "group") == 0)
1202                 return ctrl_iface_get_capability_group(res, strict, &capa,
1203                                                        buf, buflen);
1204
1205         if (os_strcmp(field, "key_mgmt") == 0)
1206                 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
1207                                                           buf, buflen);
1208
1209         if (os_strcmp(field, "proto") == 0)
1210                 return ctrl_iface_get_capability_proto(res, strict, &capa,
1211                                                        buf, buflen);
1212
1213         if (os_strcmp(field, "auth_alg") == 0)
1214                 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
1215                                                           buf, buflen);
1216
1217         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1218                    field);
1219
1220         return -1;
1221 }
1222
1223
1224 static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
1225                                          const char *cmd, char *buf,
1226                                          size_t buflen)
1227 {
1228         u8 bssid[ETH_ALEN];
1229         size_t i;
1230         struct wpa_scan_results *results;
1231         struct wpa_scan_res *bss;
1232         int ret;
1233         char *pos, *end;
1234         const u8 *ie, *ie2;
1235
1236         results = wpa_s->scan_res;
1237         if (results == NULL)
1238                 return 0;
1239
1240         if (hwaddr_aton(cmd, bssid) == 0) {
1241                 for (i = 0; i < results->num; i++) {
1242                         if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN)
1243                             == 0)
1244                                 break;
1245                 }
1246         } else
1247                 i = atoi(cmd);
1248
1249         if (i >= results->num || results->res[i] == NULL)
1250                 return 0; /* no match found */
1251
1252         bss = results->res[i];
1253         pos = buf;
1254         end = buf + buflen;
1255         ret = snprintf(pos, end - pos,
1256                        "bssid=" MACSTR "\n"
1257                        "freq=%d\n"
1258                        "beacon_int=%d\n"
1259                        "capabilities=0x%04x\n"
1260                        "qual=%d\n"
1261                        "noise=%d\n"
1262                        "level=%d\n"
1263                        "tsf=%016llu\n"
1264                        "ie=",
1265                        MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
1266                        bss->caps, bss->qual, bss->noise, bss->level,
1267                        (unsigned long long) bss->tsf);
1268         if (ret < 0 || ret >= end - pos)
1269                 return pos - buf;
1270         pos += ret;
1271
1272         ie = (const u8 *) (bss + 1);
1273         for (i = 0; i < bss->ie_len; i++) {
1274                 ret = snprintf(pos, end - pos, "%02x", *ie++);
1275                 if (ret < 0 || ret >= end - pos)
1276                         return pos - buf;
1277                 pos += ret;
1278         }
1279
1280         ret = snprintf(pos, end - pos, "\n");
1281         if (ret < 0 || ret >= end - pos)
1282                 return pos - buf;
1283         pos += ret;
1284
1285         ret = os_snprintf(pos, end - pos, "flags=");
1286         if (ret < 0 || ret >= end - pos)
1287                 return pos - buf;
1288         pos += ret;
1289
1290         ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1291         if (ie)
1292                 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1293         ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN);
1294         if (ie2)
1295                 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1296         if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1297                 ret = os_snprintf(pos, end - pos, "[WEP]");
1298                 if (ret < 0 || ret >= end - pos)
1299                         return pos - buf;
1300                 pos += ret;
1301         }
1302         if (bss->caps & IEEE80211_CAP_IBSS) {
1303                 ret = os_snprintf(pos, end - pos, "[IBSS]");
1304                 if (ret < 0 || ret >= end - pos)
1305                         return pos - buf;
1306                 pos += ret;
1307         }
1308
1309         ret = snprintf(pos, end - pos, "\n");
1310         if (ret < 0 || ret >= end - pos)
1311                 return pos - buf;
1312         pos += ret;
1313
1314         ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
1315         ret = os_snprintf(pos, end - pos, "ssid=%s\n",
1316                           ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
1317         if (ret < 0 || ret >= end - pos)
1318                 return pos - buf;
1319         pos += ret;
1320
1321         return pos - buf;
1322 }
1323
1324
1325 static int wpa_supplicant_ctrl_iface_ap_scan(
1326         struct wpa_supplicant *wpa_s, char *cmd)
1327 {
1328         int ap_scan = atoi(cmd);
1329
1330         if (ap_scan < 0 || ap_scan > 2)
1331                 return -1;
1332         wpa_s->conf->ap_scan = ap_scan;
1333         return 0;
1334 }
1335
1336
1337 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1338                                          char *buf, size_t *resp_len)
1339 {
1340         char *reply;
1341         const int reply_size = 2048;
1342         int ctrl_rsp = 0;
1343         int reply_len;
1344
1345         if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1346             os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1347                 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1348                                       (const u8 *) buf, os_strlen(buf));
1349         } else {
1350                 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1351                                   (const u8 *) buf, os_strlen(buf));
1352         }
1353
1354         reply = os_malloc(reply_size);
1355         if (reply == NULL) {
1356                 *resp_len = 1;
1357                 return NULL;
1358         }
1359
1360         os_memcpy(reply, "OK\n", 3);
1361         reply_len = 3;
1362
1363         if (os_strcmp(buf, "PING") == 0) {
1364                 os_memcpy(reply, "PONG\n", 5);
1365                 reply_len = 5;
1366         } else if (os_strcmp(buf, "MIB") == 0) {
1367                 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1368                 if (reply_len >= 0) {
1369                         int res;
1370                         res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1371                                                reply_size - reply_len);
1372                         if (res < 0)
1373                                 reply_len = -1;
1374                         else
1375                                 reply_len += res;
1376                 }
1377         } else if (os_strncmp(buf, "STATUS", 6) == 0) {
1378                 reply_len = wpa_supplicant_ctrl_iface_status(
1379                         wpa_s, buf + 6, reply, reply_size);
1380         } else if (os_strcmp(buf, "PMKSA") == 0) {
1381                 reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
1382         } else if (os_strncmp(buf, "SET ", 4) == 0) {
1383                 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1384                         reply_len = -1;
1385         } else if (os_strcmp(buf, "LOGON") == 0) {
1386                 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1387         } else if (os_strcmp(buf, "LOGOFF") == 0) {
1388                 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1389         } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
1390                 wpa_s->disconnected = 0;
1391                 wpa_s->reassociate = 1;
1392                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1393         } else if (os_strcmp(buf, "RECONNECT") == 0) {
1394                 if (wpa_s->disconnected) {
1395                         wpa_s->disconnected = 0;
1396                         wpa_s->reassociate = 1;
1397                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1398                 }
1399 #ifdef IEEE8021X_EAPOL
1400         } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1401                 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1402                         reply_len = -1;
1403 #endif /* IEEE8021X_EAPOL */
1404 #ifdef CONFIG_PEERKEY
1405         } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1406                 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1407                         reply_len = -1;
1408 #endif /* CONFIG_PEERKEY */
1409 #ifdef CONFIG_IEEE80211R
1410         } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
1411                 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
1412                         reply_len = -1;
1413 #endif /* CONFIG_IEEE80211R */
1414         } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1415         {
1416                 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1417                             wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1418                         reply_len = -1;
1419                 else
1420                         ctrl_rsp = 1;
1421         } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1422                 if (wpa_supplicant_reload_configuration(wpa_s))
1423                         reply_len = -1;
1424         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1425                 eloop_terminate();
1426         } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1427                 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1428                         reply_len = -1;
1429         } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1430                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
1431                         wpa_s, reply, reply_size);
1432         } else if (os_strcmp(buf, "DISCONNECT") == 0) {
1433                 wpa_s->reassociate = 0;
1434                 wpa_s->disconnected = 1;
1435                 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1436         } else if (os_strcmp(buf, "SCAN") == 0) {
1437                 wpa_s->scan_req = 2;
1438                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1439         } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1440                 reply_len = wpa_supplicant_ctrl_iface_scan_results(
1441                         wpa_s, reply, reply_size);
1442         } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1443                 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1444                         reply_len = -1;
1445         } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1446                 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1447                         reply_len = -1;
1448         } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1449                 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1450                         reply_len = -1;
1451         } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1452                 reply_len = wpa_supplicant_ctrl_iface_add_network(
1453                         wpa_s, reply, reply_size);
1454         } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1455                 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1456                         reply_len = -1;
1457         } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1458                 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1459                         reply_len = -1;
1460         } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1461                 reply_len = wpa_supplicant_ctrl_iface_get_network(
1462                         wpa_s, buf + 12, reply, reply_size);
1463 #ifndef CONFIG_NO_CONFIG_WRITE
1464         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1465                 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1466                         reply_len = -1;
1467 #endif /* CONFIG_NO_CONFIG_WRITE */
1468         } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1469                 reply_len = wpa_supplicant_ctrl_iface_get_capability(
1470                         wpa_s, buf + 15, reply, reply_size);
1471         } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1472                 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1473                         reply_len = -1;
1474         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1475                 reply_len = wpa_supplicant_global_iface_interfaces(
1476                         wpa_s->global, reply, reply_size);
1477         } else if (os_strncmp(buf, "BSS ", 4) == 0) {
1478                 reply_len = wpa_supplicant_ctrl_iface_bss(
1479                         wpa_s, buf + 4, reply, reply_size);
1480         } else {
1481                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1482                 reply_len = 16;
1483         }
1484
1485         if (reply_len < 0) {
1486                 os_memcpy(reply, "FAIL\n", 5);
1487                 reply_len = 5;
1488         }
1489
1490         if (ctrl_rsp)
1491                 eapol_sm_notify_ctrl_response(wpa_s->eapol);
1492
1493         *resp_len = reply_len;
1494         return reply;
1495 }
1496
1497
1498 static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1499                                            char *cmd)
1500 {
1501         struct wpa_interface iface;
1502         char *pos;
1503
1504         /*
1505          * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1506          * TAB<bridge_ifname>
1507          */
1508         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1509
1510         os_memset(&iface, 0, sizeof(iface));
1511
1512         do {
1513                 iface.ifname = pos = cmd;
1514                 pos = os_strchr(pos, '\t');
1515                 if (pos)
1516                         *pos++ = '\0';
1517                 if (iface.ifname[0] == '\0')
1518                         return -1;
1519                 if (pos == NULL)
1520                         break;
1521
1522                 iface.confname = pos;
1523                 pos = os_strchr(pos, '\t');
1524                 if (pos)
1525                         *pos++ = '\0';
1526                 if (iface.confname[0] == '\0')
1527                         iface.confname = NULL;
1528                 if (pos == NULL)
1529                         break;
1530
1531                 iface.driver = pos;
1532                 pos = os_strchr(pos, '\t');
1533                 if (pos)
1534                         *pos++ = '\0';
1535                 if (iface.driver[0] == '\0')
1536                         iface.driver = NULL;
1537                 if (pos == NULL)
1538                         break;
1539
1540                 iface.ctrl_interface = pos;
1541                 pos = os_strchr(pos, '\t');
1542                 if (pos)
1543                         *pos++ = '\0';
1544                 if (iface.ctrl_interface[0] == '\0')
1545                         iface.ctrl_interface = NULL;
1546                 if (pos == NULL)
1547                         break;
1548
1549                 iface.driver_param = pos;
1550                 pos = os_strchr(pos, '\t');
1551                 if (pos)
1552                         *pos++ = '\0';
1553                 if (iface.driver_param[0] == '\0')
1554                         iface.driver_param = NULL;
1555                 if (pos == NULL)
1556                         break;
1557
1558                 iface.bridge_ifname = pos;
1559                 pos = os_strchr(pos, '\t');
1560                 if (pos)
1561                         *pos++ = '\0';
1562                 if (iface.bridge_ifname[0] == '\0')
1563                         iface.bridge_ifname = NULL;
1564                 if (pos == NULL)
1565                         break;
1566         } while (0);
1567
1568         if (wpa_supplicant_get_iface(global, iface.ifname))
1569                 return -1;
1570
1571         return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1572 }
1573
1574
1575 static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1576                                               char *cmd)
1577 {
1578         struct wpa_supplicant *wpa_s;
1579
1580         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1581
1582         wpa_s = wpa_supplicant_get_iface(global, cmd);
1583         if (wpa_s == NULL)
1584                 return -1;
1585         return wpa_supplicant_remove_iface(global, wpa_s);
1586 }
1587
1588
1589 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1590                                                   char *buf, int len)
1591 {
1592         int res;
1593         char *pos, *end;
1594         struct wpa_supplicant *wpa_s;
1595
1596         wpa_s = global->ifaces;
1597         pos = buf;
1598         end = buf + len;
1599
1600         while (wpa_s) {
1601                 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1602                 if (res < 0 || res >= end - pos) {
1603                         *pos = '\0';
1604                         break;
1605                 }
1606                 pos += res;
1607                 wpa_s = wpa_s->next;
1608         }
1609         return pos - buf;
1610 }
1611
1612
1613 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1614                                                 char *buf, size_t *resp_len)
1615 {
1616         char *reply;
1617         const int reply_size = 2048;
1618         int reply_len;
1619
1620         wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1621                           (const u8 *) buf, os_strlen(buf));
1622
1623         reply = os_malloc(reply_size);
1624         if (reply == NULL) {
1625                 *resp_len = 1;
1626                 return NULL;
1627         }
1628
1629         os_memcpy(reply, "OK\n", 3);
1630         reply_len = 3;
1631
1632         if (os_strcmp(buf, "PING") == 0) {
1633                 os_memcpy(reply, "PONG\n", 5);
1634                 reply_len = 5;
1635         } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1636                 if (wpa_supplicant_global_iface_add(global, buf + 14))
1637                         reply_len = -1;
1638         } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1639                 if (wpa_supplicant_global_iface_remove(global, buf + 17))
1640                         reply_len = -1;
1641         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1642                 reply_len = wpa_supplicant_global_iface_interfaces(
1643                         global, reply, reply_size);
1644         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1645                 eloop_terminate();
1646         } else {
1647                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1648                 reply_len = 16;
1649         }
1650
1651         if (reply_len < 0) {
1652                 os_memcpy(reply, "FAIL\n", 5);
1653                 reply_len = 5;
1654         }
1655
1656         *resp_len = reply_len;
1657         return reply;
1658 }