Comment CONFIG_WPA_TRACE_BFD=y out by default
[libeap.git] / hostapd / ctrl_iface.c
index 7afd859..c6edb42 100644 (file)
@@ -18,7 +18,9 @@
 
 #include <sys/un.h>
 #include <sys/stat.h>
+#include <stddef.h>
 
+#include "common.h"
 #include "hostapd.h"
 #include "eloop.h"
 #include "config.h"
@@ -30,6 +32,8 @@
 #include "sta_info.h"
 #include "accounting.h"
 #include "wps_hostapd.h"
+#include "drivers/driver.h"
+#include "ctrl_iface_ap.h"
 
 
 struct wpa_ctrl_dst {
@@ -41,6 +45,10 @@ struct wpa_ctrl_dst {
 };
 
 
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   const char *buf, size_t len);
+
+
 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
                                     struct sockaddr_un *from,
                                     socklen_t fromlen)
@@ -56,7 +64,8 @@ static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
        dst->next = hapd->ctrl_dst;
        hapd->ctrl_dst = dst;
        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
-                   (u8 *) from->sun_path, fromlen);
+                   (u8 *) from->sun_path,
+                   fromlen - offsetof(struct sockaddr_un, sun_path));
        return 0;
 }
 
@@ -70,15 +79,18 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
        dst = hapd->ctrl_dst;
        while (dst) {
                if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
-                   0) {
+                   os_memcmp(from->sun_path, dst->addr.sun_path,
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
                        if (prev == NULL)
                                hapd->ctrl_dst = dst->next;
                        else
                                prev->next = dst->next;
                        os_free(dst);
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-                                   (u8 *) from->sun_path, fromlen);
+                                   (u8 *) from->sun_path,
+                                   fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
                        return 0;
                }
                prev = dst;
@@ -100,10 +112,12 @@ static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
        dst = hapd->ctrl_dst;
        while (dst) {
                if (fromlen == dst->addrlen &&
-                   os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
-                   0) {
+                   os_memcmp(from->sun_path, dst->addr.sun_path,
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
-                                   "level", (u8 *) from->sun_path, fromlen);
+                                   "level", (u8 *) from->sun_path, fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
                        dst->debug_level = atoi(level);
                        return 0;
                }
@@ -114,84 +128,6 @@ static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
 }
 
 
-static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
-                                     struct sta_info *sta,
-                                     char *buf, size_t buflen)
-{
-       int len, res, ret;
-
-       if (sta == NULL) {
-               ret = os_snprintf(buf, buflen, "FAIL\n");
-               if (ret < 0 || (size_t) ret >= buflen)
-                       return 0;
-               return ret;
-       }
-
-       len = 0;
-       ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
-                         MAC2STR(sta->addr));
-       if (ret < 0 || (size_t) ret >= buflen - len)
-               return len;
-       len += ret;
-
-       res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
-       if (res >= 0)
-               len += res;
-       res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
-       if (res >= 0)
-               len += res;
-       res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
-       if (res >= 0)
-               len += res;
-
-       return len;
-}
-
-
-static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
-                                       char *buf, size_t buflen)
-{
-       return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
-}
-
-
-static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
-                                 const char *txtaddr,
-                                 char *buf, size_t buflen)
-{
-       u8 addr[ETH_ALEN];
-       int ret;
-
-       if (hwaddr_aton(txtaddr, addr)) {
-               ret = os_snprintf(buf, buflen, "FAIL\n");
-               if (ret < 0 || (size_t) ret >= buflen)
-                       return 0;
-               return ret;
-       }
-       return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
-                                         buf, buflen);
-}
-
-
-static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
-                                      const char *txtaddr,
-                                      char *buf, size_t buflen)
-{
-       u8 addr[ETH_ALEN];
-       struct sta_info *sta;
-       int ret;
-
-       if (hwaddr_aton(txtaddr, addr) ||
-           (sta = ap_get_sta(hapd, addr)) == NULL) {
-               ret = os_snprintf(buf, buflen, "FAIL\n");
-               if (ret < 0 || (size_t) ret >= buflen)
-                       return 0;
-               return ret;
-       }               
-       return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
-}
-
-
 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
                                      const char *txtaddr)
 {
@@ -219,6 +155,7 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
 
 
 #ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
                                       const char *txtaddr)
 {
@@ -235,6 +172,7 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
 
        return 0;
 }
+#endif /* NEED_AP_MLME */
 #endif /* CONFIG_IEEE80211W */
 
 
@@ -242,11 +180,46 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
 {
        char *pin = os_strchr(txt, ' ');
+       char *timeout_txt;
+       int timeout;
+
        if (pin == NULL)
                return -1;
        *pin++ = '\0';
-       return hostapd_wps_add_pin(hapd, txt, pin);
+
+       timeout_txt = os_strchr(pin, ' ');
+       if (timeout_txt) {
+               *timeout_txt++ = '\0';
+               timeout = atoi(timeout_txt);
+       } else
+               timeout = 0;
+
+       return hostapd_wps_add_pin(hapd, txt, pin, timeout);
 }
