Re-open ctrl_iface socket on some failure cases as a workaround
[mech_eap.git] / wpa_supplicant / ctrl_iface_unix.c
index aa71aff..faa773d 100644 (file)
@@ -57,10 +57,17 @@ struct ctrl_iface_global_priv {
 };
 
 
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+                                          const char *ifname, int sock,
                                           struct dl_list *ctrl_dst,
                                           int level, const char *buf,
-                                          size_t len);
+                                          size_t len,
+                                          struct ctrl_iface_priv *priv,
+                                          struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+                                 struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+                                        struct ctrl_iface_global_priv *priv);
 
 
 static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
@@ -94,12 +101,12 @@ static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
                    os_memcmp(from->sun_path, dst->addr.sun_path,
                              fromlen - offsetof(struct sockaddr_un, sun_path))
                    == 0) {
-                       dl_list_del(&dst->list);
-                       os_free(dst);
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
                                    (u8 *) from->sun_path,
                                    fromlen -
                                    offsetof(struct sockaddr_un, sun_path));
+                       dl_list_del(&dst->list);
+                       os_free(dst);
                        return 0;
                }
        }
@@ -143,14 +150,15 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
-       char *reply = NULL;
+       char *reply = NULL, *reply_buf = NULL;
        size_t reply_len = 0;
        int new_attached = 0;
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
        if (res < 0) {
-               perror("recvfrom(ctrl_iface)");
+               wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+                          strerror(errno));
                return;
        }
        buf[res] = '\0';
@@ -176,21 +184,49 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                else
                        reply_len = 2;
        } else {
-               reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
-                                                         &reply_len);
+               reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+                                                             &reply_len);
+               reply = reply_buf;
+       }
+
+       if (!reply && reply_len == 1) {
+               reply = "FAIL\n";
+               reply_len = 5;
+       } else if (!reply && reply_len == 2) {
+               reply = "OK\n";
+               reply_len = 3;
        }
 
        if (reply) {
-               sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-                      fromlen);
-               os_free(reply);
-       } else if (reply_len == 1) {
-               sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-                      fromlen);
-       } else if (reply_len == 2) {
-               sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
-                      fromlen);
+               if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+                          fromlen) < 0) {
+                       int _errno = errno;
+                       wpa_dbg(wpa_s, MSG_DEBUG,
+                               "ctrl_iface sendto failed: %d - %s",
+                               _errno, strerror(_errno));
+                       if (_errno == ENOBUFS || _errno == EAGAIN) {
+                               /*
+                                * The socket send buffer could be full. This
+                                * may happen if client programs are not
+                                * receiving their pending messages. Close and
+                                * reopen the socket as a workaround to avoid
+                                * getting stuck being unable to send any new
+                                * responses.
+                                */
+                               sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+                               if (sock < 0) {
+                                       wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+                               }
+                       }
+                       if (new_attached) {
+                               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+                               new_attached = 0;
+                               wpa_supplicant_ctrl_iface_detach(
+                                       &priv->ctrl_dst, &from, fromlen);
+                       }
+               }
        }
+       os_free(reply_buf);
 
        if (new_attached)
                eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -258,29 +294,30 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global,
        if (wpa_s == NULL)
                return;
 
-       if (wpa_s->global->ctrl_iface) {
+       if (global != 2 && wpa_s->global->ctrl_iface) {
                struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
                if (!dl_list_empty(&priv->ctrl_dst)) {
-                       wpa_supplicant_ctrl_iface_send(global ? NULL :
+                       wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
                                                       wpa_s->ifname,
                                                       priv->sock,
                                                       &priv->ctrl_dst,
-                                                      level, txt, len);
+                                                      level, txt, len, NULL,
+                                                      priv);
                }
        }
 
        if (wpa_s->ctrl_iface == NULL)
                return;
-       wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+       wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
                                       &wpa_s->ctrl_iface->ctrl_dst,
-                                      level, txt, len);
+                                      level, txt, len, wpa_s->ctrl_iface,
+                                      NULL);
 }
 
 
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+                                    struct ctrl_iface_priv *priv)
 {
-       struct ctrl_iface_priv *priv;
        struct sockaddr_un addr;
        char *fname = NULL;
        gid_t gid = 0;
@@ -290,16 +327,6 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        char *endp;
        int flags;
 
-       priv = os_zalloc(sizeof(*priv));
-       if (priv == NULL)
-               return NULL;
-       dl_list_init(&priv->ctrl_dst);
-       priv->wpa_s = wpa_s;
-       priv->sock = -1;
-
-       if (wpa_s->conf->ctrl_interface == NULL)
-               return priv;
-
        buf = os_strdup(wpa_s->conf->ctrl_interface);
        if (buf == NULL)
                goto fail;
@@ -327,7 +354,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                        wpa_printf(MSG_DEBUG, "Using existing control "
                                   "interface directory.");
                } else {
-                       perror("mkdir[ctrl_interface]");
+                       wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
+                                  dir, strerror(errno));
                        goto fail;
                }
        }
