139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA Supplicant / UNIX domain socket -based control interface 3c1d255d3SCy Schubert * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler #include <sys/un.h> 1139beb93cSSam Leffler #include <sys/stat.h> 1239beb93cSSam Leffler #include <grp.h> 13470736a0SSam Leffler #include <stddef.h> 14f05cddf9SRui Paulo #include <unistd.h> 15f05cddf9SRui Paulo #include <fcntl.h> 16325151a3SRui Paulo #ifdef __linux__ 17325151a3SRui Paulo #include <sys/ioctl.h> 18325151a3SRui Paulo #endif /* __linux__ */ 19f05cddf9SRui Paulo #ifdef ANDROID 20f05cddf9SRui Paulo #include <cutils/sockets.h> 21f05cddf9SRui Paulo #endif /* ANDROID */ 2239beb93cSSam Leffler 23e28a4053SRui Paulo #include "utils/common.h" 24e28a4053SRui Paulo #include "utils/eloop.h" 25e28a4053SRui Paulo #include "utils/list.h" 26780fb4a2SCy Schubert #include "common/ctrl_iface_common.h" 2739beb93cSSam Leffler #include "eapol_supp/eapol_supp_sm.h" 28e28a4053SRui Paulo #include "config.h" 2939beb93cSSam Leffler #include "wpa_supplicant_i.h" 3039beb93cSSam Leffler #include "ctrl_iface.h" 3139beb93cSSam Leffler 3239beb93cSSam Leffler /* Per-interface ctrl_iface */ 3339beb93cSSam Leffler 3439beb93cSSam Leffler struct ctrl_iface_priv { 3539beb93cSSam Leffler struct wpa_supplicant *wpa_s; 3639beb93cSSam Leffler int sock; 37e28a4053SRui Paulo struct dl_list ctrl_dst; 385b9c547cSRui Paulo int android_control_socket; 39780fb4a2SCy Schubert struct dl_list msg_queue; 40780fb4a2SCy Schubert unsigned int throttle_count; 4139beb93cSSam Leffler }; 4239beb93cSSam Leffler 4339beb93cSSam Leffler 445b9c547cSRui Paulo struct ctrl_iface_global_priv { 455b9c547cSRui Paulo struct wpa_global *global; 465b9c547cSRui Paulo int sock; 475b9c547cSRui Paulo struct dl_list ctrl_dst; 485b9c547cSRui Paulo int android_control_socket; 49780fb4a2SCy Schubert struct dl_list msg_queue; 50780fb4a2SCy Schubert unsigned int throttle_count; 51780fb4a2SCy Schubert }; 52780fb4a2SCy Schubert 53780fb4a2SCy Schubert struct ctrl_iface_msg { 54780fb4a2SCy Schubert struct dl_list list; 55780fb4a2SCy Schubert struct wpa_supplicant *wpa_s; 56780fb4a2SCy Schubert int level; 57780fb4a2SCy Schubert enum wpa_msg_type type; 58780fb4a2SCy Schubert const char *txt; 59780fb4a2SCy Schubert size_t len; 605b9c547cSRui Paulo }; 615b9c547cSRui Paulo 625b9c547cSRui Paulo 635b9c547cSRui Paulo static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, 645b9c547cSRui Paulo const char *ifname, int sock, 655b9c547cSRui Paulo struct dl_list *ctrl_dst, 6639beb93cSSam Leffler int level, const char *buf, 675b9c547cSRui Paulo size_t len, 685b9c547cSRui Paulo struct ctrl_iface_priv *priv, 695b9c547cSRui Paulo struct ctrl_iface_global_priv *gp); 705b9c547cSRui Paulo static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, 715b9c547cSRui Paulo struct ctrl_iface_priv *priv); 725b9c547cSRui Paulo static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, 735b9c547cSRui Paulo struct ctrl_iface_global_priv *priv); 7439beb93cSSam Leffler 7539beb93cSSam Leffler 76325151a3SRui Paulo static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, 77325151a3SRui Paulo size_t len) 78325151a3SRui Paulo { 79325151a3SRui Paulo #ifdef __linux__ 80325151a3SRui Paulo socklen_t optlen; 81325151a3SRui Paulo int sndbuf, outq; 82325151a3SRui Paulo int level = MSG_MSGDUMP; 83325151a3SRui Paulo 84325151a3SRui Paulo if (len >= 5 && os_strncmp(buf, "PONG\n", 5) == 0) 85325151a3SRui Paulo level = MSG_EXCESSIVE; 86325151a3SRui Paulo 87325151a3SRui Paulo optlen = sizeof(sndbuf); 88325151a3SRui Paulo sndbuf = 0; 89325151a3SRui Paulo if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) 90325151a3SRui Paulo sndbuf = -1; 91325151a3SRui Paulo 92780fb4a2SCy Schubert if (ioctl(sock, TIOCOUTQ, &outq) < 0) 93325151a3SRui Paulo outq = -1; 94325151a3SRui Paulo 95325151a3SRui Paulo wpa_printf(level, 96325151a3SRui Paulo "CTRL-DEBUG: %s: sock=%d sndbuf=%d outq=%d send_len=%d", 97325151a3SRui Paulo title, sock, sndbuf, outq, (int) len); 98325151a3SRui Paulo #endif /* __linux__ */ 99325151a3SRui Paulo } 100325151a3SRui Paulo 101325151a3SRui Paulo 1025b9c547cSRui Paulo static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, 103780fb4a2SCy Schubert struct sockaddr_storage *from, 1045b9c547cSRui Paulo socklen_t fromlen, int global) 10539beb93cSSam Leffler { 10685732ac8SCy Schubert return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL); 10739beb93cSSam Leffler } 10839beb93cSSam Leffler 10939beb93cSSam Leffler 1105b9c547cSRui Paulo static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, 111780fb4a2SCy Schubert struct sockaddr_storage *from, 11239beb93cSSam Leffler socklen_t fromlen) 11339beb93cSSam Leffler { 114780fb4a2SCy Schubert return ctrl_iface_detach(ctrl_dst, from, fromlen); 11539beb93cSSam Leffler } 11639beb93cSSam Leffler 11739beb93cSSam Leffler 11839beb93cSSam Leffler static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 119780fb4a2SCy Schubert struct sockaddr_storage *from, 12039beb93cSSam Leffler socklen_t fromlen, 12139beb93cSSam Leffler char *level) 12239beb93cSSam Leffler { 12339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 12439beb93cSSam Leffler 125780fb4a2SCy Schubert return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level); 12639beb93cSSam Leffler } 12739beb93cSSam Leffler 12839beb93cSSam Leffler 12939beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 13039beb93cSSam Leffler void *sock_ctx) 13139beb93cSSam Leffler { 13239beb93cSSam Leffler struct wpa_supplicant *wpa_s = eloop_ctx; 13339beb93cSSam Leffler struct ctrl_iface_priv *priv = sock_ctx; 134c1d255d3SCy Schubert char *buf; 13539beb93cSSam Leffler int res; 136780fb4a2SCy Schubert struct sockaddr_storage from; 13739beb93cSSam Leffler socklen_t fromlen = sizeof(from); 1385b9c547cSRui Paulo char *reply = NULL, *reply_buf = NULL; 13939beb93cSSam Leffler size_t reply_len = 0; 14039beb93cSSam Leffler int new_attached = 0; 14139beb93cSSam Leffler 142c1d255d3SCy Schubert buf = os_malloc(CTRL_IFACE_MAX_LEN + 1); 143c1d255d3SCy Schubert if (!buf) 144c1d255d3SCy Schubert return; 145c1d255d3SCy Schubert res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0, 14639beb93cSSam Leffler (struct sockaddr *) &from, &fromlen); 14739beb93cSSam Leffler if (res < 0) { 1485b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 1495b9c547cSRui Paulo strerror(errno)); 150c1d255d3SCy Schubert os_free(buf); 151c1d255d3SCy Schubert return; 152c1d255d3SCy Schubert } 153c1d255d3SCy Schubert if ((size_t) res > CTRL_IFACE_MAX_LEN) { 154c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated"); 155c1d255d3SCy Schubert os_free(buf); 15639beb93cSSam Leffler return; 15739beb93cSSam Leffler } 15839beb93cSSam Leffler buf[res] = '\0'; 15939beb93cSSam Leffler 16039beb93cSSam Leffler if (os_strcmp(buf, "ATTACH") == 0) { 1615b9c547cSRui Paulo if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, 1625b9c547cSRui Paulo fromlen, 0)) 16339beb93cSSam Leffler reply_len = 1; 16439beb93cSSam Leffler else { 16539beb93cSSam Leffler new_attached = 1; 16639beb93cSSam Leffler reply_len = 2; 16739beb93cSSam Leffler } 16839beb93cSSam Leffler } else if (os_strcmp(buf, "DETACH") == 0) { 1695b9c547cSRui Paulo if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, 1705b9c547cSRui Paulo fromlen)) 17139beb93cSSam Leffler reply_len = 1; 17239beb93cSSam Leffler else 17339beb93cSSam Leffler reply_len = 2; 17439beb93cSSam Leffler } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 17539beb93cSSam Leffler if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 17639beb93cSSam Leffler buf + 6)) 17739beb93cSSam Leffler reply_len = 1; 17839beb93cSSam Leffler else 17939beb93cSSam Leffler reply_len = 2; 18039beb93cSSam Leffler } else { 181*a90b9d01SCy Schubert sockaddr_print(wpas_ctrl_cmd_debug_level(buf), 182*a90b9d01SCy Schubert "Control interface recv command from:", 183*a90b9d01SCy Schubert &from, fromlen); 1845b9c547cSRui Paulo reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 18539beb93cSSam Leffler &reply_len); 1865b9c547cSRui Paulo reply = reply_buf; 187325151a3SRui Paulo 188325151a3SRui Paulo /* 189325151a3SRui Paulo * There could be some password/key material in the command, so 190325151a3SRui Paulo * clear the buffer explicitly now that it is not needed 191325151a3SRui Paulo * anymore. 192325151a3SRui Paulo */ 193325151a3SRui Paulo os_memset(buf, 0, res); 1945b9c547cSRui Paulo } 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo if (!reply && reply_len == 1) { 1975b9c547cSRui Paulo reply = "FAIL\n"; 1985b9c547cSRui Paulo reply_len = 5; 1995b9c547cSRui Paulo } else if (!reply && reply_len == 2) { 2005b9c547cSRui Paulo reply = "OK\n"; 2015b9c547cSRui Paulo reply_len = 3; 20239beb93cSSam Leffler } 20339beb93cSSam Leffler 20439beb93cSSam Leffler if (reply) { 205325151a3SRui Paulo wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply, 206325151a3SRui Paulo reply_len); 2075b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 2085b9c547cSRui Paulo fromlen) < 0) { 2095b9c547cSRui Paulo int _errno = errno; 2105b9c547cSRui Paulo wpa_dbg(wpa_s, MSG_DEBUG, 2115b9c547cSRui Paulo "ctrl_iface sendto failed: %d - %s", 2125b9c547cSRui Paulo _errno, strerror(_errno)); 2135b9c547cSRui Paulo if (_errno == ENOBUFS || _errno == EAGAIN) { 2145b9c547cSRui Paulo /* 2155b9c547cSRui Paulo * The socket send buffer could be full. This 2165b9c547cSRui Paulo * may happen if client programs are not 2175b9c547cSRui Paulo * receiving their pending messages. Close and 2185b9c547cSRui Paulo * reopen the socket as a workaround to avoid 2195b9c547cSRui Paulo * getting stuck being unable to send any new 2205b9c547cSRui Paulo * responses. 2215b9c547cSRui Paulo */ 2225b9c547cSRui Paulo sock = wpas_ctrl_iface_reinit(wpa_s, priv); 2235b9c547cSRui Paulo if (sock < 0) { 2245b9c547cSRui Paulo wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket"); 22539beb93cSSam Leffler } 2265b9c547cSRui Paulo } 2275b9c547cSRui Paulo if (new_attached) { 2285b9c547cSRui Paulo wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching"); 2295b9c547cSRui Paulo new_attached = 0; 2305b9c547cSRui Paulo wpa_supplicant_ctrl_iface_detach( 2315b9c547cSRui Paulo &priv->ctrl_dst, &from, fromlen); 2325b9c547cSRui Paulo } 2335b9c547cSRui Paulo } 2345b9c547cSRui Paulo } 2355b9c547cSRui Paulo os_free(reply_buf); 236c1d255d3SCy Schubert os_free(buf); 23739beb93cSSam Leffler 23839beb93cSSam Leffler if (new_attached) 23939beb93cSSam Leffler eapol_sm_notify_ctrl_attached(wpa_s->eapol); 24039beb93cSSam Leffler } 24139beb93cSSam Leffler 24239beb93cSSam Leffler 24339beb93cSSam Leffler static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) 24439beb93cSSam Leffler { 24539beb93cSSam Leffler char *buf; 24639beb93cSSam Leffler size_t len; 2475b9c547cSRui Paulo char *pbuf, *dir = NULL; 24839beb93cSSam Leffler int res; 24939beb93cSSam Leffler 25039beb93cSSam Leffler if (wpa_s->conf->ctrl_interface == NULL) 25139beb93cSSam Leffler return NULL; 25239beb93cSSam Leffler 25339beb93cSSam Leffler pbuf = os_strdup(wpa_s->conf->ctrl_interface); 25439beb93cSSam Leffler if (pbuf == NULL) 25539beb93cSSam Leffler return NULL; 25639beb93cSSam Leffler if (os_strncmp(pbuf, "DIR=", 4) == 0) { 2575b9c547cSRui Paulo char *gid_str; 25839beb93cSSam Leffler dir = pbuf + 4; 25939beb93cSSam Leffler gid_str = os_strstr(dir, " GROUP="); 2605b9c547cSRui Paulo if (gid_str) 26139beb93cSSam Leffler *gid_str = '\0'; 26239beb93cSSam Leffler } else 26339beb93cSSam Leffler dir = pbuf; 26439beb93cSSam Leffler 26539beb93cSSam Leffler len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; 26639beb93cSSam Leffler buf = os_malloc(len); 26739beb93cSSam Leffler if (buf == NULL) { 26839beb93cSSam Leffler os_free(pbuf); 26939beb93cSSam Leffler return NULL; 27039beb93cSSam Leffler } 27139beb93cSSam Leffler 27239beb93cSSam Leffler res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); 2735b9c547cSRui Paulo if (os_snprintf_error(len, res)) { 27439beb93cSSam Leffler os_free(pbuf); 27539beb93cSSam Leffler os_free(buf); 27639beb93cSSam Leffler return NULL; 27739beb93cSSam Leffler } 27839beb93cSSam Leffler #ifdef __CYGWIN__ 27939beb93cSSam Leffler { 28039beb93cSSam Leffler /* Windows/WinPcap uses interface names that are not suitable 28139beb93cSSam Leffler * as a file name - convert invalid chars to underscores */ 28239beb93cSSam Leffler char *pos = buf; 28339beb93cSSam Leffler while (*pos) { 28439beb93cSSam Leffler if (*pos == '\\') 28539beb93cSSam Leffler *pos = '_'; 28639beb93cSSam Leffler pos++; 28739beb93cSSam Leffler } 28839beb93cSSam Leffler } 28939beb93cSSam Leffler #endif /* __CYGWIN__ */ 29039beb93cSSam Leffler os_free(pbuf); 29139beb93cSSam Leffler return buf; 29239beb93cSSam Leffler } 29339beb93cSSam Leffler 29439beb93cSSam Leffler 295780fb4a2SCy Schubert static int wpas_ctrl_iface_throttle(int sock) 296780fb4a2SCy Schubert { 297780fb4a2SCy Schubert #ifdef __linux__ 298780fb4a2SCy Schubert socklen_t optlen; 299780fb4a2SCy Schubert int sndbuf, outq; 300780fb4a2SCy Schubert 301780fb4a2SCy Schubert optlen = sizeof(sndbuf); 302780fb4a2SCy Schubert sndbuf = 0; 303780fb4a2SCy Schubert if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 || 304780fb4a2SCy Schubert ioctl(sock, TIOCOUTQ, &outq) < 0 || 305780fb4a2SCy Schubert sndbuf <= 0 || outq < 0) 306780fb4a2SCy Schubert return 0; 307780fb4a2SCy Schubert return outq > sndbuf / 2; 308780fb4a2SCy Schubert #else /* __linux__ */ 309780fb4a2SCy Schubert return 0; 310780fb4a2SCy Schubert #endif /* __linux__ */ 311780fb4a2SCy Schubert } 312780fb4a2SCy Schubert 313780fb4a2SCy Schubert 314780fb4a2SCy Schubert static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global) 315780fb4a2SCy Schubert { 316780fb4a2SCy Schubert struct ctrl_iface_global_priv *gpriv; 317780fb4a2SCy Schubert struct ctrl_iface_msg *msg; 318780fb4a2SCy Schubert 319780fb4a2SCy Schubert gpriv = global->ctrl_iface; 320780fb4a2SCy Schubert while (gpriv && !dl_list_empty(&gpriv->msg_queue) && 321780fb4a2SCy Schubert !wpas_ctrl_iface_throttle(gpriv->sock)) { 322780fb4a2SCy Schubert msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg, 323780fb4a2SCy Schubert list); 324780fb4a2SCy Schubert if (!msg) 325780fb4a2SCy Schubert break; 326780fb4a2SCy Schubert dl_list_del(&msg->list); 327780fb4a2SCy Schubert wpa_supplicant_ctrl_iface_send( 328780fb4a2SCy Schubert msg->wpa_s, 329780fb4a2SCy Schubert msg->type != WPA_MSG_PER_INTERFACE ? 330780fb4a2SCy Schubert NULL : msg->wpa_s->ifname, 331780fb4a2SCy Schubert gpriv->sock, &gpriv->ctrl_dst, msg->level, 332780fb4a2SCy Schubert msg->txt, msg->len, NULL, gpriv); 333780fb4a2SCy Schubert os_free(msg); 334780fb4a2SCy Schubert } 335780fb4a2SCy Schubert } 336780fb4a2SCy Schubert 337780fb4a2SCy Schubert 338780fb4a2SCy Schubert static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s) 339780fb4a2SCy Schubert { 340780fb4a2SCy Schubert struct ctrl_iface_priv *priv; 341780fb4a2SCy Schubert struct ctrl_iface_msg *msg; 342780fb4a2SCy Schubert 343780fb4a2SCy Schubert priv = wpa_s->ctrl_iface; 344780fb4a2SCy Schubert while (priv && !dl_list_empty(&priv->msg_queue) && 345780fb4a2SCy Schubert !wpas_ctrl_iface_throttle(priv->sock)) { 346780fb4a2SCy Schubert msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg, 347780fb4a2SCy Schubert list); 348780fb4a2SCy Schubert if (!msg) 349780fb4a2SCy Schubert break; 350780fb4a2SCy Schubert dl_list_del(&msg->list); 351780fb4a2SCy Schubert wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, 352780fb4a2SCy Schubert &priv->ctrl_dst, msg->level, 353780fb4a2SCy Schubert msg->txt, msg->len, priv, NULL); 354780fb4a2SCy Schubert os_free(msg); 355780fb4a2SCy Schubert } 356780fb4a2SCy Schubert } 357780fb4a2SCy Schubert 358780fb4a2SCy Schubert 359780fb4a2SCy Schubert static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx) 360780fb4a2SCy Schubert { 361780fb4a2SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 362780fb4a2SCy Schubert struct ctrl_iface_priv *priv; 363780fb4a2SCy Schubert struct ctrl_iface_global_priv *gpriv; 364780fb4a2SCy Schubert int sock = -1, gsock = -1; 365780fb4a2SCy Schubert 366780fb4a2SCy Schubert wpas_ctrl_msg_send_pending_global(wpa_s->global); 367780fb4a2SCy Schubert wpas_ctrl_msg_send_pending_iface(wpa_s); 368780fb4a2SCy Schubert 369780fb4a2SCy Schubert priv = wpa_s->ctrl_iface; 370780fb4a2SCy Schubert if (priv && !dl_list_empty(&priv->msg_queue)) 371780fb4a2SCy Schubert sock = priv->sock; 372780fb4a2SCy Schubert 373780fb4a2SCy Schubert gpriv = wpa_s->global->ctrl_iface; 374780fb4a2SCy Schubert if (gpriv && !dl_list_empty(&gpriv->msg_queue)) 375780fb4a2SCy Schubert gsock = gpriv->sock; 376780fb4a2SCy Schubert 377780fb4a2SCy Schubert if (sock > -1 || gsock > -1) { 378780fb4a2SCy Schubert /* Continue pending message transmission from a timeout */ 379780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 380780fb4a2SCy Schubert "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)", 381780fb4a2SCy Schubert sock, gsock); 382780fb4a2SCy Schubert eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout, 383780fb4a2SCy Schubert wpa_s, NULL); 384780fb4a2SCy Schubert } 385780fb4a2SCy Schubert } 386780fb4a2SCy Schubert 387780fb4a2SCy Schubert 388780fb4a2SCy Schubert static void wpas_ctrl_msg_queue(struct dl_list *queue, 389780fb4a2SCy Schubert struct wpa_supplicant *wpa_s, int level, 390780fb4a2SCy Schubert enum wpa_msg_type type, 391780fb4a2SCy Schubert const char *txt, size_t len) 392780fb4a2SCy Schubert { 393780fb4a2SCy Schubert struct ctrl_iface_msg *msg; 394780fb4a2SCy Schubert 395780fb4a2SCy Schubert msg = os_zalloc(sizeof(*msg) + len); 396780fb4a2SCy Schubert if (!msg) 397780fb4a2SCy Schubert return; 398780fb4a2SCy Schubert 399780fb4a2SCy Schubert msg->wpa_s = wpa_s; 400780fb4a2SCy Schubert msg->level = level; 401780fb4a2SCy Schubert msg->type = type; 402780fb4a2SCy Schubert os_memcpy(msg + 1, txt, len); 403780fb4a2SCy Schubert msg->txt = (const char *) (msg + 1); 404780fb4a2SCy Schubert msg->len = len; 405780fb4a2SCy Schubert dl_list_add_tail(queue, &msg->list); 406780fb4a2SCy Schubert eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL); 407780fb4a2SCy Schubert eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL); 408780fb4a2SCy Schubert } 409780fb4a2SCy Schubert 410780fb4a2SCy Schubert 411780fb4a2SCy Schubert static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count, 412780fb4a2SCy Schubert struct dl_list *queue) 413780fb4a2SCy Schubert { 414780fb4a2SCy Schubert struct ctrl_iface_msg *msg; 415780fb4a2SCy Schubert 416780fb4a2SCy Schubert if (throttle_count < 2000) 417780fb4a2SCy Schubert return; 418780fb4a2SCy Schubert 419780fb4a2SCy Schubert msg = dl_list_first(queue, struct ctrl_iface_msg, list); 420780fb4a2SCy Schubert if (msg) { 421780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message"); 422780fb4a2SCy Schubert dl_list_del(&msg->list); 423780fb4a2SCy Schubert os_free(msg); 424780fb4a2SCy Schubert } 425780fb4a2SCy Schubert } 426780fb4a2SCy Schubert 427780fb4a2SCy Schubert 428325151a3SRui Paulo static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 429325151a3SRui Paulo enum wpa_msg_type type, 43039beb93cSSam Leffler const char *txt, size_t len) 43139beb93cSSam Leffler { 43239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 433780fb4a2SCy Schubert struct ctrl_iface_priv *priv; 434780fb4a2SCy Schubert struct ctrl_iface_global_priv *gpriv; 4355b9c547cSRui Paulo 4365b9c547cSRui Paulo if (wpa_s == NULL) 43739beb93cSSam Leffler return; 4385b9c547cSRui Paulo 439780fb4a2SCy Schubert gpriv = wpa_s->global->ctrl_iface; 440780fb4a2SCy Schubert 441780fb4a2SCy Schubert if (type != WPA_MSG_NO_GLOBAL && gpriv && 442780fb4a2SCy Schubert !dl_list_empty(&gpriv->ctrl_dst)) { 443780fb4a2SCy Schubert if (!dl_list_empty(&gpriv->msg_queue) || 444780fb4a2SCy Schubert wpas_ctrl_iface_throttle(gpriv->sock)) { 445780fb4a2SCy Schubert if (gpriv->throttle_count == 0) { 446780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 447780fb4a2SCy Schubert "CTRL: Had to throttle global event message for sock %d", 448780fb4a2SCy Schubert gpriv->sock); 449780fb4a2SCy Schubert } 450780fb4a2SCy Schubert gpriv->throttle_count++; 451780fb4a2SCy Schubert wpas_ctrl_msg_queue_limit(gpriv->throttle_count, 452780fb4a2SCy Schubert &gpriv->msg_queue); 453780fb4a2SCy Schubert wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level, 454780fb4a2SCy Schubert type, txt, len); 455780fb4a2SCy Schubert } else { 456780fb4a2SCy Schubert if (gpriv->throttle_count) { 457780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 458780fb4a2SCy Schubert "CTRL: Had to throttle %u global event message(s) for sock %d", 459780fb4a2SCy Schubert gpriv->throttle_count, gpriv->sock); 460780fb4a2SCy Schubert } 461780fb4a2SCy Schubert gpriv->throttle_count = 0; 462325151a3SRui Paulo wpa_supplicant_ctrl_iface_send( 463325151a3SRui Paulo wpa_s, 464325151a3SRui Paulo type != WPA_MSG_PER_INTERFACE ? 465325151a3SRui Paulo NULL : wpa_s->ifname, 466780fb4a2SCy Schubert gpriv->sock, &gpriv->ctrl_dst, level, 467780fb4a2SCy Schubert txt, len, NULL, gpriv); 4685b9c547cSRui Paulo } 4695b9c547cSRui Paulo } 4705b9c547cSRui Paulo 471780fb4a2SCy Schubert priv = wpa_s->ctrl_iface; 472780fb4a2SCy Schubert 473780fb4a2SCy Schubert if (type != WPA_MSG_ONLY_GLOBAL && priv) { 474780fb4a2SCy Schubert if (!dl_list_empty(&priv->msg_queue) || 475780fb4a2SCy Schubert wpas_ctrl_iface_throttle(priv->sock)) { 476780fb4a2SCy Schubert if (priv->throttle_count == 0) { 477780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 478780fb4a2SCy Schubert "CTRL: Had to throttle event message for sock %d", 479780fb4a2SCy Schubert priv->sock); 480780fb4a2SCy Schubert } 481780fb4a2SCy Schubert priv->throttle_count++; 482780fb4a2SCy Schubert wpas_ctrl_msg_queue_limit(priv->throttle_count, 483780fb4a2SCy Schubert &priv->msg_queue); 484780fb4a2SCy Schubert wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level, 485780fb4a2SCy Schubert type, txt, len); 486780fb4a2SCy Schubert } else { 487780fb4a2SCy Schubert if (priv->throttle_count) { 488780fb4a2SCy Schubert wpa_printf(MSG_MSGDUMP, 489780fb4a2SCy Schubert "CTRL: Had to throttle %u event message(s) for sock %d", 490780fb4a2SCy Schubert priv->throttle_count, priv->sock); 491780fb4a2SCy Schubert } 492780fb4a2SCy Schubert priv->throttle_count = 0; 493780fb4a2SCy Schubert wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, 494780fb4a2SCy Schubert &priv->ctrl_dst, level, 495780fb4a2SCy Schubert txt, len, priv, NULL); 496780fb4a2SCy Schubert } 497780fb4a2SCy Schubert } 49839beb93cSSam Leffler } 49939beb93cSSam Leffler 50039beb93cSSam Leffler 5015b9c547cSRui Paulo static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, 5025b9c547cSRui Paulo struct ctrl_iface_priv *priv) 50339beb93cSSam Leffler { 50439beb93cSSam Leffler struct sockaddr_un addr; 50539beb93cSSam Leffler char *fname = NULL; 50639beb93cSSam Leffler gid_t gid = 0; 50739beb93cSSam Leffler int gid_set = 0; 50839beb93cSSam Leffler char *buf, *dir = NULL, *gid_str = NULL; 50939beb93cSSam Leffler struct group *grp; 51039beb93cSSam Leffler char *endp; 511f05cddf9SRui Paulo int flags; 5121edc20b7SBjoern A. Zeeb #if defined(__FreeBSD__) 5131edc20b7SBjoern A. Zeeb int optval, rc; 5141edc20b7SBjoern A. Zeeb socklen_t optlen; 5151edc20b7SBjoern A. Zeeb #endif 51639beb93cSSam Leffler 51739beb93cSSam Leffler buf = os_strdup(wpa_s->conf->ctrl_interface); 51839beb93cSSam Leffler if (buf == NULL) 51939beb93cSSam Leffler goto fail; 520f05cddf9SRui Paulo #ifdef ANDROID 521f05cddf9SRui Paulo os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", 522f05cddf9SRui Paulo wpa_s->conf->ctrl_interface); 523f05cddf9SRui Paulo priv->sock = android_get_control_socket(addr.sun_path); 5245b9c547cSRui Paulo if (priv->sock >= 0) { 5255b9c547cSRui Paulo priv->android_control_socket = 1; 526f05cddf9SRui Paulo goto havesock; 5275b9c547cSRui Paulo } 528f05cddf9SRui Paulo #endif /* ANDROID */ 52939beb93cSSam Leffler if (os_strncmp(buf, "DIR=", 4) == 0) { 53039beb93cSSam Leffler dir = buf + 4; 53139beb93cSSam Leffler gid_str = os_strstr(dir, " GROUP="); 53239beb93cSSam Leffler if (gid_str) { 53339beb93cSSam Leffler *gid_str = '\0'; 53439beb93cSSam Leffler gid_str += 7; 53539beb93cSSam Leffler } 53639beb93cSSam Leffler } else { 53739beb93cSSam Leffler dir = buf; 53839beb93cSSam Leffler gid_str = wpa_s->conf->ctrl_interface_group; 53939beb93cSSam Leffler } 54039beb93cSSam Leffler 54139beb93cSSam Leffler if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { 54239beb93cSSam Leffler if (errno == EEXIST) { 54339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using existing control " 54439beb93cSSam Leffler "interface directory."); 54539beb93cSSam Leffler } else { 5465b9c547cSRui Paulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s", 5475b9c547cSRui Paulo dir, strerror(errno)); 54839beb93cSSam Leffler goto fail; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler } 55139beb93cSSam Leffler 552f05cddf9SRui Paulo #ifdef ANDROID 553f05cddf9SRui Paulo /* 554f05cddf9SRui Paulo * wpa_supplicant is started from /init.*.rc on Android and that seems 555f05cddf9SRui Paulo * to be using umask 0077 which would leave the control interface 556f05cddf9SRui Paulo * directory without group access. This breaks things since Wi-Fi 557f05cddf9SRui Paulo * framework assumes that this directory can be accessed by other 558f05cddf9SRui Paulo * applications in the wifi group. Fix this by adding group access even 559f05cddf9SRui Paulo * if umask value would prevent this. 560f05cddf9SRui Paulo */ 561f05cddf9SRui Paulo if (chmod(dir, S_IRWXU | S_IRWXG) < 0) { 562f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", 563f05cddf9SRui Paulo strerror(errno)); 564f05cddf9SRui Paulo /* Try to continue anyway */ 565f05cddf9SRui Paulo } 566f05cddf9SRui Paulo #endif /* ANDROID */ 567f05cddf9SRui Paulo 56839beb93cSSam Leffler if (gid_str) { 56939beb93cSSam Leffler grp = getgrnam(gid_str); 57039beb93cSSam Leffler if (grp) { 57139beb93cSSam Leffler gid = grp->gr_gid; 57239beb93cSSam Leffler gid_set = 1; 57339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 57439beb93cSSam Leffler " (from group name '%s')", 57539beb93cSSam Leffler (int) gid, gid_str); 57639beb93cSSam Leffler } else { 57739beb93cSSam Leffler /* Group name not found - try to parse this as gid */ 57839beb93cSSam Leffler gid = strtol(gid_str, &endp, 10); 57939beb93cSSam Leffler if (*gid_str == '\0' || *endp != '\0') { 58039beb93cSSam Leffler wpa_printf(MSG_ERROR, "CTRL: Invalid group " 58139beb93cSSam Leffler "'%s'", gid_str); 58239beb93cSSam Leffler goto fail; 58339beb93cSSam Leffler } 58439beb93cSSam Leffler gid_set = 1; 58539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 58639beb93cSSam Leffler (int) gid); 58739beb93cSSam Leffler } 58839beb93cSSam Leffler } 58939beb93cSSam Leffler 5904bc52338SCy Schubert if (gid_set && lchown(dir, -1, gid) < 0) { 5914bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s", 5925b9c547cSRui Paulo dir, (int) gid, strerror(errno)); 59339beb93cSSam Leffler goto fail; 59439beb93cSSam Leffler } 59539beb93cSSam Leffler 5963157ba21SRui Paulo /* Make sure the group can enter and read the directory */ 5973157ba21SRui Paulo if (gid_set && 5983157ba21SRui Paulo chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { 5993157ba21SRui Paulo wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", 6003157ba21SRui Paulo strerror(errno)); 6013157ba21SRui Paulo goto fail; 6023157ba21SRui Paulo } 6033157ba21SRui Paulo 60439beb93cSSam Leffler if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= 60539beb93cSSam Leffler sizeof(addr.sun_path)) { 60639beb93cSSam Leffler wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); 60739beb93cSSam Leffler goto fail; 60839beb93cSSam Leffler } 60939beb93cSSam Leffler 61039beb93cSSam Leffler priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 61139beb93cSSam Leffler if (priv->sock < 0) { 6125b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 61339beb93cSSam Leffler goto fail; 61439beb93cSSam Leffler } 61539beb93cSSam Leffler 61639beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 617e28a4053SRui Paulo #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 618470736a0SSam Leffler addr.sun_len = sizeof(addr); 6193157ba21SRui Paulo #endif /* __FreeBSD__ */ 62039beb93cSSam Leffler addr.sun_family = AF_UNIX; 62139beb93cSSam Leffler fname = wpa_supplicant_ctrl_iface_path(wpa_s); 62239beb93cSSam Leffler if (fname == NULL) 62339beb93cSSam Leffler goto fail; 62439beb93cSSam Leffler os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 62539beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 62639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 62739beb93cSSam Leffler strerror(errno)); 62839beb93cSSam Leffler if (connect(priv->sock, (struct sockaddr *) &addr, 62939beb93cSSam Leffler sizeof(addr)) < 0) { 63039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 63139beb93cSSam Leffler " allow connections - assuming it was left" 63239beb93cSSam Leffler "over from forced program termination"); 63339beb93cSSam Leffler if (unlink(fname) < 0) { 6345b9c547cSRui Paulo wpa_printf(MSG_ERROR, 6355b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s", 6365b9c547cSRui Paulo fname, strerror(errno)); 63739beb93cSSam Leffler goto fail; 63839beb93cSSam Leffler } 63939beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, 64039beb93cSSam Leffler sizeof(addr)) < 0) { 6415b9c547cSRui Paulo wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s", 6425b9c547cSRui Paulo strerror(errno)); 64339beb93cSSam Leffler goto fail; 64439beb93cSSam Leffler } 64539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 64639beb93cSSam Leffler "ctrl_iface socket '%s'", fname); 64739beb93cSSam Leffler } else { 64839beb93cSSam Leffler wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 64939beb93cSSam Leffler "be in use - cannot override it"); 65039beb93cSSam Leffler wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 65139beb93cSSam Leffler "not used anymore", fname); 65239beb93cSSam Leffler os_free(fname); 65339beb93cSSam Leffler fname = NULL; 65439beb93cSSam Leffler goto fail; 65539beb93cSSam Leffler } 65639beb93cSSam Leffler } 65739beb93cSSam Leffler 6584bc52338SCy Schubert if (gid_set && lchown(fname, -1, gid) < 0) { 6594bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s", 6605b9c547cSRui Paulo fname, (int) gid, strerror(errno)); 66139beb93cSSam Leffler goto fail; 66239beb93cSSam Leffler } 66339beb93cSSam Leffler 66439beb93cSSam Leffler if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 6655b9c547cSRui Paulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s", 6665b9c547cSRui Paulo fname, strerror(errno)); 66739beb93cSSam Leffler goto fail; 66839beb93cSSam Leffler } 66939beb93cSSam Leffler os_free(fname); 67039beb93cSSam Leffler 671f05cddf9SRui Paulo #ifdef ANDROID 672f05cddf9SRui Paulo havesock: 673f05cddf9SRui Paulo #endif /* ANDROID */ 674f05cddf9SRui Paulo 675f05cddf9SRui Paulo /* 676f05cddf9SRui Paulo * Make socket non-blocking so that we don't hang forever if 677f05cddf9SRui Paulo * target dies unexpectedly. 678f05cddf9SRui Paulo */ 679f05cddf9SRui Paulo flags = fcntl(priv->sock, F_GETFL); 680f05cddf9SRui Paulo if (flags >= 0) { 681f05cddf9SRui Paulo flags |= O_NONBLOCK; 682f05cddf9SRui Paulo if (fcntl(priv->sock, F_SETFL, flags) < 0) { 6835b9c547cSRui Paulo wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", 6845b9c547cSRui Paulo strerror(errno)); 685f05cddf9SRui Paulo /* Not fatal, continue on.*/ 686f05cddf9SRui Paulo } 687f05cddf9SRui Paulo } 688f05cddf9SRui Paulo 6891edc20b7SBjoern A. Zeeb #if defined(__FreeBSD__) 6901edc20b7SBjoern A. Zeeb /* Ensure we can send a full length message atomically. */ 6911edc20b7SBjoern A. Zeeb optval = 0; 6921edc20b7SBjoern A. Zeeb optlen = sizeof(optval); 6931edc20b7SBjoern A. Zeeb if (getsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) == -1) { 6941edc20b7SBjoern A. Zeeb wpa_printf(MSG_INFO, "failed to get sndbuf for sock=%d: %s", 6951edc20b7SBjoern A. Zeeb priv->sock, strerror(errno)); 6961edc20b7SBjoern A. Zeeb } else if (optval < CTRL_IFACE_MAX_LEN) { 6971edc20b7SBjoern A. Zeeb optval = CTRL_IFACE_MAX_LEN; 6981edc20b7SBjoern A. Zeeb if (setsockopt(priv->sock, SOL_SOCKET, SO_SNDBUF, &optval, 6991edc20b7SBjoern A. Zeeb sizeof(optval)) == -1) 7001edc20b7SBjoern A. Zeeb wpa_printf(MSG_ERROR, "failed to set sndbuf for " 7011edc20b7SBjoern A. Zeeb "sock=%d: %s", priv->sock, strerror(errno)); 7021edc20b7SBjoern A. Zeeb } 7031edc20b7SBjoern A. Zeeb #endif 7041edc20b7SBjoern A. Zeeb 70539beb93cSSam Leffler eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 70639beb93cSSam Leffler wpa_s, priv); 70739beb93cSSam Leffler wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 70839beb93cSSam Leffler 70939beb93cSSam Leffler os_free(buf); 7105b9c547cSRui Paulo return 0; 71139beb93cSSam Leffler 71239beb93cSSam Leffler fail: 7135b9c547cSRui Paulo if (priv->sock >= 0) { 71439beb93cSSam Leffler close(priv->sock); 7155b9c547cSRui Paulo priv->sock = -1; 7165b9c547cSRui Paulo } 71739beb93cSSam Leffler if (fname) { 71839beb93cSSam Leffler unlink(fname); 71939beb93cSSam Leffler os_free(fname); 72039beb93cSSam Leffler } 72139beb93cSSam Leffler os_free(buf); 7225b9c547cSRui Paulo return -1; 7235b9c547cSRui Paulo } 7245b9c547cSRui Paulo 7255b9c547cSRui Paulo 7265b9c547cSRui Paulo struct ctrl_iface_priv * 7275b9c547cSRui Paulo wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 7285b9c547cSRui Paulo { 7295b9c547cSRui Paulo struct ctrl_iface_priv *priv; 7305b9c547cSRui Paulo 7315b9c547cSRui Paulo priv = os_zalloc(sizeof(*priv)); 7325b9c547cSRui Paulo if (priv == NULL) 73339beb93cSSam Leffler return NULL; 7345b9c547cSRui Paulo dl_list_init(&priv->ctrl_dst); 735780fb4a2SCy Schubert dl_list_init(&priv->msg_queue); 7365b9c547cSRui Paulo priv->wpa_s = wpa_s; 7375b9c547cSRui Paulo priv->sock = -1; 7385b9c547cSRui Paulo 7395b9c547cSRui Paulo if (wpa_s->conf->ctrl_interface == NULL) 7405b9c547cSRui Paulo return priv; 7415b9c547cSRui Paulo 742325151a3SRui Paulo #ifdef ANDROID 743325151a3SRui Paulo if (wpa_s->global->params.ctrl_interface) { 744325151a3SRui Paulo int same = 0; 745325151a3SRui Paulo 746325151a3SRui Paulo if (wpa_s->global->params.ctrl_interface[0] == '/') { 747325151a3SRui Paulo if (os_strcmp(wpa_s->global->params.ctrl_interface, 748325151a3SRui Paulo wpa_s->conf->ctrl_interface) == 0) 749325151a3SRui Paulo same = 1; 750325151a3SRui Paulo } else if (os_strncmp(wpa_s->global->params.ctrl_interface, 751325151a3SRui Paulo "@android:", 9) == 0 || 752325151a3SRui Paulo os_strncmp(wpa_s->global->params.ctrl_interface, 753325151a3SRui Paulo "@abstract:", 10) == 0) { 754325151a3SRui Paulo char *pos; 755325151a3SRui Paulo 756325151a3SRui Paulo /* 757325151a3SRui Paulo * Currently, Android uses @android:wpa_* as the naming 758325151a3SRui Paulo * convention for the global ctrl interface. This logic 759325151a3SRui Paulo * needs to be revisited if the above naming convention 760325151a3SRui Paulo * is modified. 761325151a3SRui Paulo */ 762325151a3SRui Paulo pos = os_strchr(wpa_s->global->params.ctrl_interface, 763325151a3SRui Paulo '_'); 764325151a3SRui Paulo if (pos && 765325151a3SRui Paulo os_strcmp(pos + 1, 766325151a3SRui Paulo wpa_s->conf->ctrl_interface) == 0) 767325151a3SRui Paulo same = 1; 768325151a3SRui Paulo } 769325151a3SRui Paulo 770325151a3SRui Paulo if (same) { 771325151a3SRui Paulo /* 772325151a3SRui Paulo * The invalid configuration combination might be 773325151a3SRui Paulo * possible to hit in an Android OTA upgrade case, so 774325151a3SRui Paulo * instead of refusing to start the wpa_supplicant 775325151a3SRui Paulo * process, do not open the per-interface ctrl_iface 776325151a3SRui Paulo * and continue with the global control interface that 777325151a3SRui Paulo * was set from the command line since the Wi-Fi 778325151a3SRui Paulo * framework will use it for operations. 779325151a3SRui Paulo */ 780325151a3SRui Paulo wpa_printf(MSG_ERROR, 781325151a3SRui Paulo "global ctrl interface %s matches ctrl interface %s - do not open per-interface ctrl interface", 782325151a3SRui Paulo wpa_s->global->params.ctrl_interface, 783325151a3SRui Paulo wpa_s->conf->ctrl_interface); 784325151a3SRui Paulo return priv; 785325151a3SRui Paulo } 786325151a3SRui Paulo } 787325151a3SRui Paulo #endif /* ANDROID */ 788325151a3SRui Paulo 7895b9c547cSRui Paulo if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) { 7905b9c547cSRui Paulo os_free(priv); 7915b9c547cSRui Paulo return NULL; 7925b9c547cSRui Paulo } 7935b9c547cSRui Paulo 7945b9c547cSRui Paulo return priv; 7955b9c547cSRui Paulo } 7965b9c547cSRui Paulo 7975b9c547cSRui Paulo 7985b9c547cSRui Paulo static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, 7995b9c547cSRui Paulo struct ctrl_iface_priv *priv) 8005b9c547cSRui Paulo { 8015b9c547cSRui Paulo int res; 8025b9c547cSRui Paulo 8035b9c547cSRui Paulo if (priv->sock <= 0) 8045b9c547cSRui Paulo return -1; 8055b9c547cSRui Paulo 8065b9c547cSRui Paulo /* 8075b9c547cSRui Paulo * On Android, the control socket being used may be the socket 8085b9c547cSRui Paulo * that is created when wpa_supplicant is started as a /init.*.rc 8095b9c547cSRui Paulo * service. Such a socket is maintained as a key-value pair in 8105b9c547cSRui Paulo * Android's environment. Closing this control socket would leave us 8115b9c547cSRui Paulo * in a bad state with an invalid socket descriptor. 8125b9c547cSRui Paulo */ 8135b9c547cSRui Paulo if (priv->android_control_socket) 8145b9c547cSRui Paulo return priv->sock; 8155b9c547cSRui Paulo 8165b9c547cSRui Paulo eloop_unregister_read_sock(priv->sock); 8175b9c547cSRui Paulo close(priv->sock); 8185b9c547cSRui Paulo priv->sock = -1; 8195b9c547cSRui Paulo res = wpas_ctrl_iface_open_sock(wpa_s, priv); 8205b9c547cSRui Paulo if (res < 0) 8215b9c547cSRui Paulo return -1; 8225b9c547cSRui Paulo return priv->sock; 82339beb93cSSam Leffler } 82439beb93cSSam Leffler 82539beb93cSSam Leffler 826c1d255d3SCy Schubert static void 827c1d255d3SCy Schubert wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global *global, 828c1d255d3SCy Schubert struct wpa_supplicant *wpa_s) 829c1d255d3SCy Schubert { 830c1d255d3SCy Schubert struct ctrl_iface_global_priv *gpriv; 831c1d255d3SCy Schubert struct ctrl_iface_msg *msg, *prev_msg; 832c1d255d3SCy Schubert unsigned int count = 0; 833c1d255d3SCy Schubert 834c1d255d3SCy Schubert if (!global || !global->ctrl_iface) 835c1d255d3SCy Schubert return; 836c1d255d3SCy Schubert 837c1d255d3SCy Schubert gpriv = global->ctrl_iface; 838c1d255d3SCy Schubert dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue, 839c1d255d3SCy Schubert struct ctrl_iface_msg, list) { 840c1d255d3SCy Schubert if (msg->wpa_s == wpa_s) { 841c1d255d3SCy Schubert count++; 842c1d255d3SCy Schubert dl_list_del(&msg->list); 843c1d255d3SCy Schubert os_free(msg); 844c1d255d3SCy Schubert } 845c1d255d3SCy Schubert } 846c1d255d3SCy Schubert 847c1d255d3SCy Schubert if (count) { 848c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 849c1d255d3SCy Schubert "CTRL: Dropped %u pending message(s) for interface that is being removed", 850c1d255d3SCy Schubert count); 851c1d255d3SCy Schubert } 852c1d255d3SCy Schubert } 853c1d255d3SCy Schubert 854c1d255d3SCy Schubert 855c1d255d3SCy Schubert void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, 856c1d255d3SCy Schubert struct ctrl_iface_priv *priv) 85739beb93cSSam Leffler { 85839beb93cSSam Leffler struct wpa_ctrl_dst *dst, *prev; 859780fb4a2SCy Schubert struct ctrl_iface_msg *msg, *prev_msg; 860780fb4a2SCy Schubert struct ctrl_iface_global_priv *gpriv; 86139beb93cSSam Leffler 862c1d255d3SCy Schubert if (!priv) { 863c1d255d3SCy Schubert /* Control interface has not yet been initialized, so there is 864c1d255d3SCy Schubert * nothing to deinitialize here. However, there might be a 865c1d255d3SCy Schubert * pending message for this interface, so get rid of any such 866c1d255d3SCy Schubert * entry before completing interface removal. */ 867c1d255d3SCy Schubert wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s); 868c1d255d3SCy Schubert eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL); 869c1d255d3SCy Schubert return; 870c1d255d3SCy Schubert } 871c1d255d3SCy Schubert 87239beb93cSSam Leffler if (priv->sock > -1) { 87339beb93cSSam Leffler char *fname; 8745b9c547cSRui Paulo char *buf, *dir = NULL; 87539beb93cSSam Leffler eloop_unregister_read_sock(priv->sock); 876e28a4053SRui Paulo if (!dl_list_empty(&priv->ctrl_dst)) { 87739beb93cSSam Leffler /* 8785b9c547cSRui Paulo * Wait before closing the control socket if 87939beb93cSSam Leffler * there are any attached monitors in order to allow 88039beb93cSSam Leffler * them to receive any pending messages. 88139beb93cSSam Leffler */ 88239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 88339beb93cSSam Leffler "monitors to receive messages"); 8845b9c547cSRui Paulo os_sleep(0, 100000); 88539beb93cSSam Leffler } 88639beb93cSSam Leffler close(priv->sock); 88739beb93cSSam Leffler priv->sock = -1; 88839beb93cSSam Leffler fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); 88939beb93cSSam Leffler if (fname) { 89039beb93cSSam Leffler unlink(fname); 89139beb93cSSam Leffler os_free(fname); 89239beb93cSSam Leffler } 89339beb93cSSam Leffler 8945b9c547cSRui Paulo if (priv->wpa_s->conf->ctrl_interface == NULL) 8955b9c547cSRui Paulo goto free_dst; 89639beb93cSSam Leffler buf = os_strdup(priv->wpa_s->conf->ctrl_interface); 89739beb93cSSam Leffler if (buf == NULL) 89839beb93cSSam Leffler goto free_dst; 89939beb93cSSam Leffler if (os_strncmp(buf, "DIR=", 4) == 0) { 9005b9c547cSRui Paulo char *gid_str; 90139beb93cSSam Leffler dir = buf + 4; 90239beb93cSSam Leffler gid_str = os_strstr(dir, " GROUP="); 9035b9c547cSRui Paulo if (gid_str) 90439beb93cSSam Leffler *gid_str = '\0'; 90539beb93cSSam Leffler } else 90639beb93cSSam Leffler dir = buf; 90739beb93cSSam Leffler 90839beb93cSSam Leffler if (rmdir(dir) < 0) { 90939beb93cSSam Leffler if (errno == ENOTEMPTY) { 91039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Control interface " 91139beb93cSSam Leffler "directory not empty - leaving it " 91239beb93cSSam Leffler "behind"); 91339beb93cSSam Leffler } else { 9145b9c547cSRui Paulo wpa_printf(MSG_ERROR, 9155b9c547cSRui Paulo "rmdir[ctrl_interface=%s]: %s", 9165b9c547cSRui Paulo dir, strerror(errno)); 91739beb93cSSam Leffler } 91839beb93cSSam Leffler } 91939beb93cSSam Leffler os_free(buf); 92039beb93cSSam Leffler } 92139beb93cSSam Leffler 92239beb93cSSam Leffler free_dst: 923e28a4053SRui Paulo dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, 924780fb4a2SCy Schubert list) { 925780fb4a2SCy Schubert dl_list_del(&dst->list); 926e28a4053SRui Paulo os_free(dst); 927780fb4a2SCy Schubert } 928780fb4a2SCy Schubert dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, 929780fb4a2SCy Schubert struct ctrl_iface_msg, list) { 930780fb4a2SCy Schubert dl_list_del(&msg->list); 931780fb4a2SCy Schubert os_free(msg); 932780fb4a2SCy Schubert } 933780fb4a2SCy Schubert gpriv = priv->wpa_s->global->ctrl_iface; 934780fb4a2SCy Schubert if (gpriv) { 935780fb4a2SCy Schubert dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue, 936780fb4a2SCy Schubert struct ctrl_iface_msg, list) { 937780fb4a2SCy Schubert if (msg->wpa_s == priv->wpa_s) { 938780fb4a2SCy Schubert dl_list_del(&msg->list); 939780fb4a2SCy Schubert os_free(msg); 940780fb4a2SCy Schubert } 941780fb4a2SCy Schubert } 942780fb4a2SCy Schubert } 943c1d255d3SCy Schubert wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s); 944780fb4a2SCy Schubert eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL); 94539beb93cSSam Leffler os_free(priv); 94639beb93cSSam Leffler } 94739beb93cSSam Leffler 94839beb93cSSam Leffler 94939beb93cSSam Leffler /** 95039beb93cSSam Leffler * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors 9515b9c547cSRui Paulo * @ifname: Interface name for global control socket or %NULL 9525b9c547cSRui Paulo * @sock: Local socket fd 9535b9c547cSRui Paulo * @ctrl_dst: List of attached listeners 95439beb93cSSam Leffler * @level: Priority level of the message 95539beb93cSSam Leffler * @buf: Message data 95639beb93cSSam Leffler * @len: Message length 95739beb93cSSam Leffler * 95839beb93cSSam Leffler * Send a packet to all monitor programs attached to the control interface. 95939beb93cSSam Leffler */ 9605b9c547cSRui Paulo static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, 9615b9c547cSRui Paulo const char *ifname, int sock, 9625b9c547cSRui Paulo struct dl_list *ctrl_dst, 96339beb93cSSam Leffler int level, const char *buf, 9645b9c547cSRui Paulo size_t len, 9655b9c547cSRui Paulo struct ctrl_iface_priv *priv, 9665b9c547cSRui Paulo struct ctrl_iface_global_priv *gp) 96739beb93cSSam Leffler { 96839beb93cSSam Leffler struct wpa_ctrl_dst *dst, *next; 96939beb93cSSam Leffler char levelstr[10]; 97039beb93cSSam Leffler int idx, res; 97139beb93cSSam Leffler struct msghdr msg; 9725b9c547cSRui Paulo struct iovec io[5]; 97339beb93cSSam Leffler 9745b9c547cSRui Paulo if (sock < 0 || dl_list_empty(ctrl_dst)) 97539beb93cSSam Leffler return; 97639beb93cSSam Leffler 97739beb93cSSam Leffler res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 9785b9c547cSRui Paulo if (os_snprintf_error(sizeof(levelstr), res)) 97939beb93cSSam Leffler return; 9805b9c547cSRui Paulo idx = 0; 9815b9c547cSRui Paulo if (ifname) { 9825b9c547cSRui Paulo io[idx].iov_base = "IFNAME="; 9835b9c547cSRui Paulo io[idx].iov_len = 7; 9845b9c547cSRui Paulo idx++; 9855b9c547cSRui Paulo io[idx].iov_base = (char *) ifname; 9865b9c547cSRui Paulo io[idx].iov_len = os_strlen(ifname); 9875b9c547cSRui Paulo idx++; 9885b9c547cSRui Paulo io[idx].iov_base = " "; 9895b9c547cSRui Paulo io[idx].iov_len = 1; 9905b9c547cSRui Paulo idx++; 9915b9c547cSRui Paulo } 9925b9c547cSRui Paulo io[idx].iov_base = levelstr; 9935b9c547cSRui Paulo io[idx].iov_len = os_strlen(levelstr); 9945b9c547cSRui Paulo idx++; 9955b9c547cSRui Paulo io[idx].iov_base = (char *) buf; 9965b9c547cSRui Paulo io[idx].iov_len = len; 9975b9c547cSRui Paulo idx++; 99839beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg)); 99939beb93cSSam Leffler msg.msg_iov = io; 10005b9c547cSRui Paulo msg.msg_iovlen = idx; 100139beb93cSSam Leffler 10025b9c547cSRui Paulo dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { 10035b9c547cSRui Paulo int _errno; 1004780fb4a2SCy Schubert char txt[200]; 10055b9c547cSRui Paulo 10065b9c547cSRui Paulo if (level < dst->debug_level) 10075b9c547cSRui Paulo continue; 10085b9c547cSRui Paulo 100939beb93cSSam Leffler msg.msg_name = (void *) &dst->addr; 101039beb93cSSam Leffler msg.msg_namelen = dst->addrlen; 1011325151a3SRui Paulo wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); 10125b9c547cSRui Paulo if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { 1013780fb4a2SCy Schubert sockaddr_print(MSG_MSGDUMP, 1014780fb4a2SCy Schubert "CTRL_IFACE monitor sent successfully to", 1015780fb4a2SCy Schubert &dst->addr, dst->addrlen); 10165b9c547cSRui Paulo dst->errors = 0; 10175b9c547cSRui Paulo continue; 10185b9c547cSRui Paulo } 10195b9c547cSRui Paulo 10205b9c547cSRui Paulo _errno = errno; 1021780fb4a2SCy Schubert os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for", 1022780fb4a2SCy Schubert _errno, strerror(_errno)); 1023780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen); 102439beb93cSSam Leffler dst->errors++; 10255b9c547cSRui Paulo 10265b9c547cSRui Paulo if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { 1027780fb4a2SCy Schubert sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:", 1028780fb4a2SCy Schubert &dst->addr, dst->addrlen); 10295b9c547cSRui Paulo wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, 103039beb93cSSam Leffler dst->addrlen); 103139beb93cSSam Leffler } 10325b9c547cSRui Paulo 10335b9c547cSRui Paulo if (_errno == ENOBUFS || _errno == EAGAIN) { 10345b9c547cSRui Paulo /* 10355b9c547cSRui Paulo * The socket send buffer could be full. This may happen 10365b9c547cSRui Paulo * if client programs are not receiving their pending 10375b9c547cSRui Paulo * messages. Close and reopen the socket as a workaround 10385b9c547cSRui Paulo * to avoid getting stuck being unable to send any new 10395b9c547cSRui Paulo * responses. 10405b9c547cSRui Paulo */ 10415b9c547cSRui Paulo if (priv) 10425b9c547cSRui Paulo sock = wpas_ctrl_iface_reinit(wpa_s, priv); 10435b9c547cSRui Paulo else if (gp) 10445b9c547cSRui Paulo sock = wpas_ctrl_iface_global_reinit( 10455b9c547cSRui Paulo wpa_s->global, gp); 10465b9c547cSRui Paulo else 10475b9c547cSRui Paulo break; 10485b9c547cSRui Paulo if (sock < 0) { 10495b9c547cSRui Paulo wpa_dbg(wpa_s, MSG_DEBUG, 10505b9c547cSRui Paulo "Failed to reinitialize ctrl_iface socket"); 10515b9c547cSRui Paulo break; 105239beb93cSSam Leffler } 10535b9c547cSRui Paulo } 105439beb93cSSam Leffler } 105539beb93cSSam Leffler } 105639beb93cSSam Leffler 105739beb93cSSam Leffler 105839beb93cSSam Leffler void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 105939beb93cSSam Leffler { 106039beb93cSSam Leffler char buf[256]; 106139beb93cSSam Leffler int res; 1062780fb4a2SCy Schubert struct sockaddr_storage from; 106339beb93cSSam Leffler socklen_t fromlen = sizeof(from); 106439beb93cSSam Leffler 1065780fb4a2SCy Schubert if (priv->sock == -1) 1066780fb4a2SCy Schubert return; 1067780fb4a2SCy Schubert 106839beb93cSSam Leffler for (;;) { 106939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " 107039beb93cSSam Leffler "attach", priv->wpa_s->ifname); 107139beb93cSSam Leffler eloop_wait_for_read_sock(priv->sock); 107239beb93cSSam Leffler 107339beb93cSSam Leffler res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, 107439beb93cSSam Leffler (struct sockaddr *) &from, &fromlen); 107539beb93cSSam Leffler if (res < 0) { 10765b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 10775b9c547cSRui Paulo strerror(errno)); 107839beb93cSSam Leffler continue; 107939beb93cSSam Leffler } 108039beb93cSSam Leffler buf[res] = '\0'; 108139beb93cSSam Leffler 108239beb93cSSam Leffler if (os_strcmp(buf, "ATTACH") == 0) { 108339beb93cSSam Leffler /* handle ATTACH signal of first monitor interface */ 10845b9c547cSRui Paulo if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, 10855b9c547cSRui Paulo &from, fromlen, 10865b9c547cSRui Paulo 0)) { 10875b9c547cSRui Paulo if (sendto(priv->sock, "OK\n", 3, 0, 10885b9c547cSRui Paulo (struct sockaddr *) &from, fromlen) < 10895b9c547cSRui Paulo 0) { 10905b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 10915b9c547cSRui Paulo strerror(errno)); 10925b9c547cSRui Paulo } 109339beb93cSSam Leffler /* OK to continue */ 109439beb93cSSam Leffler return; 109539beb93cSSam Leffler } else { 10965b9c547cSRui Paulo if (sendto(priv->sock, "FAIL\n", 5, 0, 10975b9c547cSRui Paulo (struct sockaddr *) &from, fromlen) < 10985b9c547cSRui Paulo 0) { 10995b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 11005b9c547cSRui Paulo strerror(errno)); 11015b9c547cSRui Paulo } 110239beb93cSSam Leffler } 110339beb93cSSam Leffler } else { 110439beb93cSSam Leffler /* return FAIL for all other signals */ 11055b9c547cSRui Paulo if (sendto(priv->sock, "FAIL\n", 5, 0, 11065b9c547cSRui Paulo (struct sockaddr *) &from, fromlen) < 0) { 11075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 11085b9c547cSRui Paulo "ctrl_iface sendto failed: %s", 11095b9c547cSRui Paulo strerror(errno)); 11105b9c547cSRui Paulo } 111139beb93cSSam Leffler } 111239beb93cSSam Leffler } 111339beb93cSSam Leffler } 111439beb93cSSam Leffler 111539beb93cSSam Leffler 111639beb93cSSam Leffler /* Global ctrl_iface */ 111739beb93cSSam Leffler 111839beb93cSSam Leffler static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 111939beb93cSSam Leffler void *sock_ctx) 112039beb93cSSam Leffler { 112139beb93cSSam Leffler struct wpa_global *global = eloop_ctx; 11225b9c547cSRui Paulo struct ctrl_iface_global_priv *priv = sock_ctx; 1123c1d255d3SCy Schubert char *buf; 112439beb93cSSam Leffler int res; 1125780fb4a2SCy Schubert struct sockaddr_storage from; 112639beb93cSSam Leffler socklen_t fromlen = sizeof(from); 11275b9c547cSRui Paulo char *reply = NULL, *reply_buf = NULL; 112839beb93cSSam Leffler size_t reply_len; 112939beb93cSSam Leffler 1130c1d255d3SCy Schubert buf = os_malloc(CTRL_IFACE_MAX_LEN + 1); 1131c1d255d3SCy Schubert if (!buf) 1132c1d255d3SCy Schubert return; 1133c1d255d3SCy Schubert res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN + 1, 0, 113439beb93cSSam Leffler (struct sockaddr *) &from, &fromlen); 113539beb93cSSam Leffler if (res < 0) { 11365b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 11375b9c547cSRui Paulo strerror(errno)); 1138c1d255d3SCy Schubert os_free(buf); 1139c1d255d3SCy Schubert return; 1140c1d255d3SCy Schubert } 1141c1d255d3SCy Schubert if ((size_t) res > CTRL_IFACE_MAX_LEN) { 1142c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated"); 1143c1d255d3SCy Schubert os_free(buf); 114439beb93cSSam Leffler return; 114539beb93cSSam Leffler } 114639beb93cSSam Leffler buf[res] = '\0'; 114739beb93cSSam Leffler 11485b9c547cSRui Paulo if (os_strcmp(buf, "ATTACH") == 0) { 11495b9c547cSRui Paulo if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, 11505b9c547cSRui Paulo fromlen, 1)) 11515b9c547cSRui Paulo reply_len = 1; 11525b9c547cSRui Paulo else 11535b9c547cSRui Paulo reply_len = 2; 11545b9c547cSRui Paulo } else if (os_strcmp(buf, "DETACH") == 0) { 11555b9c547cSRui Paulo if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, 11565b9c547cSRui Paulo fromlen)) 11575b9c547cSRui Paulo reply_len = 1; 11585b9c547cSRui Paulo else 11595b9c547cSRui Paulo reply_len = 2; 11605b9c547cSRui Paulo } else { 11615b9c547cSRui Paulo reply_buf = wpa_supplicant_global_ctrl_iface_process( 11625b9c547cSRui Paulo global, buf, &reply_len); 11635b9c547cSRui Paulo reply = reply_buf; 1164325151a3SRui Paulo 1165325151a3SRui Paulo /* 1166325151a3SRui Paulo * There could be some password/key material in the command, so 1167325151a3SRui Paulo * clear the buffer explicitly now that it is not needed 1168325151a3SRui Paulo * anymore. 1169325151a3SRui Paulo */ 1170325151a3SRui Paulo os_memset(buf, 0, res); 11715b9c547cSRui Paulo } 11725b9c547cSRui Paulo 11735b9c547cSRui Paulo if (!reply && reply_len == 1) { 11745b9c547cSRui Paulo reply = "FAIL\n"; 11755b9c547cSRui Paulo reply_len = 5; 11765b9c547cSRui Paulo } else if (!reply && reply_len == 2) { 11775b9c547cSRui Paulo reply = "OK\n"; 11785b9c547cSRui Paulo reply_len = 3; 11795b9c547cSRui Paulo } 118039beb93cSSam Leffler 118139beb93cSSam Leffler if (reply) { 1182325151a3SRui Paulo wpas_ctrl_sock_debug("global_ctrl_sock-sendto", 1183325151a3SRui Paulo sock, reply, reply_len); 11845b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 11855b9c547cSRui Paulo fromlen) < 0) { 11865b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 11875b9c547cSRui Paulo strerror(errno)); 118839beb93cSSam Leffler } 118939beb93cSSam Leffler } 11905b9c547cSRui Paulo os_free(reply_buf); 1191c1d255d3SCy Schubert os_free(buf); 11925b9c547cSRui Paulo } 119339beb93cSSam Leffler 119439beb93cSSam Leffler 11955b9c547cSRui Paulo static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global, 11965b9c547cSRui Paulo struct ctrl_iface_global_priv *priv) 119739beb93cSSam Leffler { 119839beb93cSSam Leffler struct sockaddr_un addr; 11995b9c547cSRui Paulo const char *ctrl = global->params.ctrl_interface; 12005b9c547cSRui Paulo int flags; 120139beb93cSSam Leffler 12025b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl); 120339beb93cSSam Leffler 1204f05cddf9SRui Paulo #ifdef ANDROID 12055b9c547cSRui Paulo if (os_strncmp(ctrl, "@android:", 9) == 0) { 12065b9c547cSRui Paulo priv->sock = android_get_control_socket(ctrl + 9); 12075b9c547cSRui Paulo if (priv->sock < 0) { 12085b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to open Android control " 12095b9c547cSRui Paulo "socket '%s'", ctrl + 9); 12105b9c547cSRui Paulo goto fail; 12115b9c547cSRui Paulo } 12125b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using Android control socket '%s'", 12135b9c547cSRui Paulo ctrl + 9); 12145b9c547cSRui Paulo priv->android_control_socket = 1; 1215f05cddf9SRui Paulo goto havesock; 12165b9c547cSRui Paulo } 1217f05cddf9SRui Paulo 12185b9c547cSRui Paulo if (os_strncmp(ctrl, "@abstract:", 10) != 0) { 12195b9c547cSRui Paulo /* 12205b9c547cSRui Paulo * Backwards compatibility - try to open an Android control 12215b9c547cSRui Paulo * socket and if that fails, assume this was a UNIX domain 12225b9c547cSRui Paulo * socket instead. 12235b9c547cSRui Paulo */ 12245b9c547cSRui Paulo priv->sock = android_get_control_socket(ctrl); 12255b9c547cSRui Paulo if (priv->sock >= 0) { 12265b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 12275b9c547cSRui Paulo "Using Android control socket '%s'", 12285b9c547cSRui Paulo ctrl); 12295b9c547cSRui Paulo priv->android_control_socket = 1; 12305b9c547cSRui Paulo goto havesock; 12315b9c547cSRui Paulo } 12325b9c547cSRui Paulo } 12335b9c547cSRui Paulo #endif /* ANDROID */ 123439beb93cSSam Leffler 123539beb93cSSam Leffler priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 123639beb93cSSam Leffler if (priv->sock < 0) { 12375b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 123839beb93cSSam Leffler goto fail; 123939beb93cSSam Leffler } 124039beb93cSSam Leffler 124139beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 1242e28a4053SRui Paulo #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 1243470736a0SSam Leffler addr.sun_len = sizeof(addr); 12443157ba21SRui Paulo #endif /* __FreeBSD__ */ 124539beb93cSSam Leffler addr.sun_family = AF_UNIX; 12465b9c547cSRui Paulo 12475b9c547cSRui Paulo if (os_strncmp(ctrl, "@abstract:", 10) == 0) { 12485b9c547cSRui Paulo addr.sun_path[0] = '\0'; 12495b9c547cSRui Paulo os_strlcpy(addr.sun_path + 1, ctrl + 10, 12505b9c547cSRui Paulo sizeof(addr.sun_path) - 1); 12515b9c547cSRui Paulo if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 12525b9c547cSRui Paulo 0) { 12535b9c547cSRui Paulo wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: " 12545b9c547cSRui Paulo "bind(PF_UNIX;%s) failed: %s", 12555b9c547cSRui Paulo ctrl, strerror(errno)); 12565b9c547cSRui Paulo goto fail; 12575b9c547cSRui Paulo } 12585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'", 12595b9c547cSRui Paulo ctrl + 10); 12605b9c547cSRui Paulo goto havesock; 12615b9c547cSRui Paulo } 12625b9c547cSRui Paulo 12635b9c547cSRui Paulo os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path)); 126439beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 12655b9c547cSRui Paulo wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s", 12665b9c547cSRui Paulo ctrl, strerror(errno)); 126739beb93cSSam Leffler if (connect(priv->sock, (struct sockaddr *) &addr, 126839beb93cSSam Leffler sizeof(addr)) < 0) { 126939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 127039beb93cSSam Leffler " allow connections - assuming it was left" 127139beb93cSSam Leffler "over from forced program termination"); 12725b9c547cSRui Paulo if (unlink(ctrl) < 0) { 12735b9c547cSRui Paulo wpa_printf(MSG_ERROR, 12745b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s", 12755b9c547cSRui Paulo ctrl, strerror(errno)); 127639beb93cSSam Leffler goto fail; 127739beb93cSSam Leffler } 127839beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, 127939beb93cSSam Leffler sizeof(addr)) < 0) { 12805b9c547cSRui Paulo wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s", 12815b9c547cSRui Paulo ctrl, strerror(errno)); 128239beb93cSSam Leffler goto fail; 128339beb93cSSam Leffler } 128439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 128539beb93cSSam Leffler "ctrl_iface socket '%s'", 12865b9c547cSRui Paulo ctrl); 128739beb93cSSam Leffler } else { 128839beb93cSSam Leffler wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 128939beb93cSSam Leffler "be in use - cannot override it"); 129039beb93cSSam Leffler wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 129139beb93cSSam Leffler "not used anymore", 12925b9c547cSRui Paulo ctrl); 129339beb93cSSam Leffler goto fail; 129439beb93cSSam Leffler } 129539beb93cSSam Leffler } 129639beb93cSSam Leffler 12975b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl); 12985b9c547cSRui Paulo 12995b9c547cSRui Paulo if (global->params.ctrl_interface_group) { 13005b9c547cSRui Paulo char *gid_str = global->params.ctrl_interface_group; 13015b9c547cSRui Paulo gid_t gid = 0; 13025b9c547cSRui Paulo struct group *grp; 13035b9c547cSRui Paulo char *endp; 13045b9c547cSRui Paulo 13055b9c547cSRui Paulo grp = getgrnam(gid_str); 13065b9c547cSRui Paulo if (grp) { 13075b9c547cSRui Paulo gid = grp->gr_gid; 13085b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 13095b9c547cSRui Paulo " (from group name '%s')", 13105b9c547cSRui Paulo (int) gid, gid_str); 13115b9c547cSRui Paulo } else { 13125b9c547cSRui Paulo /* Group name not found - try to parse this as gid */ 13135b9c547cSRui Paulo gid = strtol(gid_str, &endp, 10); 13145b9c547cSRui Paulo if (*gid_str == '\0' || *endp != '\0') { 13155b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CTRL: Invalid group " 13165b9c547cSRui Paulo "'%s'", gid_str); 13175b9c547cSRui Paulo goto fail; 13185b9c547cSRui Paulo } 13195b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 13205b9c547cSRui Paulo (int) gid); 13215b9c547cSRui Paulo } 13224bc52338SCy Schubert if (lchown(ctrl, -1, gid) < 0) { 13235b9c547cSRui Paulo wpa_printf(MSG_ERROR, 13244bc52338SCy Schubert "lchown[global_ctrl_interface=%s,gid=%d]: %s", 13255b9c547cSRui Paulo ctrl, (int) gid, strerror(errno)); 13265b9c547cSRui Paulo goto fail; 13275b9c547cSRui Paulo } 13285b9c547cSRui Paulo 13295b9c547cSRui Paulo if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) { 13305b9c547cSRui Paulo wpa_printf(MSG_ERROR, 13315b9c547cSRui Paulo "chmod[global_ctrl_interface=%s]: %s", 13325b9c547cSRui Paulo ctrl, strerror(errno)); 13335b9c547cSRui Paulo goto fail; 13345b9c547cSRui Paulo } 13355b9c547cSRui Paulo } else { 13365b9c547cSRui Paulo if (chmod(ctrl, S_IRWXU) < 0) { 13375b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 13385b9c547cSRui Paulo "chmod[global_ctrl_interface=%s](S_IRWXU): %s", 13395b9c547cSRui Paulo ctrl, strerror(errno)); 13405b9c547cSRui Paulo /* continue anyway since group change was not required 13415b9c547cSRui Paulo */ 13425b9c547cSRui Paulo } 13435b9c547cSRui Paulo } 13445b9c547cSRui Paulo 1345f05cddf9SRui Paulo havesock: 13465b9c547cSRui Paulo 13475b9c547cSRui Paulo /* 13485b9c547cSRui Paulo * Make socket non-blocking so that we don't hang forever if 13495b9c547cSRui Paulo * target dies unexpectedly. 13505b9c547cSRui Paulo */ 13515b9c547cSRui Paulo flags = fcntl(priv->sock, F_GETFL); 13525b9c547cSRui Paulo if (flags >= 0) { 13535b9c547cSRui Paulo flags |= O_NONBLOCK; 13545b9c547cSRui Paulo if (fcntl(priv->sock, F_SETFL, flags) < 0) { 13555b9c547cSRui Paulo wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", 13565b9c547cSRui Paulo strerror(errno)); 13575b9c547cSRui Paulo /* Not fatal, continue on.*/ 13585b9c547cSRui Paulo } 13595b9c547cSRui Paulo } 13605b9c547cSRui Paulo 136139beb93cSSam Leffler eloop_register_read_sock(priv->sock, 136239beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_receive, 13635b9c547cSRui Paulo global, priv); 136439beb93cSSam Leffler 13655b9c547cSRui Paulo return 0; 136639beb93cSSam Leffler 136739beb93cSSam Leffler fail: 13685b9c547cSRui Paulo if (priv->sock >= 0) { 136939beb93cSSam Leffler close(priv->sock); 13705b9c547cSRui Paulo priv->sock = -1; 13715b9c547cSRui Paulo } 13725b9c547cSRui Paulo return -1; 13735b9c547cSRui Paulo } 13745b9c547cSRui Paulo 13755b9c547cSRui Paulo 13765b9c547cSRui Paulo struct ctrl_iface_global_priv * 13775b9c547cSRui Paulo wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 13785b9c547cSRui Paulo { 13795b9c547cSRui Paulo struct ctrl_iface_global_priv *priv; 13805b9c547cSRui Paulo 13815b9c547cSRui Paulo priv = os_zalloc(sizeof(*priv)); 13825b9c547cSRui Paulo if (priv == NULL) 13835b9c547cSRui Paulo return NULL; 13845b9c547cSRui Paulo dl_list_init(&priv->ctrl_dst); 1385780fb4a2SCy Schubert dl_list_init(&priv->msg_queue); 13865b9c547cSRui Paulo priv->global = global; 13875b9c547cSRui Paulo priv->sock = -1; 13885b9c547cSRui Paulo 13895b9c547cSRui Paulo if (global->params.ctrl_interface == NULL) 13905b9c547cSRui Paulo return priv; 13915b9c547cSRui Paulo 13925b9c547cSRui Paulo if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) { 139339beb93cSSam Leffler os_free(priv); 139439beb93cSSam Leffler return NULL; 139539beb93cSSam Leffler } 139639beb93cSSam Leffler 13975b9c547cSRui Paulo wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 13985b9c547cSRui Paulo 13995b9c547cSRui Paulo return priv; 14005b9c547cSRui Paulo } 14015b9c547cSRui Paulo 14025b9c547cSRui Paulo 14035b9c547cSRui Paulo static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, 14045b9c547cSRui Paulo struct ctrl_iface_global_priv *priv) 14055b9c547cSRui Paulo { 14065b9c547cSRui Paulo int res; 14075b9c547cSRui Paulo 14085b9c547cSRui Paulo if (priv->sock <= 0) 14095b9c547cSRui Paulo return -1; 14105b9c547cSRui Paulo 14115b9c547cSRui Paulo /* 14125b9c547cSRui Paulo * On Android, the control socket being used may be the socket 14135b9c547cSRui Paulo * that is created when wpa_supplicant is started as a /init.*.rc 14145b9c547cSRui Paulo * service. Such a socket is maintained as a key-value pair in 14155b9c547cSRui Paulo * Android's environment. Closing this control socket would leave us 14165b9c547cSRui Paulo * in a bad state with an invalid socket descriptor. 14175b9c547cSRui Paulo */ 14185b9c547cSRui Paulo if (priv->android_control_socket) 14195b9c547cSRui Paulo return priv->sock; 14205b9c547cSRui Paulo 14215b9c547cSRui Paulo eloop_unregister_read_sock(priv->sock); 14225b9c547cSRui Paulo close(priv->sock); 14235b9c547cSRui Paulo priv->sock = -1; 14245b9c547cSRui Paulo res = wpas_global_ctrl_iface_open_sock(global, priv); 14255b9c547cSRui Paulo if (res < 0) 14265b9c547cSRui Paulo return -1; 14275b9c547cSRui Paulo return priv->sock; 14285b9c547cSRui Paulo } 14295b9c547cSRui Paulo 143039beb93cSSam Leffler 143139beb93cSSam Leffler void 143239beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 143339beb93cSSam Leffler { 14345b9c547cSRui Paulo struct wpa_ctrl_dst *dst, *prev; 1435780fb4a2SCy Schubert struct ctrl_iface_msg *msg, *prev_msg; 14365b9c547cSRui Paulo 143739beb93cSSam Leffler if (priv->sock >= 0) { 143839beb93cSSam Leffler eloop_unregister_read_sock(priv->sock); 143939beb93cSSam Leffler close(priv->sock); 144039beb93cSSam Leffler } 144139beb93cSSam Leffler if (priv->global->params.ctrl_interface) 144239beb93cSSam Leffler unlink(priv->global->params.ctrl_interface); 14435b9c547cSRui Paulo dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, 1444780fb4a2SCy Schubert list) { 1445780fb4a2SCy Schubert dl_list_del(&dst->list); 14465b9c547cSRui Paulo os_free(dst); 1447780fb4a2SCy Schubert } 1448780fb4a2SCy Schubert dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, 1449780fb4a2SCy Schubert struct ctrl_iface_msg, list) { 1450780fb4a2SCy Schubert dl_list_del(&msg->list); 1451780fb4a2SCy Schubert os_free(msg); 1452780fb4a2SCy Schubert } 145339beb93cSSam Leffler os_free(priv); 145439beb93cSSam Leffler } 1455