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