+
+
+#ifdef CONFIG_WPS_OOB
+static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
+{
+       char *path, *method, *name;
+
+       path = os_strchr(txt, ' ');
+       if (path == NULL)
+               return -1;
+       *path++ = '\0';
+
+       method = os_strchr(path, ' ');
+       if (method == NULL)
+               return -1;
+       *method++ = '\0';
+
+       name = os_strchr(method, ' ');
+       if (name != NULL)
+               *name++ = '\0';
+
+       return hostapd_wps_start_oob(hapd, txt, path, method, name);
+}
+#endif /* CONFIG_WPS_OOB */
 #endif /* CONFIG_WPS */
 
 
@@ -302,6 +275,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                        else
                                reply_len += res;
                }
+#ifndef CONFIG_NO_RADIUS
                if (reply_len >= 0) {
                        res = radius_client_get_mib(hapd->radius,
                                                    reply + reply_len,
@@ -311,6 +285,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                        else
                                reply_len += res;
                }
+#endif /* CONFIG_NO_RADIUS */
        } else if (os_strcmp(buf, "STA-FIRST") == 0) {
                reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
                                                         reply_size);
@@ -334,9 +309,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
                        reply_len = -1;
 #ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
        } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
                if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
                        reply_len = -1;
+#endif /* NEED_AP_MLME */
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
        } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
@@ -345,6 +322,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strcmp(buf, "WPS_PBC") == 0) {
                if (hostapd_wps_button_pushed(hapd))
                        reply_len = -1;
+#ifdef CONFIG_WPS_OOB
+       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
+               if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
+                       reply_len = -1;
+#endif /* CONFIG_WPS_OOB */
 #endif /* CONFIG_WPS */
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
@@ -381,6 +363,16 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
 }
 
 
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+                                     const char *txt, size_t len)
+{
+       struct hostapd_data *hapd = ctx;
+       if (hapd == NULL)
+               return;
+       hostapd_ctrl_iface_send(hapd, level, txt, len);
+}
+
+
 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
 {
        struct sockaddr_un addr;
@@ -420,14 +412,44 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        }
 
        os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+       addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
        addr.sun_family = AF_UNIX;
        fname = hostapd_ctrl_iface_path(hapd);
        if (fname == NULL)
                goto fail;
        os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
-               goto fail;
+               wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+                          strerror(errno));
+               if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                       wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+                                  " allow connections - assuming it was left"
+                                  "over from forced program termination");
+                       if (unlink(fname) < 0) {
+                               perror("unlink[ctrl_iface]");
+                               wpa_printf(MSG_ERROR, "Could not unlink "
+                                          "existing ctrl_iface socket '%s'",
+                                          fname);
+                               goto fail;
+                       }
+                       if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+                           0) {
+                               perror("bind(PF_UNIX)");
+                               goto fail;
+                       }
+                       wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+                                  "ctrl_iface socket '%s'", fname);
+               } else {
+                       wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+                                  "be in use - cannot override it");
+                       wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+                                  "not used anymore", fname);
+                       os_free(fname);
+                       fname = NULL;
+                       goto fail;
+               }
        }
 
        if (hapd->conf->ctrl_interface_gid_set &&
@@ -445,6 +467,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        hapd->ctrl_sock = s;
        eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
                                 NULL);
+       hapd->msg_ctx = hapd;
+       wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
 
        return 0;
 
@@ -494,8 +518,8 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
 }
 
 
-void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
-                            char *buf, size_t len)
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   const char *buf, size_t len)
 {
        struct wpa_ctrl_dst *dst, *next;
        struct msghdr msg;
@@ -510,7 +534,7 @@ void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
        os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
        io[0].iov_base = levelstr;
        io[0].iov_len = os_strlen(levelstr);
-       io[1].iov_base = buf;
+       io[1].iov_base = (char *) buf;
        io[1].iov_len = len;
        os_memset(&msg, 0, sizeof(msg));
        msg.msg_iov = io;
@@ -521,15 +545,17 @@ void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
                next = dst->next;
                if (level >= dst->debug_level) {
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
-                                   (u8 *) dst->addr.sun_path, dst->addrlen);
+                                   (u8 *) dst->addr.sun_path, dst->addrlen -
+                                   offsetof(struct sockaddr_un, sun_path));
                        msg.msg_name = &dst->addr;
                        msg.msg_namelen = dst->addrlen;
                        if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
-                               fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
-                                       idx);
-                               perror("sendmsg");
+                               int _errno = errno;
+                               wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+                                          "%d - %s",
+                                          idx, errno, strerror(errno));
                                dst->errors++;
-                               if (dst->errors > 10) {
+                               if (dst->errors > 10 || _errno == ENOENT) {
                                        hostapd_ctrl_iface_detach(
                                                hapd, &dst->addr,
                                                dst->addrlen);