DEVFS - Make synchronization prior to mountroot more robust
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / 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_strncmp(buf, "PREAUTH ", 8) == 0) {
1124                 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1125                         reply_len = -1;
1126 #ifdef CONFIG_PEERKEY
1127         } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1128                 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1129                         reply_len = -1;
1130 #endif /* CONFIG_PEERKEY */
1131         } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1132         {
1133                 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1134                             wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1135                         reply_len = -1;
1136                 else
1137                         ctrl_rsp = 1;
1138         } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1139                 if (wpa_supplicant_reload_configuration(wpa_s))
1140                         reply_len = -1;
1141         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1142                 eloop_terminate();
1143         } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1144                 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1145                         reply_len = -1;
1146         } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1147                 reply_len = wpa_supplicant_ctrl_iface_list_networks(
1148                         wpa_s, reply, reply_size);
1149         } else if (os_strcmp(buf, "DISCONNECT") == 0) {
1150                 wpa_s->disconnected = 1;
1151                 wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
1152         } else if (os_strcmp(buf, "SCAN") == 0) {
1153                 wpa_s->scan_req = 2;
1154                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1155         } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1156                 reply_len = wpa_supplicant_ctrl_iface_scan_results(
1157                         wpa_s, reply, reply_size);
1158         } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1159                 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1160                         reply_len = -1;
1161         } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1162                 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1163                         reply_len = -1;
1164         } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1165                 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1166                         reply_len = -1;
1167         } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1168                 reply_len = wpa_supplicant_ctrl_iface_add_network(
1169                         wpa_s, reply, reply_size);
1170         } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1171                 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1172                         reply_len = -1;
1173         } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1174                 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1175                         reply_len = -1;
1176         } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1177                 reply_len = wpa_supplicant_ctrl_iface_get_network(
1178                         wpa_s, buf + 12, reply, reply_size);
1179         } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1180                 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1181                         reply_len = -1;
1182         } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1183                 reply_len = wpa_supplicant_ctrl_iface_get_capability(
1184                         wpa_s, buf + 15, reply, reply_size);
1185         } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1186                 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1187                         reply_len = -1;
1188         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1189                 reply_len = wpa_supplicant_global_iface_interfaces(
1190                         wpa_s->global, reply, reply_size);
1191         } else {
1192                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1193                 reply_len = 16;
1194         }
1195
1196         if (reply_len < 0) {
1197                 os_memcpy(reply, "FAIL\n", 5);
1198                 reply_len = 5;
1199         }
1200
1201         if (ctrl_rsp)
1202                 eapol_sm_notify_ctrl_response(wpa_s->eapol);
1203
1204         *resp_len = reply_len;
1205         return reply;
1206 }
1207
1208
1209 static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1210                                            char *cmd)
1211 {
1212         struct wpa_interface iface;
1213         char *pos;
1214
1215         /*
1216          * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1217          * TAB<bridge_ifname>
1218          */
1219         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1220
1221         os_memset(&iface, 0, sizeof(iface));
1222
1223         do {
1224                 iface.ifname = pos = cmd;
1225                 pos = os_strchr(pos, '\t');
1226                 if (pos)
1227                         *pos++ = '\0';
1228                 if (iface.ifname[0] == '\0')
1229                         return -1;
1230                 if (pos == NULL)
1231                         break;
1232
1233                 iface.confname = pos;
1234                 pos = os_strchr(pos, '\t');
1235                 if (pos)
1236                         *pos++ = '\0';
1237                 if (iface.confname[0] == '\0')
1238                         iface.confname = NULL;
1239                 if (pos == NULL)
1240                         break;
1241
1242                 iface.driver = pos;
1243                 pos = os_strchr(pos, '\t');
1244                 if (pos)
1245                         *pos++ = '\0';
1246                 if (iface.driver[0] == '\0')
1247                         iface.driver = NULL;
1248                 if (pos == NULL)
1249                         break;
1250
1251                 iface.ctrl_interface = pos;
1252                 pos = os_strchr(pos, '\t');
1253                 if (pos)
1254                         *pos++ = '\0';
1255                 if (iface.ctrl_interface[0] == '\0')
1256                         iface.ctrl_interface = NULL;
1257                 if (pos == NULL)
1258                         break;
1259
1260                 iface.driver_param = pos;
1261                 pos = os_strchr(pos, '\t');
1262                 if (pos)
1263                         *pos++ = '\0';
1264                 if (iface.driver_param[0] == '\0')
1265                         iface.driver_param = NULL;
1266                 if (pos == NULL)
1267                         break;
1268
1269                 iface.bridge_ifname = pos;
1270                 pos = os_strchr(pos, '\t');
1271                 if (pos)
1272                         *pos++ = '\0';
1273                 if (iface.bridge_ifname[0] == '\0')
1274                         iface.bridge_ifname = NULL;
1275                 if (pos == NULL)
1276                         break;
1277         } while (0);
1278
1279         if (wpa_supplicant_get_iface(global, iface.ifname))
1280                 return -1;
1281
1282         return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1283 }
1284
1285
1286 static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1287                                               char *cmd)
1288 {
1289         struct wpa_supplicant *wpa_s;
1290
1291         wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1292
1293         wpa_s = wpa_supplicant_get_iface(global, cmd);
1294         if (wpa_s == NULL)
1295                 return -1;
1296         return wpa_supplicant_remove_iface(global, wpa_s);
1297 }
1298
1299
1300 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1301                                                   char *buf, int len)
1302 {
1303         int res;
1304         char *pos, *end;
1305         struct wpa_supplicant *wpa_s;
1306
1307         wpa_s = global->ifaces;
1308         pos = buf;
1309         end = buf + len;
1310
1311         while (wpa_s) {
1312                 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1313                 if (res < 0 || res >= end - pos) {
1314                         *pos = '\0';
1315                         break;
1316                 }
1317                 pos += res;
1318                 wpa_s = wpa_s->next;
1319         }
1320         return pos - buf;
1321 }
1322
1323
1324 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1325                                                 char *buf, size_t *resp_len)
1326 {
1327         char *reply;
1328         const int reply_size = 2048;
1329         int reply_len;
1330
1331         wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1332                           (const u8 *) buf, os_strlen(buf));
1333
1334         reply = os_malloc(reply_size);
1335         if (reply == NULL) {
1336                 *resp_len = 1;
1337                 return NULL;
1338         }
1339
1340         os_memcpy(reply, "OK\n", 3);
1341         reply_len = 3;
1342
1343         if (os_strcmp(buf, "PING") == 0) {
1344                 os_memcpy(reply, "PONG\n", 5);
1345                 reply_len = 5;
1346         } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1347                 if (wpa_supplicant_global_iface_add(global, buf + 14))
1348                         reply_len = -1;
1349         } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1350                 if (wpa_supplicant_global_iface_remove(global, buf + 17))
1351                         reply_len = -1;
1352         } else if (os_strcmp(buf, "INTERFACES") == 0) {
1353                 reply_len = wpa_supplicant_global_iface_interfaces(
1354                         global, reply, reply_size);
1355         } else if (os_strcmp(buf, "TERMINATE") == 0) {
1356                 eloop_terminate();
1357         } else {
1358                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1359                 reply_len = 16;
1360         }
1361
1362         if (reply_len < 0) {
1363                 os_memcpy(reply, "FAIL\n", 5);
1364                 reply_len = 5;
1365         }
1366
1367         *resp_len = reply_len;
1368         return reply;
1369 }