@@ -371,7 +399,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
 
        if (gid_set && chown(dir, -1, gid) < 0) {
-               perror("chown[ctrl_interface]");
+               wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+                          dir, (int) gid, strerror(errno));
                goto fail;
        }
 
@@ -391,7 +420,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 
        priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
-               perror("socket(PF_UNIX)");
+               wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
                goto fail;
        }
 
@@ -413,15 +442,15 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                                   " 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);
+                               wpa_printf(MSG_ERROR,
+                                          "Could not unlink existing ctrl_iface socket '%s': %s",
+                                          fname, strerror(errno));
                                goto fail;
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+                               wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
+                                          strerror(errno));
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -438,12 +467,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
 
        if (gid_set && chown(fname, -1, gid) < 0) {
-               perror("chown[ctrl_interface/ifname]");
+               wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+                          fname, (int) gid, strerror(errno));
                goto fail;
        }
 
        if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-               perror("chmod[ctrl_interface/ifname]");
+               wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
+                          fname, strerror(errno));
                goto fail;
        }
        os_free(fname);
@@ -460,7 +491,8 @@ havesock:
        if (flags >= 0) {
                flags |= O_NONBLOCK;
                if (fcntl(priv->sock, F_SETFL, flags) < 0) {
-                       perror("fcntl(ctrl, O_NONBLOCK)");
+                       wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+                                  strerror(errno));
                        /* Not fatal, continue on.*/
                }
        }
@@ -470,18 +502,61 @@ havesock:
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
 
        os_free(buf);
-       return priv;
+       return 0;
 
 fail:
-       if (priv->sock >= 0)
+       if (priv->sock >= 0) {
                close(priv->sock);
-       os_free(priv);
+               priv->sock = -1;
+       }
        if (fname) {
                unlink(fname);
                os_free(fname);
        }
        os_free(buf);
-       return NULL;
+       return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+       struct ctrl_iface_priv *priv;
+
+       priv = os_zalloc(sizeof(*priv));
+       if (priv == NULL)
+               return NULL;
+       dl_list_init(&priv->ctrl_dst);
+       priv->wpa_s = wpa_s;
+       priv->sock = -1;
+
+       if (wpa_s->conf->ctrl_interface == NULL)
+               return priv;
+
+       if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+               os_free(priv);
+               return NULL;
+       }
+
+       return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+                                 struct ctrl_iface_priv *priv)
+{
+       int res;
+
+       if (priv->sock <= 0)
+               return -1;
+
+       eloop_unregister_read_sock(priv->sock);
+       close(priv->sock);
+       priv->sock = -1;
+       res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+       if (res < 0)
+               return -1;
+       return priv->sock;
 }
 
 
@@ -495,13 +570,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
                eloop_unregister_read_sock(priv->sock);
                if (!dl_list_empty(&priv->ctrl_dst)) {
                        /*
-                        * Wait a second before closing the control socket if
+                        * Wait before closing the control socket if
                         * there are any attached monitors in order to allow
                         * them to receive any pending messages.
                         */
                        wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
                                   "monitors to receive messages");
-                       os_sleep(1, 0);
+                       os_sleep(0, 100000);
                }
                close(priv->sock);
                priv->sock = -1;
@@ -530,7 +605,9 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
                                           "directory not empty - leaving it "
                                           "behind");
                        } else {
-                               perror("rmdir[ctrl_interface]");
+                               wpa_printf(MSG_ERROR,
+                                          "rmdir[ctrl_interface=%s]: %s",
+                                          dir, strerror(errno));
                        }
                }
                os_free(buf);
@@ -555,10 +632,13 @@ free_dst:
  *
  * Send a packet to all monitor programs attached to the control interface.
  */
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+                                          const char *ifname, int sock,
                                           struct dl_list *ctrl_dst,
                                           int level, const char *buf,
