]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/ctrl_iface.c
update to 0.5.11: some useful bug fixes (check ChangeLog)
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / ctrl_iface.c
1 /*
2  * WPA Supplicant / Control interface (shared code for all backends)
3  * Copyright (c) 2004-2006, 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 "wpa_supplicant.h"
21 #include "config.h"
22 #include "eapol_sm.h"
23 #include "wpa_supplicant_i.h"
24 #include "ctrl_iface.h"
25 #include "l2_packet.h"
26 #include "preauth.h"
27 #include "pmksa_cache.h"
28 #include "wpa_ctrl.h"
29 #include "eap.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
85         if (hwaddr_aton(addr, bssid)) {
86                 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
87                            "'%s'", addr);
88                 return -1;
89         }
90
91         wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
92         rsn_preauth_deinit(wpa_s->wpa);
93         if (rsn_preauth_init(wpa_s->wpa, bssid, wpa_s->current_ssid))
94                 return -1;
95
96         return 0;
97 }
98 #endif /* IEEE8021X_EAPOL */
99
100
101 #ifdef CONFIG_PEERKEY
102 /* MLME-STKSTART.request(peer) */
103 static int wpa_supplicant_ctrl_iface_stkstart(
104         struct wpa_supplicant *wpa_s, char *addr)
105 {
106         u8 peer[ETH_ALEN];
107
108         if (hwaddr_aton(addr, peer)) {
109                 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
110                            "address '%s'", peer);
111                 return -1;
112         }
113
114         wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
115                    MAC2STR(peer));
116
117         return wpa_sm_stkstart(wpa_s->wpa, peer);
118 }
119 #endif /* CONFIG_PEERKEY */
120
121
122 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
123                                               char *rsp)
124 {
125 #ifdef IEEE8021X_EAPOL
126         char *pos, *id_pos;
127         int id;
128         struct wpa_ssid *ssid;
129
130         pos = os_strchr(rsp, '-');
131         if (pos == NULL)
132                 return -1;
133         *pos++ = '\0';
134         id_pos = pos;
135         pos = os_strchr(pos, ':');
136         if (pos == NULL)
137                 return -1;
138         *pos++ = '\0';
139         id = atoi(id_pos);
140         wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
141         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
142                               (u8 *) pos, os_strlen(pos));
143
144         ssid = wpa_config_get_network(wpa_s->conf, id);
145         if (ssid == NULL) {
146                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
147                            "to update", id);
148                 return -1;
149         }
150
151         if (os_strcmp(rsp, "IDENTITY") == 0) {
152                 os_free(ssid->identity);
153                 ssid->identity = (u8 *) os_strdup(pos);
154                 ssid->identity_len = os_strlen(pos);
155                 ssid->pending_req_identity = 0;
156                 if (ssid == wpa_s->current_ssid)
157                         wpa_s->reassociate = 1;
158         } else if (os_strcmp(rsp, "PASSWORD") == 0) {
159                 os_free(ssid->password);
160                 ssid->password = (u8 *) os_strdup(pos);
161                 ssid->password_len = os_strlen(pos);
162                 ssid->pending_req_password = 0;
163                 if (ssid == wpa_s->current_ssid)
164                         wpa_s->reassociate = 1;
165         } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
166                 os_free(ssid->new_password);
167                 ssid->new_password = (u8 *) os_strdup(pos);
168                 ssid->new_password_len = os_strlen(pos);
169                 ssid->pending_req_new_password = 0;
170                 if (ssid == wpa_s->current_ssid)
171                         wpa_s->reassociate = 1;
172         } else if (os_strcmp(rsp, "PIN") == 0) {
173                 os_free(ssid->pin);
174                 ssid->pin = os_strdup(pos);
175                 ssid->pending_req_pin = 0;
176                 if (ssid == wpa_s->current_ssid)
177                         wpa_s->reassociate = 1;
178         } else if (os_strcmp(rsp, "OTP") == 0) {
179                 os_free(ssid->otp);
180                 ssid->otp = (u8 *) os_strdup(pos);
181                 ssid->otp_len = os_strlen(pos);
182                 os_free(ssid->pending_req_otp);
183                 ssid->pending_req_otp = NULL;
184                 ssid->pending_req_otp_len = 0;
185         } else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
186                 os_free(ssid->private_key_passwd);
187                 ssid->private_key_passwd = (u8 *) os_strdup(pos);
188                 ssid->pending_req_passphrase = 0;
189                 if (ssid == wpa_s->current_ssid)
190                         wpa_s->reassociate = 1;
191         } else {
192                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
193                 return -1;
194         }
195
196         return 0;
197 #else /* IEEE8021X_EAPOL */
198         wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
199         return -1;
200 #endif /* IEEE8021X_EAPOL */
201 }
202
203
204 static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
205                                             const char *params,
206                                             char *buf, size_t buflen)
207 {
208         char *pos, *end, tmp[30];
209         int res, verbose, ret;
210
211         verbose = os_strcmp(params, "-VERBOSE") == 0;
212         pos = buf;
213         end = buf + buflen;
214         if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
215                 struct wpa_ssid *ssid = wpa_s->current_ssid;
216                 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
217                                   MAC2STR(wpa_s->bssid));
218                 if (ret < 0 || ret >= end - pos)
219                         return pos - buf;
220                 pos += ret;
221                 if (ssid) {
222                         u8 *_ssid = ssid->ssid;
223                         size_t ssid_len = ssid->ssid_len;
224                         u8 ssid_buf[MAX_SSID_LEN];
225                         if (ssid_len == 0) {
226                                 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
227                                 if (_res < 0)
228                                         ssid_len = 0;
229                                 else
230                                         ssid_len = _res;
231                                 _ssid = ssid_buf;
232                         }
233                         ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
234                                           wpa_ssid_txt(_ssid, ssid_len),
235                                           ssid->id);
236                         if (ret < 0 || ret >= end - pos)
237                                 return pos - buf;
238                         pos += ret;
239
240                         if (ssid->id_str) {
241                                 ret = os_snprintf(pos, end - pos,
242                                                   "id_str=%s\n",
243                                                   ssid->id_str);
244                                 if (ret < 0 || ret >= end - pos)
245                                         return pos - buf;
246                                 pos += ret;
247                         }
248                 }
249
250                 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
251         }
252         ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
253                           wpa_supplicant_state_txt(wpa_s->wpa_state));
254         if (ret < 0 || ret >= end - pos)
255                 return pos - buf;
256         pos += ret;
257
258         if (wpa_s->l2 &&
259             l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
260                 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
261                 if (ret < 0 || ret >= end - pos)
262                         return pos - buf;
263                 pos += ret;
264         }
265
266         if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
267             wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
268                 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
269                                           verbose);
270                 if (res >= 0)
271                         pos += res;
272         }
273
274         res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
275         if (res >= 0)
276                 pos += res;
277
278         return pos - buf;
279 }
280
281
282 static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
283                                            char *cmd)
284 {
285         char *pos;
286         int id;
287         struct wpa_ssid *ssid;
288         u8 bssid[ETH_ALEN];
289
290         /* cmd: "<network id> <BSSID>" */
291         pos = os_strchr(cmd, ' ');
292         if (pos == NULL)
293                 return -1;
294         *pos++ = '\0';
295         id = atoi(cmd);
296         wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
297         if (hwaddr_aton(pos, bssid)) {
298                 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
299                 return -1;
300         }
301
302         ssid = wpa_config_get_network(wpa_s->conf, id);
303         if (ssid == NULL) {
304                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
305                            "to update", id);
306                 return -1;
307         }
308
309         os_memcpy(ssid->bssid, bssid, ETH_ALEN);
310         ssid->bssid_set =
311                 os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
312                 
313
314         return 0;
315 }
316
317
318 static int wpa_supplicant_ctrl_iface_list_networks(
319         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
320 {
321         char *pos, *end;
322         struct wpa_ssid *ssid;
323         int ret;
324
325         pos = buf;
326         end = buf + buflen;
327         ret = os_snprintf(pos, end - pos,
328                           "network id / ssid / bssid / flags\n");
329         if (ret < 0 || ret >= end - pos)
330                 return pos - buf;
331         pos += ret;
332
333         ssid = wpa_s->conf->ssid;
334         while (ssid) {
335                 ret = os_snprintf(pos, end - pos, "%d\t%s",
336                                   ssid->id,
337                                   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
338                 if (ret < 0 || ret >= end - pos)
339                         return pos - buf;
340                 pos += ret;
341                 if (ssid->bssid_set) {
342                         ret = os_snprintf(pos, end - pos, "\t" MACSTR,
343                                           MAC2STR(ssid->bssid));
344                 } else {
345                         ret = os_snprintf(pos, end - pos, "\tany");
346                 }
347                 if (ret < 0 || ret >= end - pos)
348                         return pos - buf;
349                 pos += ret;
350                 ret = os_snprintf(pos, end - pos, "\t%s%s",
351                                   ssid == wpa_s->current_ssid ?
352                                   "[CURRENT]" : "",
353                                   ssid->disabled ? "[DISABLED]" : "");
354                 if (ret < 0 || ret >= end - pos)
355                         return pos - buf;
356                 pos += ret;
357                 ret = os_snprintf(pos, end - pos, "\n");
358                 if (ret < 0 || ret >= end - pos)
359                         return pos - buf;
360                 pos += ret;
361
362                 ssid = ssid->next;
363         }
364
365         return pos - buf;
366 }
367
368
369 static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
370 {
371         int first = 1, ret;
372         ret = os_snprintf(pos, end - pos, "-");
373         if (ret < 0 || ret >= end - pos)
374                 return pos;
375         pos += ret;
376         if (cipher & WPA_CIPHER_NONE) {
377                 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
378                 if (ret < 0 || ret >= end - pos)
379                         return pos;
380                 pos += ret;
381                 first = 0;
382         }
383         if (cipher & WPA_CIPHER_WEP40) {
384                 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
385                 if (ret < 0 || ret >= end - pos)
386                         return pos;
387                 pos += ret;
388                 first = 0;
389         }
390         if (cipher & WPA_CIPHER_WEP104) {
391                 ret = os_snprintf(pos, end - pos, "%sWEP104",
392                                   first ? "" : "+");
393                 if (ret < 0 || ret >= end - pos)
394                         return pos;
395                 pos += ret;
396                 first = 0;
397         }
398         if (cipher & WPA_CIPHER_TKIP) {
399                 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
400                 if (ret < 0 || ret >= end - pos)
401                         return pos;
402                 pos += ret;
403                 first = 0;
404         }
405         if (cipher & WPA_CIPHER_CCMP) {
406                 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
407                 if (ret < 0 || ret >= end - pos)
408                         return pos;
409                 pos += ret;
410                 first = 0;
411         }
412         return pos;
413 }
414
415
416 static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
417                                     const u8 *ie, size_t ie_len)
418 {
419         struct wpa_ie_data data;
420         int first, ret;
421
422         ret = os_snprintf(pos, end - pos, "[%s-", proto);
423         if (ret < 0 || ret >= end - pos)
424                 return pos;
425         pos += ret;
426
427         if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
428                 ret = os_snprintf(pos, end - pos, "?]");
429                 if (ret < 0 || ret >= end - pos)
430                         return pos;
431                 pos += ret;
432                 return pos;
433         }
434
435         first = 1;
436         if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
437                 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
438                 if (ret < 0 || ret >= end - pos)
439                         return pos;
440                 pos += ret;
441                 first = 0;
442         }
443         if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
444                 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
445                 if (ret < 0 || ret >= end - pos)
446                         return pos;
447                 pos += ret;
448                 first = 0;
449         }
450         if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
451                 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
452                 if (ret < 0 || ret >= end - pos)
453                         return pos;
454                 pos += ret;
455                 first = 0;
456         }
457
458         pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
459
460         if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
461                 ret = os_snprintf(pos, end - pos, "-preauth");
462                 if (ret < 0 || ret >= end - pos)
463                         return pos;
464                 pos += ret;
465         }
466
467         ret = os_snprintf(pos, end - pos, "]");
468         if (ret < 0 || ret >= end - pos)
469                 return pos;
470         pos += ret;
471
472         return pos;
473 }
474
475
476 static int wpa_supplicant_ctrl_iface_scan_results(
477         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
478 {
479         char *pos, *end;
480         struct wpa_scan_result *res;
481         int i, ret;
482
483         if (wpa_s->scan_results == NULL &&
484             wpa_supplicant_get_scan_results(wpa_s) < 0)
485                 return 0;
486         if (wpa_s->scan_results == NULL)
487                 return 0;
488
489         pos = buf;
490         end = buf + buflen;
491         ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
492                           "flags / ssid\n");
493         if (ret < 0 || ret >= end - pos)
494                 return pos - buf;
495         pos += ret;
496
497         for (i = 0; i < wpa_s->num_scan_results; i++) {
498                 res = &wpa_s->scan_results[i];
499                 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
500                                   MAC2STR(res->bssid), res->freq, res->level);
501                 if (ret < 0 || ret >= end - pos)
502                         return pos - buf;
503                 pos += ret;
504                 if (res->wpa_ie_len) {
505                         pos = wpa_supplicant_ie_txt(pos, end, "WPA",
506                                                     res->wpa_ie,
507                                                     res->wpa_ie_len);
508                 }
509                 if (res->rsn_ie_len) {
510                         pos = wpa_supplicant_ie_txt(pos, end, "WPA2",
511                                                     res->rsn_ie,
512                                                     res->rsn_ie_len);
513                 }
514                 if (!res->wpa_ie_len && !res->rsn_ie_len &&
515                     res->caps & IEEE80211_CAP_PRIVACY) {
516                         ret = os_snprintf(pos, end - pos, "[WEP]");
517                         if (ret < 0 || ret >= end - pos)
518                                 return pos - buf;
519                         pos += ret;
520                 }
521                 if (res->caps & IEEE80211_CAP_IBSS) {
522                         ret = os_snprintf(pos, end - pos, "[IBSS]");
523                         if (ret < 0 || ret >= end - pos)
524                                 return pos - buf;
525                         pos += ret;
526                 }
527
528                 ret = os_snprintf(pos, end - pos, "\t%s",
529                                   wpa_ssid_txt(res->ssid, res->ssid_len));
530                 if (ret < 0 || ret >= end - pos)
531                         return pos - buf;
532                 pos += ret;
533
534                 ret = os_snprintf(pos, end - pos, "\n");
535                 if (ret < 0 || ret >= end - pos)
536                         return pos - buf;
537                 pos += ret;
538         }
539
540         return pos - buf;
541 }
542
543
544 static int wpa_supplicant_ctrl_iface_select_network(
545         struct wpa_supplicant *wpa_s, char *cmd)
546 {
547         int id;
548         struct wpa_ssid *ssid;
549
550         /* cmd: "<network id>" or "any" */
551         if (os_strcmp(cmd, "any") == 0) {
552                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
553                 ssid = wpa_s->conf->ssid;
554                 while (ssid) {
555                         ssid->disabled = 0;
556                         ssid = ssid->next;
557                 }
558                 wpa_s->reassociate = 1;
559                 wpa_supplicant_req_scan(wpa_s, 0, 0);
560                 return 0;
561         }
562
563         id = atoi(cmd);
564         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
565
566         ssid = wpa_config_get_network(wpa_s->conf, id);
567         if (ssid == NULL) {
568                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
569                            "id=%d", id);
570                 return -1;
571         }
572
573         if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
574                 wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
575
576         /* Mark all other networks disabled and trigger reassociation */
577         ssid = wpa_s->conf->ssid;
578         while (ssid) {
579                 ssid->disabled = id != ssid->id;
580                 ssid = ssid->next;
581         }
582         wpa_s->reassociate = 1;
583         wpa_supplicant_req_scan(wpa_s, 0, 0);
584
585         return 0;
586 }
587
588
589 static int wpa_supplicant_ctrl_iface_enable_network(
590         struct wpa_supplicant *wpa_s, char *cmd)
591 {
592         int id;
593         struct wpa_ssid *ssid;
594
595         /* cmd: "<network id>" */
596         id = atoi(cmd);
597         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
598
599         ssid = wpa_config_get_network(wpa_s->conf, id);
600         if (ssid == NULL) {
601                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
602                            "id=%d", id);
603                 return -1;
604         }
605
606         if (wpa_s->current_ssid == NULL && ssid->disabled) {
607                 /*
608                  * Try to reassociate since there is no current configuration
609                  * and a new network was made available. */
610                 wpa_s->reassociate = 1;
611                 wpa_supplicant_req_scan(wpa_s, 0, 0);
612         }
613         ssid->disabled = 0;
614
615         return 0;
616 }
617
618
619 static int wpa_supplicant_ctrl_iface_disable_network(
620         struct wpa_supplicant *wpa_s, char *cmd)
621 {
622         int id;
623         struct wpa_ssid *ssid;
624
625         /* cmd: "<network id>" */
626         id = atoi(cmd);
627         wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
628
629         ssid = wpa_config_get_network(wpa_s->conf, id);
630         if (ssid == NULL) {
631                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
632                            "id=%d", id);
633                 return -1;
634         }
635
636         if (ssid == wpa_s->current_ssid)
637                 wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
638         ssid->disabled = 1;
639
640         return 0;
641 }
642
643
644 static int wpa_supplicant_ctrl_iface_add_network(
645         struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
646 {
647         struct wpa_ssid *ssid;
648         int ret;
649
650         wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
651
652         ssid = wpa_config_add_network(wpa_s->conf);
653         if (ssid == NULL)
654                 return -1;
655         ssid->disabled = 1;
656         wpa_config_set_network_defaults(ssid);
657
658         ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
659         if (ret < 0 || (size_t) ret >= buflen)
660                 return -1;
661         return ret;
662 }
663
664
665 static int wpa_supplicant_ctrl_iface_remove_network(
666         struct wpa_supplicant *wpa_s, char *cmd)
667 {
668         int id;
669         struct wpa_ssid *ssid;
670
671         /* cmd: "<network id>" */
672         id = atoi(cmd);
673         wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
674
675         ssid = wpa_config_get_network(wpa_s->conf, id);
676         if (ssid == NULL ||
677             wpa_config_remove_network(wpa_s->conf, id) < 0) {
678                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
679                            "id=%d", id);
680                 return -1;
681         }
682
683         if (ssid == wpa_s->current_ssid) {
684                 /*
685                  * Invalidate the EAP session cache if the current network is
686                  * removed.
687                  */
688                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
689
690                 wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
691         }
692
693         return 0;
694 }
695
696
697 static int wpa_supplicant_ctrl_iface_set_network(
698         struct wpa_supplicant *wpa_s, char *cmd)
699 {
700         int id;
701         struct wpa_ssid *ssid;
702         char *name, *value;
703
704         /* cmd: "<network id> <variable name> <value>" */
705         name = os_strchr(cmd, ' ');
706         if (name == NULL)
707                 return -1;
708         *name++ = '\0';
709
710         value = os_strchr(name, ' ');
711         if (value == NULL)
712                 return -1;
713         *value++ = '\0';
714
715         id = atoi(cmd);
716         wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
717                    id, name);
718         wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
719                               (u8 *) value, os_strlen(value));
720
721         ssid = wpa_config_get_network(wpa_s->conf, id);
722         if (ssid == NULL) {
723                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
724                            "id=%d", id);
725                 return -1;
726         }
727
728         if (wpa_config_set(ssid, name, value, 0) < 0) {
729                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
730                            "variable '%s'", name);
731                 return -1;
732         }
733
734         if (wpa_s->current_ssid == ssid) {
735                 /*
736                  * Invalidate the EAP session cache if anything in the current
737                  * configuration changes.
738                  */
739                 eapol_sm_invalidate_cached_session(wpa_s->eapol);
740         }
741
742         if ((os_strcmp(name, "psk") == 0 &&
743              value[0] == '"' && ssid->ssid_len) ||
744             (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
745                 wpa_config_update_psk(ssid);
746
747         return 0;
748 }
749
750
751 static int wpa_supplicant_ctrl_iface_get_network(
752         struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
753 {
754         int id;
755         struct wpa_ssid *ssid;
756         char *name, *value;
757
758         /* cmd: "<network id> <variable name>" */
759         name = os_strchr(cmd, ' ');
760         if (name == NULL || buflen == 0)
761                 return -1;
762         *name++ = '\0';
763
764         id = atoi(cmd);
765         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
766                    id, name);
767
768         ssid = wpa_config_get_network(wpa_s->conf, id);
769         if (ssid == NULL) {
770                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
771                            "id=%d", id);
772                 return -1;
773         }
774
775         value = wpa_config_get_no_key(ssid, name);
776         if (value == NULL) {
777                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
778                            "variable '%s'", name);
779                 return -1;
780         }
781
782         os_snprintf(buf, buflen, "%s", value);
783         buf[buflen - 1] = '\0';
784
785         os_free(value);
786
787         return os_strlen(buf);
788 }
789
790
791 static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
792 {
793         int ret;
794
795         if (!wpa_s->conf->update_config) {
796                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
797                            "to update configuration (update_config=0)");
798                 return -1;
799         }
800
801         ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
802         if (ret) {
803                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
804                            "update configuration");
805         } else {
806                 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
807                            " updated");
808         }
809
810         return ret;
811 }
812
813
814 static int wpa_supplicant_ctrl_iface_get_capability(
815         struct wpa_supplicant *wpa_s, const char *_field, char *buf,
816         size_t buflen)
817 {
818         struct wpa_driver_capa capa;
819         int res, first = 1, ret;
820         char *pos, *end, *strict;
821         char field[30];
822
823         /* Determine whether or not strict checking was requested */
824         os_snprintf(field, sizeof(field), "%s", _field);
825         field[sizeof(field) - 1] = '\0';
826         strict = os_strchr(field, ' ');
827         if (strict != NULL) {
828                 *strict++ = '\0';
829                 if (os_strcmp(strict, "strict") != 0)
830                         return -1;
831         }
832
833         wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
834                 field, strict ? strict : "");
835
836         if (os_strcmp(field, "eap") == 0) {
837                 return eap_get_names(buf, buflen);
838         }
839
840         res = wpa_drv_get_capa(wpa_s, &capa);
841
842         pos = buf;
843         end = pos + buflen;
844
845         if (os_strcmp(field, "pairwise") == 0) {
846                 if (res < 0) {
847                         if (strict)
848                                 return 0;
849                         ret = os_snprintf(buf, buflen, "CCMP TKIP NONE");
850                         if (ret < 0 || (size_t) ret >= buflen)
851                                 return -1;
852                         return ret;
853                 }
854
855                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
856                         ret = os_snprintf(pos, end - pos, "%sCCMP",
857                                           first ? "" : " ");
858                         if (ret < 0 || ret >= end - pos)
859                                 return pos - buf;
860                         pos += ret;
861                         first = 0;
862                 }
863
864                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
865                         ret = os_snprintf(pos, end - pos, "%sTKIP",
866                                           first ? "" : " ");
867                         if (ret < 0 || ret >= end - pos)
868                                 return pos - buf;
869                         pos += ret;
870                         first = 0;
871                 }
872
873                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
874                         ret = os_snprintf(pos, end - pos, "%sNONE",
875                                           first ? "" : " ");
876                         if (ret < 0 || ret >= end - pos)
877                                 return pos - buf;
878                         pos += ret;
879                         first = 0;
880                 }
881
882                 return pos - buf;
883         }
884
885         if (os_strcmp(field, "group") == 0) {
886                 if (res < 0) {
887                         if (strict)
888                                 return 0;
889                         ret = os_snprintf(buf, buflen,
890                                           "CCMP TKIP WEP104 WEP40");
891                         if (ret < 0 || (size_t) ret >= buflen)
892                                 return -1;
893                         return ret;
894                 }
895
896                 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
897                         ret = os_snprintf(pos, end - pos, "%sCCMP",
898                                           first ? "" : " ");
899                         if (ret < 0 || ret >= end - pos)
900                                 return pos - buf;
901                         pos += ret;
902                         first = 0;
903                 }
904
905                 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
906                         ret = os_snprintf(pos, end - pos, "%sTKIP",
907                                           first ? "" : " ");
908                         if (ret < 0 || ret >= end - pos)
909                                 return pos - buf;
910                         pos += ret;
911                         first = 0;
912                 }
913
914                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
915                         ret = os_snprintf(pos, end - pos, "%sWEP104",
916                                           first ? "" : " ");
917                         if (ret < 0 || ret >= end - pos)
918                                 return pos - buf;
919                         pos += ret;
920                         first = 0;
921                 }
922
923                 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
924                         ret = os_snprintf(pos, end - pos, "%sWEP40",
925                                           first ? "" : " ");
926                         if (ret < 0 || ret >= end - pos)
927                                 return pos - buf;
928                         pos += ret;
929                         first = 0;
930                 }
931
932                 return pos - buf;
933         }
934
935         if (os_strcmp(field, "key_mgmt") == 0) {
936                 if (res < 0) {
937                         if (strict)
938                                 return 0;
939                         ret = os_snprintf(buf, buflen, "WPA-PSK WPA-EAP "
940                                           "IEEE8021X WPA-NONE NONE");
941                         if (ret < 0 || (size_t) ret >= buflen)
942                                 return -1;
943                         return ret;
944                 }
945
946                 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
947                 if (ret < 0 || ret >= end - pos)
948                         return pos - buf;
949                 pos += ret;
950
951                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
952                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
953                         ret = os_snprintf(pos, end - pos, " WPA-EAP");
954                         if (ret < 0 || ret >= end - pos)
955                                 return pos - buf;
956                         pos += ret;
957                 }
958
959                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
960                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
961                         ret = os_snprintf(pos, end - pos, " WPA-PSK");
962                         if (ret < 0 || ret >= end - pos)
963                                 return pos - buf;
964                         pos += ret;
965                 }
966
967                 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
968                         ret = os_snprintf(pos, end - pos, " WPA-NONE");
969                         if (ret < 0 || ret >= end - pos)
970                                 return pos - buf;
971                         pos += ret;
972                 }
973
974                 return pos - buf;
975         }
976
977         if (os_strcmp(field, "proto") == 0) {
978                 if (res < 0) {
979                         if (strict)
980                                 return 0;
981                         ret = os_snprintf(buf, buflen, "RSN WPA");
982                         if (ret < 0 || (size_t) ret >= buflen)
983                                 return -1;
984                         return ret;
985                 }
986
987                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
988                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
989                         ret = os_snprintf(pos, end - pos, "%sRSN",
990                                           first ? "" : " ");
991                         if (ret < 0 || ret >= end - pos)
992                                 return pos - buf;
993                         pos += ret;
994                         first = 0;
995                 }
996
997                 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
998                                      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
999                         ret = os_snprintf(pos, end - pos, "%sWPA",
1000                                           first ? "" : " ");
1001                         if (ret < 0 || ret >= end - pos)
1002                                 return pos - buf;
1003                         pos += ret;
1004                         first = 0;
1005                 }
1006
1007                 return pos - buf;
1008         }
1009
1010         if (os_strcmp(field, "auth_alg") == 0) {
1011                 if (res < 0) {
1012                         if (strict)
1013                                 return 0;
1014                         ret = os_snprintf(buf, buflen, "OPEN SHARED LEAP");
1015                         if (ret < 0 || (size_t) ret >= buflen)
1016                                 return -1;
1017                         return ret;
1018                 }
1019
1020                 if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
1021                         ret = os_snprintf(pos, end - pos, "%sOPEN",
1022                                           first ? "" : " ");
1023                         if (ret < 0 || ret >= end - pos)
1024                                 return pos - buf;
1025                         pos += ret;
1026                         first = 0;
1027                 }
1028
1029                 if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
1030                         ret = os_snprintf(pos, end - pos, "%sSHARED",
1031                                           first ? "" : " ");
1032                         if (ret < 0 || ret >= end - pos)
1033                                 return pos - buf;
1034                         pos += ret;
1035                         first = 0;
1036                 }
1037
1038                 if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
1039                         ret = os_snprintf(pos, end - pos, "%sLEAP",
1040                                           first ? "" : " ");
1041                         if (ret < 0 || ret >= end - pos)
1042                                 return pos - buf;
1043                         pos += ret;
1044                         first = 0;
1045                 }
1046
1047                 return pos - buf;
1048         }
1049
1050         wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1051                    field);
1052
1053         return -1;
1054 }
1055
1056
1057 static int wpa_supplicant_ctrl_iface_ap_scan(
1058         struct wpa_supplicant *wpa_s, char *cmd)
1059 {
1060         int ap_scan = atoi(cmd);
1061
1062         if (ap_scan < 0 || ap_scan > 2)
1063                 return -1;
1064         wpa_s->conf->ap_scan = ap_scan;
1065         return 0;
1066 }
1067
1068
1069 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1070                                          char *buf, size_t *resp_len)
1071 {
1072         char *reply;
1073         const int reply_size = 2048;
1074         int ctrl_rsp = 0;
1075         int reply_len;
1076
1077         if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1078             os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1079                 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1080                                       (const u8 *) buf, os_strlen(buf));
1081         } else {
1082                 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1083                                   (const u8 *) buf, os_strlen(buf));
1084         }
1085
1086         reply = os_malloc(reply_size);
1087         if (reply == NULL) {
1088                 *resp_len = 1;
1089                 return NULL;
1090         }
1091
1092         os_memcpy(reply, "OK\n", 3);
1093         reply_len = 3;
1094
1095         if (os_strcmp(buf, "PING") == 0) {
1096                 os_memcpy(reply, "PONG\n", 5);
1097                 reply_len = 5;
1098         } else if (os_strcmp(buf, "MIB") == 0) {
1099                 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1100                 if (reply_len >= 0) {
1101                         int res;
1102                         res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1103                                                reply_size - reply_len);
1104                         if (res < 0)
1105                                 reply_len = -1;
1106                         else
1107                                 reply_len += res;
1108                 }
1109         } else if (os_strncmp(buf, "STATUS", 6) == 0) {
1110                 reply_len = wpa_supplicant_ctrl_iface_status(
1111                         wpa_s, buf + 6, reply, reply_size);
1112         } else if (os_strcmp(buf, "PMKSA") == 0) {
1113                 reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
1114         } else if (os_strncmp(buf, "SET ", 4) == 0) {
1115                 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1116                         reply_len = -1;
1117         } else if (os_strcmp(buf, "LOGON") == 0) {
1118                 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1119         } else if (os_strcmp(buf, "LOGOFF") == 0) {
1120                 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1121         } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
1122                 wpa_s->disconnected = 0;
1123                 wpa_s->reassociate = 1;
1124                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1125         } else if (os_strcmp(buf, "RECONNECT") == 0) {
1126                 if (wpa_s->disconnected) {
1127                         wpa_s->disconnected = 0;
1128                         wpa_s->reassociate = 1;
1129                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1130                 }
1131 #ifdef IEEE8021X_EAPOL
1132         } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1133                 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1134                         reply_len = -1;
1135 #endif /* IEEE8021X_EAPOL */
1136 #ifdef CONFIG_PEERKEY
1137         } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1138                 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1139                         reply_len = -1;
1140 #endif /* CONFIG_PEERKEY */
1141         } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1142         {
1143                 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1144                             wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1145                         reply_len = -1;
1146                 else
1147                         ctrl_rsp = 1;
1148         } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1149                 if (wpa_supplicant_reload_configuration(wpa_s))
1150                         reply_len = -1;
1151         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1152                 eloop_terminate();
1153         } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1154                 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1155                         reply_len = -1;
1156         } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1157                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
1158                         wpa_s, reply, reply_size);
1159         } else if (os_strcmp(buf, "DISCONNECT") == 0) {
1160                 wpa_s->reassociate = 0;
1161                 wpa_s->disconnected = 1;
1162                 wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
1163         } else if (os_strcmp(buf, "SCAN") == 0) {
1164                 wpa_s->scan_req = 2;
1165                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1166         } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1167                 reply_len = wpa_supplicant_ctrl_iface_scan_results(
1168                         wpa_s, reply, reply_size);
1169         } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1170                 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1171                         reply_len = -1;
1172         } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1173                 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1174                         reply_len = -1;
1175         } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1176                 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1177                         reply_len = -1;
1178         } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1179                 reply_len = wpa_supplicant_ctrl_iface_add_network(
1180                         wpa_s, reply, reply_size);
1181         } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1182                 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1183                         reply_len = -1;
1184         } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1185                 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1186                         reply_len = -1;
1187         } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1188                 reply_len = wpa_supplicant_ctrl_iface_get_network(
1189                         wpa_s, buf + 12, reply, reply_size);
1190         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1191                 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1192                         reply_len = -1;
1193         } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1194                 reply_len = wpa_supplicant_ctrl_iface_get_capability(
1195                         wpa_s, buf + 15, reply, reply_size);
1196         } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1197                 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1198                         reply_len = -1;
1199         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1200                 reply_len = wpa_supplicant_global_iface_interfaces(
1201                         wpa_s->global, reply, reply_size);
1202         } else {
1203                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1204                 reply_len = 16;
1205         }
1206
1207         if (reply_len < 0) {
1208                 os_memcpy(reply, "FAIL\n", 5);
1209                 reply_len = 5;
1210         }
1211
1212         if (ctrl_rsp)
1213                 eapol_sm_notify_ctrl_response(wpa_s->eapol);
1214
1215         *resp_len = reply_len;
1216         return reply;
1217 }
1218
1219
1220 static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1221                                            char *cmd)
1222 {
1223         struct wpa_interface iface;
1224         char *pos;
1225
1226         /*
1227          * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1228          * TAB<bridge_ifname>
1229          */
1230         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1231
1232         os_memset(&iface, 0, sizeof(iface));
1233
1234         do {
1235                 iface.ifname = pos = cmd;
1236                 pos = os_strchr(pos, '\t');
1237                 if (pos)
1238                         *pos++ = '\0';
1239                 if (iface.ifname[0] == '\0')
1240                         return -1;
1241                 if (pos == NULL)
1242                         break;
1243
1244                 iface.confname = pos;
1245                 pos = os_strchr(pos, '\t');
1246                 if (pos)
1247                         *pos++ = '\0';
1248                 if (iface.confname[0] == '\0')
1249                         iface.confname = NULL;
1250                 if (pos == NULL)
1251                         break;
1252
1253                 iface.driver = pos;
1254                 pos = os_strchr(pos, '\t');
1255                 if (pos)
1256                         *pos++ = '\0';
1257                 if (iface.driver[0] == '\0')
1258                         iface.driver = NULL;
1259                 if (pos == NULL)
1260                         break;
1261
1262                 iface.ctrl_interface = pos;
1263                 pos = os_strchr(pos, '\t');
1264                 if (pos)
1265                         *pos++ = '\0';
1266                 if (iface.ctrl_interface[0] == '\0')
1267                         iface.ctrl_interface = NULL;
1268                 if (pos == NULL)
1269                         break;
1270
1271                 iface.driver_param = pos;
1272                 pos = os_strchr(pos, '\t');
1273                 if (pos)
1274                         *pos++ = '\0';
1275                 if (iface.driver_param[0] == '\0')
1276                         iface.driver_param = NULL;
1277                 if (pos == NULL)
1278                         break;
1279
1280                 iface.bridge_ifname = pos;
1281                 pos = os_strchr(pos, '\t');
1282                 if (pos)
1283                         *pos++ = '\0';
1284                 if (iface.bridge_ifname[0] == '\0')
1285                         iface.bridge_ifname = NULL;
1286                 if (pos == NULL)
1287                         break;
1288         } while (0);
1289
1290         if (wpa_supplicant_get_iface(global, iface.ifname))
1291                 return -1;
1292
1293         return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1294 }
1295
1296
1297 static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1298                                               char *cmd)
1299 {
1300         struct wpa_supplicant *wpa_s;
1301
1302         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1303
1304         wpa_s = wpa_supplicant_get_iface(global, cmd);
1305         if (wpa_s == NULL)
1306                 return -1;
1307         return wpa_supplicant_remove_iface(global, wpa_s);
1308 }
1309
1310
1311 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1312                                                   char *buf, int len)
1313 {
1314         int res;
1315         char *pos, *end;
1316         struct wpa_supplicant *wpa_s;
1317
1318         wpa_s = global->ifaces;
1319         pos = buf;
1320         end = buf + len;
1321
1322         while (wpa_s) {
1323                 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1324                 if (res < 0 || res >= end - pos) {
1325                         *pos = '\0';
1326                         break;
1327                 }
1328                 pos += res;
1329                 wpa_s = wpa_s->next;
1330         }
1331         return pos - buf;
1332 }
1333
1334
1335 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1336                                                 char *buf, size_t *resp_len)
1337 {
1338         char *reply;
1339         const int reply_size = 2048;
1340         int reply_len;
1341
1342         wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1343                           (const u8 *) buf, os_strlen(buf));
1344
1345         reply = os_malloc(reply_size);
1346         if (reply == NULL) {
1347                 *resp_len = 1;
1348                 return NULL;
1349         }
1350
1351         os_memcpy(reply, "OK\n", 3);
1352         reply_len = 3;
1353
1354         if (os_strcmp(buf, "PING") == 0) {
1355                 os_memcpy(reply, "PONG\n", 5);
1356                 reply_len = 5;
1357         } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1358                 if (wpa_supplicant_global_iface_add(global, buf + 14))
1359                         reply_len = -1;
1360         } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1361                 if (wpa_supplicant_global_iface_remove(global, buf + 17))
1362                         reply_len = -1;
1363         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1364                 reply_len = wpa_supplicant_global_iface_interfaces(
1365                         global, reply, reply_size);
1366         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1367                 eloop_terminate();
1368         } else {
1369                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1370                 reply_len = 16;
1371         }
1372
1373         if (reply_len < 0) {
1374                 os_memcpy(reply, "FAIL\n", 5);
1375                 reply_len = 5;
1376         }
1377
1378         *resp_len = reply_len;
1379         return reply;
1380 }