hostapd: Global control interface notifications
authorAnton Nayshtut <qca_antonn@qca.qualcomm.com>
Sun, 16 Nov 2014 14:52:49 +0000 (16:52 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 16 Jul 2015 09:33:29 +0000 (12:33 +0300)
This commit implements hostapd global control interface notifications
infrastructure. hostapd global control interface clients issue
ATTACH/DETACH commands to register and deregister with hostapd
correspondingly - the same way as for any other hostapd/wpa_supplicant
control interface.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
hostapd/ctrl_iface.c
hostapd/main.c
src/ap/hostapd.h
src/utils/wpa_debug.c
src/utils/wpa_debug.h
wpa_supplicant/ctrl_iface_unix.c

index 16add37..aa4c912 100644 (file)
@@ -58,6 +58,7 @@ struct wpa_ctrl_dst {
 
 
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   enum wpa_msg_type type,
                                    const char *buf, size_t len);
 
 
@@ -2229,7 +2230,7 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
        struct hostapd_data *hapd = ctx;
        if (hapd == NULL)
                return;
-       hostapd_ctrl_iface_send(hapd, level, txt, len);
+       hostapd_ctrl_iface_send(hapd, level, type, txt, len);
 }
 
 
@@ -2452,6 +2453,58 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
 }
 
 
+static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
+                                           struct sockaddr_un *from,
+                                           socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst;
+
+       dst = os_zalloc(sizeof(*dst));
+       if (dst == NULL)
+               return -1;
+       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+       dst->addrlen = fromlen;
+       dst->debug_level = MSG_INFO;
+       dst->next = interfaces->global_ctrl_dst;
+       interfaces->global_ctrl_dst = dst;
+       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
+                   from->sun_path,
+                   fromlen - offsetof(struct sockaddr_un, sun_path));
+       return 0;
+}
+
+
+static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
+                                           struct sockaddr_un *from,
+                                           socklen_t fromlen)
+{
+       struct wpa_ctrl_dst *dst, *prev = NULL;
+
+       dst = interfaces->global_ctrl_dst;
+       while (dst) {
+               if (fromlen == dst->addrlen &&
+                   os_memcmp(from->sun_path, dst->addr.sun_path,
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
+                       wpa_hexdump(MSG_DEBUG,
+                                   "CTRL_IFACE monitor detached (global)",
+                                   from->sun_path,
+                                   fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
+                       if (prev == NULL)
+                               interfaces->global_ctrl_dst = dst->next;
+                       else
+                               prev->next = dst->next;
+                       os_free(dst);
+                       return 0;
+               }
+               prev = dst;
+               dst = dst->next;
+       }
+       return -1;
+}
+
+
 static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
 {
 #ifdef CONFIG_WPS_TESTING
@@ -2470,8 +2523,9 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
-       char reply[24];
+       char *reply;
        int reply_len;
+       const int reply_size = 4096;
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
@@ -2483,6 +2537,16 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        buf[res] = '\0';
        wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
 
+       reply = os_malloc(reply_size);
+       if (reply == NULL) {
+               if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+                          fromlen) < 0) {
+                       wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+                                  strerror(errno));
+               }
+               return;
+       }
+
        os_memcpy(reply, "OK\n", 3);
        reply_len = 3;
 
@@ -2500,6 +2564,14 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
                if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
                        reply_len = -1;
+       } else if (os_strcmp(buf, "ATTACH") == 0) {
+               if (hostapd_global_ctrl_iface_attach(interfaces, &from,
+                                                    fromlen))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DETACH") == 0) {
+               if (hostapd_global_ctrl_iface_detach(interfaces, &from,
+                       fromlen))
+                       reply_len = -1;
 #ifdef CONFIG_MODULE_TESTS
        } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
                int hapd_module_tests(void);
@@ -2522,6 +2594,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
                           strerror(errno));
        }
+       os_free(reply);
 }
 
 
@@ -2659,6 +2732,7 @@ fail:
 void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
 {
        char *fname = NULL;
+       struct wpa_ctrl_dst *dst, *prev;
 
        if (interfaces->global_ctrl_sock > -1) {
                eloop_unregister_read_sock(interfaces->global_ctrl_sock);
@@ -2683,13 +2757,23 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
                                           strerror(errno));
                        }
                }