-                                          size_t len)
+                                          size_t len,
+                                          struct ctrl_iface_priv *priv,
+                                          struct ctrl_iface_global_priv *gp)
 {
        struct wpa_ctrl_dst *dst, *next;
        char levelstr[10];
@@ -594,31 +674,56 @@ static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
        msg.msg_iov = io;
        msg.msg_iovlen = idx;
 
-       idx = 0;
+       idx = -1;
        dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
-               if (level >= dst->debug_level) {
-                       wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
-                                   (u8 *) dst->addr.sun_path, dst->addrlen -
-                                   offsetof(struct sockaddr_un, sun_path));
-                       msg.msg_name = (void *) &dst->addr;
-                       msg.msg_namelen = dst->addrlen;
-                       if (sendmsg(sock, &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 > 1000 ||
-                                   (_errno != ENOBUFS && dst->errors > 10) ||
-                                   _errno == ENOENT) {
-                                       wpa_supplicant_ctrl_iface_detach(
-                                               ctrl_dst, &dst->addr,
-                                               dst->addrlen);
-                               }
-                       } else
-                               dst->errors = 0;
-               }
+               int _errno;
+
                idx++;
+               if (level < dst->debug_level)
+                       continue;
+
+               wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+                           (u8 *) dst->addr.sun_path, dst->addrlen -
+                           offsetof(struct sockaddr_un, sun_path));
+               msg.msg_name = (void *) &dst->addr;
+               msg.msg_namelen = dst->addrlen;
+               if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+                       dst->errors = 0;
+                       idx++;
+                       continue;
+               }
+
+               _errno = errno;
+               wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: %d - %s",
+                          idx, errno, strerror(errno));
+               dst->errors++;
+
+               if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
+                       wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages");
+                       wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+                                                        dst->addrlen);
+               }
+
+               if (_errno == ENOBUFS || _errno == EAGAIN) {
+                       /*
+                        * The socket send buffer could be full. This may happen
+                        * if client programs are not receiving their pending
+                        * messages. Close and reopen the socket as a workaround
+                        * to avoid getting stuck being unable to send any new
+                        * responses.
+                        */
+                       if (priv)
+                               sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+                       else if (gp)
+                               sock = wpas_ctrl_iface_global_reinit(
+                                       wpa_s->global, gp);
+                       else
+                               break;
+                       if (sock < 0) {
+                               wpa_dbg(wpa_s, MSG_DEBUG,
+                                       "Failed to reinitialize ctrl_iface socket");
+                       }
+               }
        }
 }
 
@@ -638,7 +743,8 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
                res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
                               (struct sockaddr *) &from, &fromlen);
                if (res < 0) {
-                       perror("recvfrom(ctrl_iface)");
+                       wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+                                  strerror(errno));
                        continue;
                }
                buf[res] = '\0';
@@ -647,18 +753,30 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
                        /* handle ATTACH signal of first monitor interface */
                        if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
                                                              &from, fromlen)) {
-                               sendto(priv->sock, "OK\n", 3, 0,
-                                      (struct sockaddr *) &from, fromlen);
+                               if (sendto(priv->sock, "OK\n", 3, 0,
+                                          (struct sockaddr *) &from, fromlen) <
+                                   0) {
+                                       wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+                                                  strerror(errno));
+                               }
                                /* OK to continue */
                                return;
                        } else {
-                               sendto(priv->sock, "FAIL\n", 5, 0,
-                                      (struct sockaddr *) &from, fromlen);
+                               if (sendto(priv->sock, "FAIL\n", 5, 0,
+                                          (struct sockaddr *) &from, fromlen) <
+                                   0) {
+                                       wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+                                                  strerror(errno));
+                               }
                        }
                } else {
                        /* return FAIL for all other signals */
-                       sendto(priv->sock, "FAIL\n", 5, 0,
-                              (struct sockaddr *) &from, fromlen);
+                       if (sendto(priv->sock, "FAIL\n", 5, 0,
+                                  (struct sockaddr *) &from, fromlen) < 0) {
+                               wpa_printf(MSG_DEBUG,
+                                          "ctrl_iface sendto failed: %s",
+                                          strerror(errno));
+                       }
                }
        }
 }
@@ -675,13 +793,14 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
-       char *reply = NULL;
+       char *reply = NULL, *reply_buf = NULL;
        size_t reply_len;
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
        if (res < 0) {
-               perror("recvfrom(ctrl_iface)");
+               wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+                          strerror(errno));
                return;
        }
        buf[res] = '\0';
