2 * WPA Supplicant / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include <sys/types.h>
22 #ifndef CONFIG_NATIVE_WINDOWS
23 #include <sys/socket.h>
26 #endif /* CONFIG_NATIVE_WINDOWS */
31 #include "wpa_supplicant.h"
34 #include "wpa_supplicant_i.h"
35 #include "ctrl_iface.h"
36 #include "l2_packet.h"
39 #ifdef CONFIG_NATIVE_WINDOWS
40 typedef int socklen_t;
41 #endif /* CONFIG_NATIVE_WINDOWS */
43 #ifdef CONFIG_CTRL_IFACE_UDP
44 #define CTRL_IFACE_SOCK struct sockaddr_in
45 #else /* CONFIG_CTRL_IFACE_UDP */
46 #define CTRL_IFACE_SOCK struct sockaddr_un
47 #endif /* CONFIG_CTRL_IFACE_UDP */
51 struct wpa_ctrl_dst *next;
59 static const char * wpa_state_txt(int state)
62 case WPA_DISCONNECTED:
63 return "DISCONNECTED";
70 case WPA_4WAY_HANDSHAKE:
71 return "4WAY_HANDSHAKE";
72 case WPA_GROUP_HANDSHAKE:
73 return "GROUP_HANDSHAKE";
82 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
87 value = strchr(cmd, ' ');
92 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
93 if (strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
94 eapol_sm_configure(wpa_s->eapol,
95 atoi(value), -1, -1, -1);
96 } else if (strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
97 eapol_sm_configure(wpa_s->eapol,
98 -1, atoi(value), -1, -1);
99 } else if (strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
100 eapol_sm_configure(wpa_s->eapol,
101 -1, -1, atoi(value), -1);
102 } else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) {
103 eapol_sm_configure(wpa_s->eapol,
104 -1, -1, -1, atoi(value));
111 static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
116 if (hwaddr_aton(addr, bssid)) {
117 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
122 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
123 rsn_preauth_deinit(wpa_s);
124 if (rsn_preauth_init(wpa_s, bssid))
131 static int wpa_supplicant_ctrl_iface_attach(struct wpa_supplicant *wpa_s,
132 CTRL_IFACE_SOCK *from,
135 struct wpa_ctrl_dst *dst;
137 dst = malloc(sizeof(*dst));
140 memset(dst, 0, sizeof(*dst));
141 memcpy(&dst->addr, from, sizeof(CTRL_IFACE_SOCK));
142 dst->addrlen = fromlen;
143 dst->debug_level = MSG_INFO;
144 dst->next = wpa_s->ctrl_dst;
145 wpa_s->ctrl_dst = dst;
146 #ifdef CONFIG_CTRL_IFACE_UDP
147 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
148 inet_ntoa(from->sin_addr), ntohs(from->sin_port));
149 #else /* CONFIG_CTRL_IFACE_UDP */
150 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
151 (u8 *) from->sun_path, fromlen);
152 #endif /* CONFIG_CTRL_IFACE_UDP */
157 static int wpa_supplicant_ctrl_iface_detach(struct wpa_supplicant *wpa_s,
158 CTRL_IFACE_SOCK *from,
161 struct wpa_ctrl_dst *dst, *prev = NULL;
163 dst = wpa_s->ctrl_dst;
165 #ifdef CONFIG_CTRL_IFACE_UDP
166 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
167 from->sin_port == dst->addr.sin_port) {
169 wpa_s->ctrl_dst = dst->next;
171 prev->next = dst->next;
173 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
174 "%s:%d", inet_ntoa(from->sin_addr),
175 ntohs(from->sin_port));
178 #else /* CONFIG_CTRL_IFACE_UDP */
179 if (fromlen == dst->addrlen &&
180 memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
182 wpa_s->ctrl_dst = dst->next;
184 prev->next = dst->next;
186 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
187 (u8 *) from->sun_path, fromlen);
190 #endif /* CONFIG_CTRL_IFACE_UDP */
198 static int wpa_supplicant_ctrl_iface_level(struct wpa_supplicant *wpa_s,
199 CTRL_IFACE_SOCK *from,
203 struct wpa_ctrl_dst *dst;
205 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
207 dst = wpa_s->ctrl_dst;
209 #ifdef CONFIG_CTRL_IFACE_UDP
210 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
211 from->sin_port == dst->addr.sin_port) {
212 wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
213 "level %s:%d", inet_ntoa(from->sin_addr),
214 ntohs(from->sin_port));
215 dst->debug_level = atoi(level);
218 #else /* CONFIG_CTRL_IFACE_UDP */
219 if (fromlen == dst->addrlen &&
220 memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
221 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
222 "level", (u8 *) from->sun_path, fromlen);
223 dst->debug_level = atoi(level);
226 #endif /* CONFIG_CTRL_IFACE_UDP */
234 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
239 struct wpa_ssid *ssid;
241 pos = strchr(rsp, '-');
246 pos = strchr(pos, ':');
251 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
252 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
253 (u8 *) pos, strlen(pos));
255 ssid = wpa_s->conf->ssid;
263 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
268 if (strcmp(rsp, "IDENTITY") == 0) {
269 free(ssid->identity);
270 ssid->identity = (u8 *) strdup(pos);
271 ssid->identity_len = strlen(pos);
272 ssid->pending_req_identity = 0;
273 if (ssid == wpa_s->current_ssid)
274 wpa_s->reassociate = 1;
275 } else if (strcmp(rsp, "PASSWORD") == 0) {
276 free(ssid->password);
277 ssid->password = (u8 *) strdup(pos);
278 ssid->password_len = strlen(pos);
279 ssid->pending_req_password = 0;
280 if (ssid == wpa_s->current_ssid)
281 wpa_s->reassociate = 1;
282 } else if (strcmp(rsp, "OTP") == 0) {
284 ssid->otp = (u8 *) strdup(pos);
285 ssid->otp_len = strlen(pos);
286 free(ssid->pending_req_otp);
287 ssid->pending_req_otp = NULL;
288 ssid->pending_req_otp_len = 0;
290 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
298 static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
300 char *buf, size_t buflen)
305 verbose = strcmp(params, "-VERBOSE") == 0;
308 pos += snprintf(pos, end - pos, "bssid=" MACSTR "\n",
309 MAC2STR(wpa_s->bssid));
310 if (wpa_s->current_ssid) {
311 pos += snprintf(pos, end - pos, "ssid=%s\n",
312 wpa_ssid_txt(wpa_s->current_ssid->ssid,
313 wpa_s->current_ssid->ssid_len));
315 pos += snprintf(pos, end - pos,
316 "pairwise_cipher=%s\n"
320 wpa_cipher_txt(wpa_s->pairwise_cipher),
321 wpa_cipher_txt(wpa_s->group_cipher),
322 wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->proto),
323 wpa_state_txt(wpa_s->wpa_state));
325 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, verbose);
329 if (wpa_s->preauth_eapol) {
330 pos += snprintf(pos, end - pos, "Pre-authentication "
331 "EAPOL state machines:\n");
332 res = eapol_sm_get_status(wpa_s->preauth_eapol,
333 pos, end - pos, verbose);
342 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
345 struct wpa_supplicant *wpa_s = eloop_ctx;
348 CTRL_IFACE_SOCK from;
349 socklen_t fromlen = sizeof(from);
351 const int reply_size = 2048;
353 int new_attached = 0, ctrl_rsp = 0;
355 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
356 (struct sockaddr *) &from, &fromlen);
358 perror("recvfrom(ctrl_iface)");
362 if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
363 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
366 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
369 reply = malloc(reply_size);
371 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
376 memcpy(reply, "OK\n", 3);
379 if (strcmp(buf, "PING") == 0) {
380 memcpy(reply, "PONG\n", 5);
382 } else if (strcmp(buf, "MIB") == 0) {
383 reply_len = wpa_get_mib(wpa_s, reply, reply_size);
384 if (reply_len >= 0) {
385 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
386 reply_size - reply_len);
392 } else if (strncmp(buf, "STATUS", 6) == 0) {
393 reply_len = wpa_supplicant_ctrl_iface_status(
394 wpa_s, buf + 6, reply, reply_size);
395 } else if (strcmp(buf, "PMKSA") == 0) {
396 reply_len = pmksa_cache_list(wpa_s, reply, reply_size);
397 } else if (strncmp(buf, "SET ", 4) == 0) {
398 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
400 } else if (strcmp(buf, "LOGON") == 0) {
401 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
402 } else if (strcmp(buf, "LOGOFF") == 0) {
403 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
404 } else if (strcmp(buf, "REASSOCIATE") == 0) {
405 wpa_s->reassociate = 1;
406 wpa_supplicant_req_scan(wpa_s, 0, 0);
407 } else if (strncmp(buf, "PREAUTH ", 8) == 0) {
408 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
410 } else if (strcmp(buf, "ATTACH") == 0) {
411 if (wpa_supplicant_ctrl_iface_attach(wpa_s, &from, fromlen))
415 } else if (strcmp(buf, "DETACH") == 0) {
416 if (wpa_supplicant_ctrl_iface_detach(wpa_s, &from, fromlen))
418 } else if (strncmp(buf, "LEVEL ", 6) == 0) {
419 if (wpa_supplicant_ctrl_iface_level(wpa_s, &from, fromlen,
422 } else if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
423 if (wpa_supplicant_ctrl_iface_ctrl_rsp(wpa_s, buf + 9))
427 } else if (strcmp(buf, "RECONFIGURE") == 0) {
428 if (wpa_supplicant_reload_configuration(wpa_s))
430 } else if (strcmp(buf, "TERMINATE") == 0) {
433 memcpy(reply, "UNKNOWN COMMAND\n", 16);
438 memcpy(reply, "FAIL\n", 5);
441 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
445 eapol_sm_notify_ctrl_attached(wpa_s->eapol);
447 eapol_sm_notify_ctrl_response(wpa_s->eapol);
451 static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
456 if (wpa_s->conf->ctrl_interface == NULL)
459 len = strlen(wpa_s->conf->ctrl_interface) + strlen(wpa_s->ifname) + 2;
464 snprintf(buf, len, "%s/%s",
465 wpa_s->conf->ctrl_interface, wpa_s->ifname);
468 /* Windows/WinPcap uses interface names that are not suitable
469 * as a file name - convert invalid chars to underscores */
477 #endif /* __CYGWIN__ */
482 int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
484 CTRL_IFACE_SOCK addr;
488 wpa_s->ctrl_sock = -1;
490 if (wpa_s->conf->ctrl_interface == NULL)
493 #ifdef CONFIG_CTRL_IFACE_UDP
494 s = socket(PF_INET, SOCK_DGRAM, 0);
496 perror("socket(PF_INET)");
500 memset(&addr, 0, sizeof(addr));
501 addr.sin_family = AF_INET;
502 addr.sin_addr.s_addr = htonl((127 << 24) | 1);
503 addr.sin_port = htons(9877);
504 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
505 perror("bind(AF_UNIX)");
508 #else /* CONFIG_CTRL_IFACE_UDP */
509 if (mkdir(wpa_s->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
510 if (errno == EEXIST) {
511 wpa_printf(MSG_DEBUG, "Using existing control "
512 "interface directory.");
514 perror("mkdir[ctrl_interface]");
519 if (wpa_s->conf->ctrl_interface_gid_set &&
520 chown(wpa_s->conf->ctrl_interface, 0,
521 wpa_s->conf->ctrl_interface_gid) < 0) {
522 perror("chown[ctrl_interface]");
526 if (strlen(wpa_s->conf->ctrl_interface) + 1 + strlen(wpa_s->ifname) >=
527 sizeof(addr.sun_path))
530 s = socket(PF_UNIX, SOCK_DGRAM, 0);
532 perror("socket(PF_UNIX)");
536 memset(&addr, 0, sizeof(addr));
537 addr.sun_family = AF_UNIX;
538 fname = wpa_supplicant_ctrl_iface_path(wpa_s);
541 strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
542 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
543 perror("bind(PF_UNIX)");
544 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
545 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
546 " allow connections - assuming it was left"
547 "over from forced program termination");
548 if (unlink(fname) < 0) {
549 perror("unlink[ctrl_iface]");
550 wpa_printf(MSG_ERROR, "Could not unlink "
551 "existing ctrl_iface socket '%s'",
555 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
557 perror("bind(PF_UNIX)");
560 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
561 "ctrl_iface socket '%s'", fname);
563 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
564 "be in use - cannot override it");
565 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
566 "not used anymore", fname);
573 if (wpa_s->conf->ctrl_interface_gid_set &&
574 chown(fname, 0, wpa_s->conf->ctrl_interface_gid) < 0) {
575 perror("chown[ctrl_interface/ifname]");
579 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
580 perror("chmod[ctrl_interface/ifname]");
584 #endif /* CONFIG_CTRL_IFACE_UDP */
586 wpa_s->ctrl_sock = s;
587 eloop_register_read_sock(s, wpa_supplicant_ctrl_iface_receive, wpa_s,
603 void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
605 struct wpa_ctrl_dst *dst, *prev;
607 if (wpa_s->ctrl_sock > -1) {
609 eloop_unregister_read_sock(wpa_s->ctrl_sock);
610 if (wpa_s->ctrl_dst) {
612 * Wait a second before closing the control socket if
613 * there are any attached monitors in order to allow
614 * them to receive any pending messages.
616 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
617 "monitors to receive messages");
620 close(wpa_s->ctrl_sock);
621 wpa_s->ctrl_sock = -1;
622 fname = wpa_supplicant_ctrl_iface_path(wpa_s);
627 if (rmdir(wpa_s->conf->ctrl_interface) < 0) {
628 if (errno == ENOTEMPTY) {
629 wpa_printf(MSG_DEBUG, "Control interface "
630 "directory not empty - leaving it "
633 perror("rmdir[ctrl_interface]");
638 dst = wpa_s->ctrl_dst;
647 void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
648 char *buf, size_t len)
650 struct wpa_ctrl_dst *dst, *next;
653 #ifdef CONFIG_CTRL_IFACE_UDP
657 dst = wpa_s->ctrl_dst;
658 if (wpa_s->ctrl_sock < 0 || dst == NULL)
661 snprintf(levelstr, sizeof(levelstr), "<%d>", level);
663 llen = strlen(levelstr);
664 sbuf = malloc(llen + len);
668 memcpy(sbuf, levelstr, llen);
669 memcpy(sbuf + llen, buf, len);
674 if (level >= dst->debug_level) {
675 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
676 inet_ntoa(dst->addr.sin_addr),
677 ntohs(dst->addr.sin_port));
678 if (sendto(wpa_s->ctrl_sock, sbuf, llen + len, 0,
679 (struct sockaddr *) &dst->addr,
680 sizeof(dst->addr)) < 0) {
681 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
685 if (dst->errors > 10) {
686 wpa_supplicant_ctrl_iface_detach(
697 #else /* CONFIG_CTRL_IFACE_UDP */
701 dst = wpa_s->ctrl_dst;
702 if (wpa_s->ctrl_sock < 0 || dst == NULL)
705 snprintf(levelstr, sizeof(levelstr), "<%d>", level);
706 io[0].iov_base = levelstr;
707 io[0].iov_len = strlen(levelstr);
708 io[1].iov_base = buf;
710 memset(&msg, 0, sizeof(msg));
717 if (level >= dst->debug_level) {
718 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
719 (u8 *) dst->addr.sun_path, dst->addrlen);
720 msg.msg_name = &dst->addr;
721 msg.msg_namelen = dst->addrlen;
722 if (sendmsg(wpa_s->ctrl_sock, &msg, 0) < 0) {
723 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
727 if (dst->errors > 10) {
728 wpa_supplicant_ctrl_iface_detach(
738 #endif /* CONFIG_CTRL_IFACE_UDP */