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
wpas_ctrl_sock_debug(const char * title,int sock,const char * buf,size_t len)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
wpa_supplicant_ctrl_iface_attach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen,int global)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
wpa_supplicant_ctrl_iface_detach(struct dl_list * ctrl_dst,struct sockaddr_storage * from,socklen_t fromlen)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
wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv * priv,struct sockaddr_storage * from,socklen_t fromlen,char * level)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
wpa_supplicant_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)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
wpa_supplicant_ctrl_iface_path(struct wpa_supplicant * wpa_s)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
wpas_ctrl_iface_throttle(int sock)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
wpas_ctrl_msg_send_pending_global(struct wpa_global * global)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
wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant * wpa_s)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
wpas_ctrl_msg_queue_timeout(void * eloop_ctx,void * timeout_ctx)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
wpas_ctrl_msg_queue(struct dl_list * queue,struct wpa_supplicant * wpa_s,int level,enum wpa_msg_type type,const char * txt,size_t len)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
wpas_ctrl_msg_queue_limit(unsigned int throttle_count,struct dl_list * queue)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
wpa_supplicant_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)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
wpas_ctrl_iface_open_sock(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)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 *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant * wpa_s)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
wpas_ctrl_iface_reinit(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)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
wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global * global,struct wpa_supplicant * wpa_s)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
wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)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 */
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,struct ctrl_iface_priv * priv,struct ctrl_iface_global_priv * gp)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
wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv * priv)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
wpa_supplicant_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)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
wpas_global_ctrl_iface_open_sock(struct wpa_global * global,struct ctrl_iface_global_priv * priv)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 *
wpa_supplicant_global_ctrl_iface_init(struct wpa_global * global)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
wpas_ctrl_iface_global_reinit(struct wpa_global * global,struct ctrl_iface_global_priv * priv)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
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv * priv)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