@@ -699,39 +818,36 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                else
                        reply_len = 2;
        } else {
-               reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-                                                                &reply_len);
+               reply_buf = wpa_supplicant_global_ctrl_iface_process(
+                       global, buf, &reply_len);
+               reply = reply_buf;
+       }
+
+       if (!reply && reply_len == 1) {
+               reply = "FAIL\n";
+               reply_len = 5;
+       } else if (!reply && reply_len == 2) {
+               reply = "OK\n";
+               reply_len = 3;
        }
 
        if (reply) {
-               sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-                      fromlen);
-               os_free(reply);
-       } else if (reply_len == 1) {
-               sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-                      fromlen);
-       } else if (reply_len == 2) {
-               sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
+               if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+                          fromlen) < 0) {
+                       wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+                               strerror(errno));
+               }
        }
+       os_free(reply_buf);
 }
 
 
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+                                           struct ctrl_iface_global_priv *priv)
 {
-       struct ctrl_iface_global_priv *priv;
        struct sockaddr_un addr;
        const char *ctrl = global->params.ctrl_interface;
-
-       priv = os_zalloc(sizeof(*priv));
-       if (priv == NULL)
-               return NULL;
-       dl_list_init(&priv->ctrl_dst);
-       priv->global = global;
-       priv->sock = -1;
-
-       if (ctrl == NULL)
-               return priv;
+       int flags;
 
        wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
 
@@ -766,7 +882,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 
        priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
-               perror("socket(PF_UNIX)");
+               wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
                goto fail;
        }
 
@@ -783,7 +899,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
                if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
                    0) {
                        wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
-                                  "bind(PF_UNIX) failed: %s", strerror(errno));
+                                  "bind(PF_UNIX;%s) failed: %s",
+                                  ctrl, strerror(errno));
                        goto fail;
                }
                wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
@@ -793,23 +910,23 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 
        os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
        if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("supp-global-ctrl-iface-init (will try fixup): "
-                      "bind(PF_UNIX)");
+               wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
+                          ctrl, strerror(errno));
                if (connect(priv->sock, (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(ctrl) < 0) {
-                               perror("unlink[ctrl_iface]");
-                               wpa_printf(MSG_ERROR, "Could not unlink "
-                                          "existing ctrl_iface socket '%s'",
-                                          ctrl);
+                               wpa_printf(MSG_ERROR,
+                                          "Could not unlink existing ctrl_iface socket '%s': %s",
+                                          ctrl, strerror(errno));
                                goto fail;
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("supp-glb-iface-init: bind(PF_UNIX)");
+                               wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
+                                          ctrl, strerror(errno));
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -851,12 +968,16 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
                                   (int) gid);
                }
                if (chown(ctrl, -1, gid) < 0) {
-                       perror("chown[global_ctrl_interface/ifname]");
+                       wpa_printf(MSG_ERROR,
+                                  "chown[global_ctrl_interface=%s,gid=%d]: %s",
+                                  ctrl, (int) gid, strerror(errno));
                        goto fail;
                }
 
                if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
-                       perror("chmod[global_ctrl_interface/ifname]");
+                       wpa_printf(MSG_ERROR,
+                                  "chmod[global_ctrl_interface=%s]: %s",
+                                  ctrl, strerror(errno));
                        goto fail;
                }
        } else {
@@ -864,17 +985,75 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        }
 
 havesock:
+
+       /*
+        * Make socket non-blocking so that we don't hang forever if
+        * target dies unexpectedly.
+        */
+       flags = fcntl(priv->sock, F_GETFL);
+       if (flags >= 0) {
+               flags |= O_NONBLOCK;
+               if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+                       wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+                                  strerror(errno));
+                       /* Not fatal, continue on.*/
+               }
+       }
+
        eloop_register_read_sock(priv->sock,
                                 wpa_supplicant_global_ctrl_iface_receive,
                                 global, priv);
 
-       return priv;
+       return 0;
 
 fail:
-       if (priv->sock >= 0)
+       if (priv->sock >= 0) {
                close(priv->sock);
-       os_free(priv);
-       return NULL;
+               priv->sock = -1;
+       }
+       return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+       struct ctrl_iface_global_priv *priv;
+
+       priv = os_zalloc(sizeof(*priv));
+       if (priv == NULL)
+               return NULL;
+       dl_list_init(&priv->ctrl_dst);
+       priv->global = global;
+       priv->sock = -1;
+
+       if (global->params.ctrl_interface == NULL)
+               return priv;
+
+       if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+               os_free(priv);
+               return NULL;
+       }
+
+       return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+                                        struct ctrl_iface_global_priv *priv)
+{
+       int res;
+
+       if (priv->sock <= 0)
+               return -1;
+
+       eloop_unregister_read_sock(priv->sock);
+       close(priv->sock);
+       priv->sock = -1;
+       res = wpas_global_ctrl_iface_open_sock(global, priv);
+       if (res < 0)
+               return -1;
+       return priv->sock;
 }