-               os_free(interfaces->global_iface_path);
-               interfaces->global_iface_path = NULL;
+       }
+
+       os_free(interfaces->global_iface_path);
+       interfaces->global_iface_path = NULL;
+
+       dst = interfaces->global_ctrl_dst;
+       interfaces->global_ctrl_dst = NULL;
+       while (dst) {
+               prev = dst;
+               dst = dst->next;
+               os_free(prev);
        }
 }
 
 
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+                                   enum wpa_msg_type type,
                                    const char *buf, size_t len)
 {
        struct wpa_ctrl_dst *dst, *next;
@@ -2697,9 +2781,17 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
        int idx;
        struct iovec io[2];
        char levelstr[10];
+       int s;
 
-       dst = hapd->ctrl_dst;
-       if (hapd->ctrl_sock < 0 || dst == NULL)
+       if (type != WPA_MSG_ONLY_GLOBAL) {
+               s = hapd->ctrl_sock;
+               dst = hapd->ctrl_dst;
+       } else {
+               s = hapd->iface->interfaces->global_ctrl_sock;
+               dst = hapd->iface->interfaces->global_ctrl_dst;
+       }
+
+       if (s < 0 || dst == NULL)
                return;
 
        os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -2720,16 +2812,22 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
                                    offsetof(struct sockaddr_un, sun_path));
                        msg.msg_name = &dst->addr;
                        msg.msg_namelen = dst->addrlen;
-                       if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+                       if (sendmsg(s, &msg, 0) < 0) {
                                int _errno = errno;
                                wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
                                           "%d - %s",
                                           idx, errno, strerror(errno));
                                dst->errors++;
                                if (dst->errors > 10 || _errno == ENOENT) {
-                                       hostapd_ctrl_iface_detach(
-                                               hapd, &dst->addr,
-                                               dst->addrlen);
+                                       if (type != WPA_MSG_ONLY_GLOBAL)
+                                               hostapd_ctrl_iface_detach(
+                                                       hapd, &dst->addr,
+                                                       dst->addrlen);
+                                       else
+                                               hostapd_global_ctrl_iface_detach(
+                                                       hapd->iface->interfaces,
+                                                       &dst->addr,
+                                                       dst->addrlen);
                                }
                        } else
                                dst->errors = 0;
index e36c948..62d0775 100644 (file)
@@ -561,6 +561,7 @@ int main(int argc, char *argv[])
        interfaces.global_iface_path = NULL;
        interfaces.global_iface_name = NULL;
        interfaces.global_ctrl_sock = -1;
+       interfaces.global_ctrl_dst = NULL;
 
        for (;;) {
                c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
index be5c7a8..dc71694 100644 (file)
@@ -41,6 +41,7 @@ struct hapd_interfaces {
 
        size_t count;
        int global_ctrl_sock;
+       struct wpa_ctrl_dst *global_ctrl_dst;
        char *global_iface_path;
        char *global_iface_name;
 #ifndef CONFIG_NATIVE_WINDOWS
index b7a6dba..3c26301 100644 (file)
@@ -749,6 +749,33 @@ void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
        bin_clear_free(buf, buflen);
 }
 
+
+void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
+{
+       va_list ap;
+       char *buf;
+       int buflen;
+       int len;
+
+       va_start(ap, fmt);
+       buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+       va_end(ap);
+
+       buf = os_malloc(buflen);
+       if (buf == NULL) {
+               wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer",
+                          __func__);
+               return;
+       }
+       va_start(ap, fmt);
+       len = vsnprintf(buf, buflen, fmt, ap);
+       va_end(ap);
+       wpa_printf(level, "%s", buf);
+       if (wpa_msg_cb)
+               wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
+       os_free(buf);
+}
+
 #endif /* CONFIG_NO_WPA_MSG */
 
 
index 5fdc50e..87bd7fa 100644 (file)
@@ -164,6 +164,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 #define wpa_msg_global(args...) do { } while (0)
 #define wpa_msg_global_ctrl(args...) do { } while (0)
 #define wpa_msg_no_global(args...) do { } while (0)
+#define wpa_msg_global_only(args...) do { } while (0)
 #define wpa_msg_register_cb(f) do { } while (0)
 #define wpa_msg_register_ifname_cb(f) do { } while (0)
 #else /* CONFIG_NO_WPA_MSG */
@@ -243,10 +244,25 @@ PRINTF_FORMAT(3, 4);
 void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
 PRINTF_FORMAT(3, 4);
 
+/**
+ * wpa_msg_global_only - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *     with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg_global(), but it sends the output only as a
+ * global event.
+ */
+void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
 enum wpa_msg_type {
        WPA_MSG_PER_INTERFACE,
        WPA_MSG_GLOBAL,
        WPA_MSG_NO_GLOBAL,
+       WPA_MSG_ONLY_GLOBAL,
 };
 
 typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type,
index f49ba07..d7e8d26 100644 (file)
@@ -316,13 +316,14 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
                if (!dl_list_empty(&priv->ctrl_dst)) {
                        wpa_supplicant_ctrl_iface_send(
                                wpa_s,
-                               type == WPA_MSG_GLOBAL ? NULL : wpa_s->ifname,
+                               type != WPA_MSG_PER_INTERFACE ?
+                               NULL : wpa_s->ifname,
                                priv->sock, &priv->ctrl_dst, level, txt, len,
                                NULL, priv);
                }
        }
 
-       if (wpa_s->ctrl_iface == NULL)
+       if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL)
                return;
        wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
                                       &wpa_s->ctrl_iface->ctrl_dst,