1189251Ssam/* 2189251Ssam * WPA Supplicant / UNIX domain socket -based control interface 3214734Srpaulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam#include <sys/un.h> 17189251Ssam#include <sys/stat.h> 18189251Ssam#include <grp.h> 19189775Ssam#include <stddef.h> 20189251Ssam 21214734Srpaulo#include "utils/common.h" 22214734Srpaulo#include "utils/eloop.h" 23214734Srpaulo#include "utils/list.h" 24214734Srpaulo#include "eapol_supp/eapol_supp_sm.h" 25189251Ssam#include "config.h" 26189251Ssam#include "wpa_supplicant_i.h" 27189251Ssam#include "ctrl_iface.h" 28189251Ssam 29189251Ssam/* Per-interface ctrl_iface */ 30189251Ssam 31189251Ssam/** 32189251Ssam * struct wpa_ctrl_dst - Internal data structure of control interface monitors 33189251Ssam * 34189251Ssam * This structure is used to store information about registered control 35189251Ssam * interface monitors into struct wpa_supplicant. This data is private to 36189251Ssam * ctrl_iface_unix.c and should not be touched directly from other files. 37189251Ssam */ 38189251Ssamstruct wpa_ctrl_dst { 39214734Srpaulo struct dl_list list; 40189251Ssam struct sockaddr_un addr; 41189251Ssam socklen_t addrlen; 42189251Ssam int debug_level; 43189251Ssam int errors; 44189251Ssam}; 45189251Ssam 46189251Ssam 47189251Ssamstruct ctrl_iface_priv { 48189251Ssam struct wpa_supplicant *wpa_s; 49189251Ssam int sock; 50214734Srpaulo struct dl_list ctrl_dst; 51189251Ssam}; 52189251Ssam 53189251Ssam 54189251Ssamstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 55189251Ssam int level, const char *buf, 56189251Ssam size_t len); 57189251Ssam 58189251Ssam 59189251Ssamstatic int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, 60189251Ssam struct sockaddr_un *from, 61189251Ssam socklen_t fromlen) 62189251Ssam{ 63189251Ssam struct wpa_ctrl_dst *dst; 64189251Ssam 65189251Ssam dst = os_zalloc(sizeof(*dst)); 66189251Ssam if (dst == NULL) 67189251Ssam return -1; 68189251Ssam os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 69189251Ssam dst->addrlen = fromlen; 70189251Ssam dst->debug_level = MSG_INFO; 71214734Srpaulo dl_list_add(&priv->ctrl_dst, &dst->list); 72189251Ssam wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 73189775Ssam (u8 *) from->sun_path, 74189775Ssam fromlen - offsetof(struct sockaddr_un, sun_path)); 75189251Ssam return 0; 76189251Ssam} 77189251Ssam 78189251Ssam 79189251Ssamstatic int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, 80189251Ssam struct sockaddr_un *from, 81189251Ssam socklen_t fromlen) 82189251Ssam{ 83214734Srpaulo struct wpa_ctrl_dst *dst; 84189251Ssam 85214734Srpaulo dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { 86189251Ssam if (fromlen == dst->addrlen && 87189251Ssam os_memcmp(from->sun_path, dst->addr.sun_path, 88209158Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 89209158Srpaulo == 0) { 90214734Srpaulo dl_list_del(&dst->list); 91189251Ssam os_free(dst); 92189251Ssam wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 93189251Ssam (u8 *) from->sun_path, 94209158Srpaulo fromlen - 95209158Srpaulo offsetof(struct sockaddr_un, sun_path)); 96189251Ssam return 0; 97189251Ssam } 98189251Ssam } 99189251Ssam return -1; 100189251Ssam} 101189251Ssam 102189251Ssam 103189251Ssamstatic int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 104189251Ssam struct sockaddr_un *from, 105189251Ssam socklen_t fromlen, 106189251Ssam char *level) 107189251Ssam{ 108189251Ssam struct wpa_ctrl_dst *dst; 109189251Ssam 110189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 111189251Ssam 112214734Srpaulo dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { 113189251Ssam if (fromlen == dst->addrlen && 114189251Ssam os_memcmp(from->sun_path, dst->addr.sun_path, 115209158Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 116209158Srpaulo == 0) { 117189251Ssam wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 118189251Ssam "level", (u8 *) from->sun_path, 119209158Srpaulo fromlen - 120209158Srpaulo offsetof(struct sockaddr_un, sun_path)); 121189251Ssam dst->debug_level = atoi(level); 122189251Ssam return 0; 123189251Ssam } 124189251Ssam } 125189251Ssam 126189251Ssam return -1; 127189251Ssam} 128189251Ssam 129189251Ssam 130189251Ssamstatic void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 131189251Ssam void *sock_ctx) 132189251Ssam{ 133189251Ssam struct wpa_supplicant *wpa_s = eloop_ctx; 134189251Ssam struct ctrl_iface_priv *priv = sock_ctx; 135189251Ssam char buf[256]; 136189251Ssam int res; 137189251Ssam struct sockaddr_un from; 138189251Ssam socklen_t fromlen = sizeof(from); 139189251Ssam char *reply = NULL; 140189251Ssam size_t reply_len = 0; 141189251Ssam int new_attached = 0; 142189251Ssam 143189251Ssam res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 144189251Ssam (struct sockaddr *) &from, &fromlen); 145189251Ssam if (res < 0) { 146189251Ssam perror("recvfrom(ctrl_iface)"); 147189251Ssam return; 148189251Ssam } 149189251Ssam buf[res] = '\0'; 150189251Ssam 151189251Ssam if (os_strcmp(buf, "ATTACH") == 0) { 152189251Ssam if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) 153189251Ssam reply_len = 1; 154189251Ssam else { 155189251Ssam new_attached = 1; 156189251Ssam reply_len = 2; 157189251Ssam } 158189251Ssam } else if (os_strcmp(buf, "DETACH") == 0) { 159189251Ssam if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) 160189251Ssam reply_len = 1; 161189251Ssam else 162189251Ssam reply_len = 2; 163189251Ssam } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 164189251Ssam if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 165189251Ssam buf + 6)) 166189251Ssam reply_len = 1; 167189251Ssam else 168189251Ssam reply_len = 2; 169189251Ssam } else { 170189251Ssam reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 171189251Ssam &reply_len); 172189251Ssam } 173189251Ssam 174189251Ssam if (reply) { 175189251Ssam sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 176189251Ssam fromlen); 177189251Ssam os_free(reply); 178189251Ssam } else if (reply_len == 1) { 179189251Ssam sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 180189251Ssam fromlen); 181189251Ssam } else if (reply_len == 2) { 182189251Ssam sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, 183189251Ssam fromlen); 184189251Ssam } 185189251Ssam 186189251Ssam if (new_attached) 187189251Ssam eapol_sm_notify_ctrl_attached(wpa_s->eapol); 188189251Ssam} 189189251Ssam 190189251Ssam 191189251Ssamstatic char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) 192189251Ssam{ 193189251Ssam char *buf; 194189251Ssam size_t len; 195189251Ssam char *pbuf, *dir = NULL, *gid_str = NULL; 196189251Ssam int res; 197189251Ssam 198189251Ssam if (wpa_s->conf->ctrl_interface == NULL) 199189251Ssam return NULL; 200189251Ssam 201189251Ssam pbuf = os_strdup(wpa_s->conf->ctrl_interface); 202189251Ssam if (pbuf == NULL) 203189251Ssam return NULL; 204189251Ssam if (os_strncmp(pbuf, "DIR=", 4) == 0) { 205189251Ssam dir = pbuf + 4; 206189251Ssam gid_str = os_strstr(dir, " GROUP="); 207189251Ssam if (gid_str) { 208189251Ssam *gid_str = '\0'; 209189251Ssam gid_str += 7; 210189251Ssam } 211189251Ssam } else 212189251Ssam dir = pbuf; 213189251Ssam 214189251Ssam len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; 215189251Ssam buf = os_malloc(len); 216189251Ssam if (buf == NULL) { 217189251Ssam os_free(pbuf); 218189251Ssam return NULL; 219189251Ssam } 220189251Ssam 221189251Ssam res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); 222189251Ssam if (res < 0 || (size_t) res >= len) { 223189251Ssam os_free(pbuf); 224189251Ssam os_free(buf); 225189251Ssam return NULL; 226189251Ssam } 227189251Ssam#ifdef __CYGWIN__ 228189251Ssam { 229189251Ssam /* Windows/WinPcap uses interface names that are not suitable 230189251Ssam * as a file name - convert invalid chars to underscores */ 231189251Ssam char *pos = buf; 232189251Ssam while (*pos) { 233189251Ssam if (*pos == '\\') 234189251Ssam *pos = '_'; 235189251Ssam pos++; 236189251Ssam } 237189251Ssam } 238189251Ssam#endif /* __CYGWIN__ */ 239189251Ssam os_free(pbuf); 240189251Ssam return buf; 241189251Ssam} 242189251Ssam 243189251Ssam 244189251Ssamstatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 245189251Ssam const char *txt, size_t len) 246189251Ssam{ 247189251Ssam struct wpa_supplicant *wpa_s = ctx; 248189251Ssam if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 249189251Ssam return; 250189251Ssam wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 251189251Ssam} 252189251Ssam 253189251Ssam 254189251Ssamstruct ctrl_iface_priv * 255189251Ssamwpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 256189251Ssam{ 257189251Ssam struct ctrl_iface_priv *priv; 258189251Ssam struct sockaddr_un addr; 259189251Ssam char *fname = NULL; 260189251Ssam gid_t gid = 0; 261189251Ssam int gid_set = 0; 262189251Ssam char *buf, *dir = NULL, *gid_str = NULL; 263189251Ssam struct group *grp; 264189251Ssam char *endp; 265189251Ssam 266189251Ssam priv = os_zalloc(sizeof(*priv)); 267189251Ssam if (priv == NULL) 268189251Ssam return NULL; 269214734Srpaulo dl_list_init(&priv->ctrl_dst); 270189251Ssam priv->wpa_s = wpa_s; 271189251Ssam priv->sock = -1; 272189251Ssam 273189251Ssam if (wpa_s->conf->ctrl_interface == NULL) 274189251Ssam return priv; 275189251Ssam 276189251Ssam buf = os_strdup(wpa_s->conf->ctrl_interface); 277189251Ssam if (buf == NULL) 278189251Ssam goto fail; 279189251Ssam if (os_strncmp(buf, "DIR=", 4) == 0) { 280189251Ssam dir = buf + 4; 281189251Ssam gid_str = os_strstr(dir, " GROUP="); 282189251Ssam if (gid_str) { 283189251Ssam *gid_str = '\0'; 284189251Ssam gid_str += 7; 285189251Ssam } 286189251Ssam } else { 287189251Ssam dir = buf; 288189251Ssam gid_str = wpa_s->conf->ctrl_interface_group; 289189251Ssam } 290189251Ssam 291189251Ssam if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { 292189251Ssam if (errno == EEXIST) { 293189251Ssam wpa_printf(MSG_DEBUG, "Using existing control " 294189251Ssam "interface directory."); 295189251Ssam } else { 296189251Ssam perror("mkdir[ctrl_interface]"); 297189251Ssam goto fail; 298189251Ssam } 299189251Ssam } 300189251Ssam 301189251Ssam if (gid_str) { 302189251Ssam grp = getgrnam(gid_str); 303189251Ssam if (grp) { 304189251Ssam gid = grp->gr_gid; 305189251Ssam gid_set = 1; 306189251Ssam wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 307189251Ssam " (from group name '%s')", 308189251Ssam (int) gid, gid_str); 309189251Ssam } else { 310189251Ssam /* Group name not found - try to parse this as gid */ 311189251Ssam gid = strtol(gid_str, &endp, 10); 312189251Ssam if (*gid_str == '\0' || *endp != '\0') { 313189251Ssam wpa_printf(MSG_ERROR, "CTRL: Invalid group " 314189251Ssam "'%s'", gid_str); 315189251Ssam goto fail; 316189251Ssam } 317189251Ssam gid_set = 1; 318189251Ssam wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 319189251Ssam (int) gid); 320189251Ssam } 321189251Ssam } 322189251Ssam 323189251Ssam if (gid_set && chown(dir, -1, gid) < 0) { 324189251Ssam perror("chown[ctrl_interface]"); 325189251Ssam goto fail; 326189251Ssam } 327189251Ssam 328209158Srpaulo /* Make sure the group can enter and read the directory */ 329209158Srpaulo if (gid_set && 330209158Srpaulo chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { 331209158Srpaulo wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", 332209158Srpaulo strerror(errno)); 333209158Srpaulo goto fail; 334209158Srpaulo } 335209158Srpaulo 336189251Ssam if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= 337189251Ssam sizeof(addr.sun_path)) { 338189251Ssam wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); 339189251Ssam goto fail; 340189251Ssam } 341189251Ssam 342189251Ssam priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 343189251Ssam if (priv->sock < 0) { 344189251Ssam perror("socket(PF_UNIX)"); 345189251Ssam goto fail; 346189251Ssam } 347189251Ssam 348189251Ssam os_memset(&addr, 0, sizeof(addr)); 349214734Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 350189775Ssam addr.sun_len = sizeof(addr); 351209158Srpaulo#endif /* __FreeBSD__ */ 352189251Ssam addr.sun_family = AF_UNIX; 353189251Ssam fname = wpa_supplicant_ctrl_iface_path(wpa_s); 354189251Ssam if (fname == NULL) 355189251Ssam goto fail; 356189251Ssam os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 357189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 358189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 359189251Ssam strerror(errno)); 360189251Ssam if (connect(priv->sock, (struct sockaddr *) &addr, 361189251Ssam sizeof(addr)) < 0) { 362189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 363189251Ssam " allow connections - assuming it was left" 364189251Ssam "over from forced program termination"); 365189251Ssam if (unlink(fname) < 0) { 366189251Ssam perror("unlink[ctrl_iface]"); 367189251Ssam wpa_printf(MSG_ERROR, "Could not unlink " 368189251Ssam "existing ctrl_iface socket '%s'", 369189251Ssam fname); 370189251Ssam goto fail; 371189251Ssam } 372189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, 373189251Ssam sizeof(addr)) < 0) { 374189251Ssam perror("bind(PF_UNIX)"); 375189251Ssam goto fail; 376189251Ssam } 377189251Ssam wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 378189251Ssam "ctrl_iface socket '%s'", fname); 379189251Ssam } else { 380189251Ssam wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 381189251Ssam "be in use - cannot override it"); 382189251Ssam wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 383189251Ssam "not used anymore", fname); 384189251Ssam os_free(fname); 385189251Ssam fname = NULL; 386189251Ssam goto fail; 387189251Ssam } 388189251Ssam } 389189251Ssam 390189251Ssam if (gid_set && chown(fname, -1, gid) < 0) { 391189251Ssam perror("chown[ctrl_interface/ifname]"); 392189251Ssam goto fail; 393189251Ssam } 394189251Ssam 395189251Ssam if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 396189251Ssam perror("chmod[ctrl_interface/ifname]"); 397189251Ssam goto fail; 398189251Ssam } 399189251Ssam os_free(fname); 400189251Ssam 401189251Ssam eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 402189251Ssam wpa_s, priv); 403189251Ssam wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 404189251Ssam 405189251Ssam os_free(buf); 406189251Ssam return priv; 407189251Ssam 408189251Ssamfail: 409189251Ssam if (priv->sock >= 0) 410189251Ssam close(priv->sock); 411189251Ssam os_free(priv); 412189251Ssam if (fname) { 413189251Ssam unlink(fname); 414189251Ssam os_free(fname); 415189251Ssam } 416189251Ssam os_free(buf); 417189251Ssam return NULL; 418189251Ssam} 419189251Ssam 420189251Ssam 421189251Ssamvoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 422189251Ssam{ 423189251Ssam struct wpa_ctrl_dst *dst, *prev; 424189251Ssam 425189251Ssam if (priv->sock > -1) { 426189251Ssam char *fname; 427189251Ssam char *buf, *dir = NULL, *gid_str = NULL; 428189251Ssam eloop_unregister_read_sock(priv->sock); 429214734Srpaulo if (!dl_list_empty(&priv->ctrl_dst)) { 430189251Ssam /* 431189251Ssam * Wait a second before closing the control socket if 432189251Ssam * there are any attached monitors in order to allow 433189251Ssam * them to receive any pending messages. 434189251Ssam */ 435189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 436189251Ssam "monitors to receive messages"); 437189251Ssam os_sleep(1, 0); 438189251Ssam } 439189251Ssam close(priv->sock); 440189251Ssam priv->sock = -1; 441189251Ssam fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); 442189251Ssam if (fname) { 443189251Ssam unlink(fname); 444189251Ssam os_free(fname); 445189251Ssam } 446189251Ssam 447189251Ssam buf = os_strdup(priv->wpa_s->conf->ctrl_interface); 448189251Ssam if (buf == NULL) 449189251Ssam goto free_dst; 450189251Ssam if (os_strncmp(buf, "DIR=", 4) == 0) { 451189251Ssam dir = buf + 4; 452189251Ssam gid_str = os_strstr(dir, " GROUP="); 453189251Ssam if (gid_str) { 454189251Ssam *gid_str = '\0'; 455189251Ssam gid_str += 7; 456189251Ssam } 457189251Ssam } else 458189251Ssam dir = buf; 459189251Ssam 460189251Ssam if (rmdir(dir) < 0) { 461189251Ssam if (errno == ENOTEMPTY) { 462189251Ssam wpa_printf(MSG_DEBUG, "Control interface " 463189251Ssam "directory not empty - leaving it " 464189251Ssam "behind"); 465189251Ssam } else { 466189251Ssam perror("rmdir[ctrl_interface]"); 467189251Ssam } 468189251Ssam } 469189251Ssam os_free(buf); 470189251Ssam } 471189251Ssam 472189251Ssamfree_dst: 473214734Srpaulo dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, 474214734Srpaulo list) 475214734Srpaulo os_free(dst); 476189251Ssam os_free(priv); 477189251Ssam} 478189251Ssam 479189251Ssam 480189251Ssam/** 481189251Ssam * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors 482189251Ssam * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() 483189251Ssam * @level: Priority level of the message 484189251Ssam * @buf: Message data 485189251Ssam * @len: Message length 486189251Ssam * 487189251Ssam * Send a packet to all monitor programs attached to the control interface. 488189251Ssam */ 489189251Ssamstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 490189251Ssam int level, const char *buf, 491189251Ssam size_t len) 492189251Ssam{ 493189251Ssam struct wpa_ctrl_dst *dst, *next; 494189251Ssam char levelstr[10]; 495189251Ssam int idx, res; 496189251Ssam struct msghdr msg; 497189251Ssam struct iovec io[2]; 498189251Ssam 499214734Srpaulo if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst)) 500189251Ssam return; 501189251Ssam 502189251Ssam res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 503189251Ssam if (res < 0 || (size_t) res >= sizeof(levelstr)) 504189251Ssam return; 505189251Ssam io[0].iov_base = levelstr; 506189251Ssam io[0].iov_len = os_strlen(levelstr); 507189251Ssam io[1].iov_base = (char *) buf; 508189251Ssam io[1].iov_len = len; 509189251Ssam os_memset(&msg, 0, sizeof(msg)); 510189251Ssam msg.msg_iov = io; 511189251Ssam msg.msg_iovlen = 2; 512189251Ssam 513189251Ssam idx = 0; 514214734Srpaulo dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst, 515214734Srpaulo list) { 516189251Ssam if (level >= dst->debug_level) { 517189251Ssam wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 518209158Srpaulo (u8 *) dst->addr.sun_path, dst->addrlen - 519209158Srpaulo offsetof(struct sockaddr_un, sun_path)); 520189251Ssam msg.msg_name = (void *) &dst->addr; 521189251Ssam msg.msg_namelen = dst->addrlen; 522189251Ssam if (sendmsg(priv->sock, &msg, 0) < 0) { 523209158Srpaulo int _errno = errno; 524209158Srpaulo wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " 525209158Srpaulo "%d - %s", 526209158Srpaulo idx, errno, strerror(errno)); 527189251Ssam dst->errors++; 528214734Srpaulo if (dst->errors > 1000 || 529214734Srpaulo (_errno != ENOBUFS && dst->errors > 10) || 530214734Srpaulo _errno == ENOENT) { 531189251Ssam wpa_supplicant_ctrl_iface_detach( 532189251Ssam priv, &dst->addr, 533189251Ssam dst->addrlen); 534189251Ssam } 535189251Ssam } else 536189251Ssam dst->errors = 0; 537189251Ssam } 538189251Ssam idx++; 539189251Ssam } 540189251Ssam} 541189251Ssam 542189251Ssam 543189251Ssamvoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 544189251Ssam{ 545189251Ssam char buf[256]; 546189251Ssam int res; 547189251Ssam struct sockaddr_un from; 548189251Ssam socklen_t fromlen = sizeof(from); 549189251Ssam 550189251Ssam for (;;) { 551189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " 552189251Ssam "attach", priv->wpa_s->ifname); 553189251Ssam eloop_wait_for_read_sock(priv->sock); 554189251Ssam 555189251Ssam res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, 556189251Ssam (struct sockaddr *) &from, &fromlen); 557189251Ssam if (res < 0) { 558189251Ssam perror("recvfrom(ctrl_iface)"); 559189251Ssam continue; 560189251Ssam } 561189251Ssam buf[res] = '\0'; 562189251Ssam 563189251Ssam if (os_strcmp(buf, "ATTACH") == 0) { 564189251Ssam /* handle ATTACH signal of first monitor interface */ 565189251Ssam if (!wpa_supplicant_ctrl_iface_attach(priv, &from, 566189251Ssam fromlen)) { 567189251Ssam sendto(priv->sock, "OK\n", 3, 0, 568189251Ssam (struct sockaddr *) &from, fromlen); 569189251Ssam /* OK to continue */ 570189251Ssam return; 571189251Ssam } else { 572189251Ssam sendto(priv->sock, "FAIL\n", 5, 0, 573189251Ssam (struct sockaddr *) &from, fromlen); 574189251Ssam } 575189251Ssam } else { 576189251Ssam /* return FAIL for all other signals */ 577189251Ssam sendto(priv->sock, "FAIL\n", 5, 0, 578189251Ssam (struct sockaddr *) &from, fromlen); 579189251Ssam } 580189251Ssam } 581189251Ssam} 582189251Ssam 583189251Ssam 584189251Ssam/* Global ctrl_iface */ 585189251Ssam 586189251Ssamstruct ctrl_iface_global_priv { 587189251Ssam struct wpa_global *global; 588189251Ssam int sock; 589189251Ssam}; 590189251Ssam 591189251Ssam 592189251Ssamstatic void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 593189251Ssam void *sock_ctx) 594189251Ssam{ 595189251Ssam struct wpa_global *global = eloop_ctx; 596189251Ssam char buf[256]; 597189251Ssam int res; 598189251Ssam struct sockaddr_un from; 599189251Ssam socklen_t fromlen = sizeof(from); 600189251Ssam char *reply; 601189251Ssam size_t reply_len; 602189251Ssam 603189251Ssam res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 604189251Ssam (struct sockaddr *) &from, &fromlen); 605189251Ssam if (res < 0) { 606189251Ssam perror("recvfrom(ctrl_iface)"); 607189251Ssam return; 608189251Ssam } 609189251Ssam buf[res] = '\0'; 610189251Ssam 611189251Ssam reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 612189251Ssam &reply_len); 613189251Ssam 614189251Ssam if (reply) { 615189251Ssam sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 616189251Ssam fromlen); 617189251Ssam os_free(reply); 618189251Ssam } else if (reply_len) { 619189251Ssam sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 620189251Ssam fromlen); 621189251Ssam } 622189251Ssam} 623189251Ssam 624189251Ssam 625189251Ssamstruct ctrl_iface_global_priv * 626189251Ssamwpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 627189251Ssam{ 628189251Ssam struct ctrl_iface_global_priv *priv; 629189251Ssam struct sockaddr_un addr; 630189251Ssam 631189251Ssam priv = os_zalloc(sizeof(*priv)); 632189251Ssam if (priv == NULL) 633189251Ssam return NULL; 634189251Ssam priv->global = global; 635189251Ssam priv->sock = -1; 636189251Ssam 637189251Ssam if (global->params.ctrl_interface == NULL) 638189251Ssam return priv; 639189251Ssam 640189251Ssam wpa_printf(MSG_DEBUG, "Global control interface '%s'", 641189251Ssam global->params.ctrl_interface); 642189251Ssam 643189251Ssam priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 644189251Ssam if (priv->sock < 0) { 645189251Ssam perror("socket(PF_UNIX)"); 646189251Ssam goto fail; 647189251Ssam } 648189251Ssam 649189251Ssam os_memset(&addr, 0, sizeof(addr)); 650214734Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 651189775Ssam addr.sun_len = sizeof(addr); 652209158Srpaulo#endif /* __FreeBSD__ */ 653189251Ssam addr.sun_family = AF_UNIX; 654189251Ssam os_strlcpy(addr.sun_path, global->params.ctrl_interface, 655189251Ssam sizeof(addr.sun_path)); 656189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 657189251Ssam perror("bind(PF_UNIX)"); 658189251Ssam if (connect(priv->sock, (struct sockaddr *) &addr, 659189251Ssam sizeof(addr)) < 0) { 660189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 661189251Ssam " allow connections - assuming it was left" 662189251Ssam "over from forced program termination"); 663189251Ssam if (unlink(global->params.ctrl_interface) < 0) { 664189251Ssam perror("unlink[ctrl_iface]"); 665189251Ssam wpa_printf(MSG_ERROR, "Could not unlink " 666189251Ssam "existing ctrl_iface socket '%s'", 667189251Ssam global->params.ctrl_interface); 668189251Ssam goto fail; 669189251Ssam } 670189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, 671189251Ssam sizeof(addr)) < 0) { 672189251Ssam perror("bind(PF_UNIX)"); 673189251Ssam goto fail; 674189251Ssam } 675189251Ssam wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 676189251Ssam "ctrl_iface socket '%s'", 677189251Ssam global->params.ctrl_interface); 678189251Ssam } else { 679189251Ssam wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 680189251Ssam "be in use - cannot override it"); 681189251Ssam wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 682189251Ssam "not used anymore", 683189251Ssam global->params.ctrl_interface); 684189251Ssam goto fail; 685189251Ssam } 686189251Ssam } 687189251Ssam 688189251Ssam eloop_register_read_sock(priv->sock, 689189251Ssam wpa_supplicant_global_ctrl_iface_receive, 690189251Ssam global, NULL); 691189251Ssam 692189251Ssam return priv; 693189251Ssam 694189251Ssamfail: 695189251Ssam if (priv->sock >= 0) 696189251Ssam close(priv->sock); 697189251Ssam os_free(priv); 698189251Ssam return NULL; 699189251Ssam} 700189251Ssam 701189251Ssam 702189251Ssamvoid 703189251Ssamwpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 704189251Ssam{ 705189251Ssam if (priv->sock >= 0) { 706189251Ssam eloop_unregister_read_sock(priv->sock); 707189251Ssam close(priv->sock); 708189251Ssam } 709189251Ssam if (priv->global->params.ctrl_interface) 710189251Ssam unlink(priv->global->params.ctrl_interface); 711189251Ssam os_free(priv); 712189251Ssam} 713