1214503Srpaulo/* 2214503Srpaulo * hostapd / UNIX domain socket -based control interface 3252726Srpaulo * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 4214503Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214503Srpaulo */ 8214503Srpaulo 9214503Srpaulo#include "utils/includes.h" 10214503Srpaulo 11214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 12214503Srpaulo 13214503Srpaulo#include <sys/un.h> 14214503Srpaulo#include <sys/stat.h> 15214503Srpaulo#include <stddef.h> 16214503Srpaulo 17214503Srpaulo#include "utils/common.h" 18214503Srpaulo#include "utils/eloop.h" 19252726Srpaulo#include "common/version.h" 20214503Srpaulo#include "common/ieee802_11_defs.h" 21214503Srpaulo#include "drivers/driver.h" 22214503Srpaulo#include "radius/radius_client.h" 23214503Srpaulo#include "ap/hostapd.h" 24214503Srpaulo#include "ap/ap_config.h" 25214503Srpaulo#include "ap/ieee802_1x.h" 26214503Srpaulo#include "ap/wpa_auth.h" 27214503Srpaulo#include "ap/ieee802_11.h" 28214503Srpaulo#include "ap/sta_info.h" 29214503Srpaulo#include "ap/wps_hostapd.h" 30214503Srpaulo#include "ap/ctrl_iface_ap.h" 31252726Srpaulo#include "ap/ap_drv_ops.h" 32252726Srpaulo#include "wps/wps_defs.h" 33252726Srpaulo#include "wps/wps.h" 34252726Srpaulo#include "config_file.h" 35214503Srpaulo#include "ctrl_iface.h" 36214503Srpaulo 37214503Srpaulo 38214503Srpaulostruct wpa_ctrl_dst { 39214503Srpaulo struct wpa_ctrl_dst *next; 40214503Srpaulo struct sockaddr_un addr; 41214503Srpaulo socklen_t addrlen; 42214503Srpaulo int debug_level; 43214503Srpaulo int errors; 44214503Srpaulo}; 45214503Srpaulo 46214503Srpaulo 47214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 48214503Srpaulo const char *buf, size_t len); 49214503Srpaulo 50214503Srpaulo 51214503Srpaulostatic int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, 52214503Srpaulo struct sockaddr_un *from, 53214503Srpaulo socklen_t fromlen) 54214503Srpaulo{ 55214503Srpaulo struct wpa_ctrl_dst *dst; 56214503Srpaulo 57214503Srpaulo dst = os_zalloc(sizeof(*dst)); 58214503Srpaulo if (dst == NULL) 59214503Srpaulo return -1; 60214503Srpaulo os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 61214503Srpaulo dst->addrlen = fromlen; 62214503Srpaulo dst->debug_level = MSG_INFO; 63214503Srpaulo dst->next = hapd->ctrl_dst; 64214503Srpaulo hapd->ctrl_dst = dst; 65214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 66214503Srpaulo (u8 *) from->sun_path, 67214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)); 68214503Srpaulo return 0; 69214503Srpaulo} 70214503Srpaulo 71214503Srpaulo 72214503Srpaulostatic int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, 73214503Srpaulo struct sockaddr_un *from, 74214503Srpaulo socklen_t fromlen) 75214503Srpaulo{ 76214503Srpaulo struct wpa_ctrl_dst *dst, *prev = NULL; 77214503Srpaulo 78214503Srpaulo dst = hapd->ctrl_dst; 79214503Srpaulo while (dst) { 80214503Srpaulo if (fromlen == dst->addrlen && 81214503Srpaulo os_memcmp(from->sun_path, dst->addr.sun_path, 82214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 83214503Srpaulo == 0) { 84214503Srpaulo if (prev == NULL) 85214503Srpaulo hapd->ctrl_dst = dst->next; 86214503Srpaulo else 87214503Srpaulo prev->next = dst->next; 88214503Srpaulo os_free(dst); 89214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 90214503Srpaulo (u8 *) from->sun_path, 91214503Srpaulo fromlen - 92214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 93214503Srpaulo return 0; 94214503Srpaulo } 95214503Srpaulo prev = dst; 96214503Srpaulo dst = dst->next; 97214503Srpaulo } 98214503Srpaulo return -1; 99214503Srpaulo} 100214503Srpaulo 101214503Srpaulo 102214503Srpaulostatic int hostapd_ctrl_iface_level(struct hostapd_data *hapd, 103214503Srpaulo struct sockaddr_un *from, 104214503Srpaulo socklen_t fromlen, 105214503Srpaulo char *level) 106214503Srpaulo{ 107214503Srpaulo struct wpa_ctrl_dst *dst; 108214503Srpaulo 109214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 110214503Srpaulo 111214503Srpaulo dst = hapd->ctrl_dst; 112214503Srpaulo while (dst) { 113214503Srpaulo if (fromlen == dst->addrlen && 114214503Srpaulo os_memcmp(from->sun_path, dst->addr.sun_path, 115214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 116214503Srpaulo == 0) { 117214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 118214503Srpaulo "level", (u8 *) from->sun_path, fromlen - 119214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 120214503Srpaulo dst->debug_level = atoi(level); 121214503Srpaulo return 0; 122214503Srpaulo } 123214503Srpaulo dst = dst->next; 124214503Srpaulo } 125214503Srpaulo 126214503Srpaulo return -1; 127214503Srpaulo} 128214503Srpaulo 129214503Srpaulo 130214503Srpaulostatic int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, 131214503Srpaulo const char *txtaddr) 132214503Srpaulo{ 133214503Srpaulo u8 addr[ETH_ALEN]; 134214503Srpaulo struct sta_info *sta; 135214503Srpaulo 136214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); 137214503Srpaulo 138214503Srpaulo if (hwaddr_aton(txtaddr, addr)) 139214503Srpaulo return -1; 140214503Srpaulo 141214503Srpaulo sta = ap_get_sta(hapd, addr); 142214503Srpaulo if (sta) 143214503Srpaulo return 0; 144214503Srpaulo 145214503Srpaulo wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " 146214503Srpaulo "notification", MAC2STR(addr)); 147214503Srpaulo sta = ap_sta_add(hapd, addr); 148214503Srpaulo if (sta == NULL) 149214503Srpaulo return -1; 150214503Srpaulo 151214503Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 152214503Srpaulo return 0; 153214503Srpaulo} 154214503Srpaulo 155214503Srpaulo 156214503Srpaulo#ifdef CONFIG_IEEE80211W 157214503Srpaulo#ifdef NEED_AP_MLME 158214503Srpaulostatic int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, 159214503Srpaulo const char *txtaddr) 160214503Srpaulo{ 161214503Srpaulo u8 addr[ETH_ALEN]; 162214503Srpaulo u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; 163214503Srpaulo 164214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); 165214503Srpaulo 166214503Srpaulo if (hwaddr_aton(txtaddr, addr) || 167214503Srpaulo os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) 168214503Srpaulo return -1; 169214503Srpaulo 170214503Srpaulo ieee802_11_send_sa_query_req(hapd, addr, trans_id); 171214503Srpaulo 172214503Srpaulo return 0; 173214503Srpaulo} 174214503Srpaulo#endif /* NEED_AP_MLME */ 175214503Srpaulo#endif /* CONFIG_IEEE80211W */ 176214503Srpaulo 177214503Srpaulo 178214503Srpaulo#ifdef CONFIG_WPS 179214503Srpaulostatic int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) 180214503Srpaulo{ 181214503Srpaulo char *pin = os_strchr(txt, ' '); 182214503Srpaulo char *timeout_txt; 183214503Srpaulo int timeout; 184252726Srpaulo u8 addr_buf[ETH_ALEN], *addr = NULL; 185252726Srpaulo char *pos; 186214503Srpaulo 187214503Srpaulo if (pin == NULL) 188214503Srpaulo return -1; 189214503Srpaulo *pin++ = '\0'; 190214503Srpaulo 191214503Srpaulo timeout_txt = os_strchr(pin, ' '); 192214503Srpaulo if (timeout_txt) { 193214503Srpaulo *timeout_txt++ = '\0'; 194214503Srpaulo timeout = atoi(timeout_txt); 195252726Srpaulo pos = os_strchr(timeout_txt, ' '); 196252726Srpaulo if (pos) { 197252726Srpaulo *pos++ = '\0'; 198252726Srpaulo if (hwaddr_aton(pos, addr_buf) == 0) 199252726Srpaulo addr = addr_buf; 200252726Srpaulo } 201214503Srpaulo } else 202214503Srpaulo timeout = 0; 203214503Srpaulo 204252726Srpaulo return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout); 205214503Srpaulo} 206214503Srpaulo 207214503Srpaulo 208252726Srpaulostatic int hostapd_ctrl_iface_wps_check_pin( 209252726Srpaulo struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) 210214503Srpaulo{ 211252726Srpaulo char pin[9]; 212252726Srpaulo size_t len; 213252726Srpaulo char *pos; 214252726Srpaulo int ret; 215214503Srpaulo 216252726Srpaulo wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", 217252726Srpaulo (u8 *) cmd, os_strlen(cmd)); 218252726Srpaulo for (pos = cmd, len = 0; *pos != '\0'; pos++) { 219252726Srpaulo if (*pos < '0' || *pos > '9') 220252726Srpaulo continue; 221252726Srpaulo pin[len++] = *pos; 222252726Srpaulo if (len == 9) { 223252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); 224252726Srpaulo return -1; 225252726Srpaulo } 226252726Srpaulo } 227252726Srpaulo if (len != 4 && len != 8) { 228252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); 229214503Srpaulo return -1; 230252726Srpaulo } 231252726Srpaulo pin[len] = '\0'; 232214503Srpaulo 233252726Srpaulo if (len == 8) { 234252726Srpaulo unsigned int pin_val; 235252726Srpaulo pin_val = atoi(pin); 236252726Srpaulo if (!wps_pin_valid(pin_val)) { 237252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); 238252726Srpaulo ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); 239252726Srpaulo if (ret < 0 || (size_t) ret >= buflen) 240252726Srpaulo return -1; 241252726Srpaulo return ret; 242252726Srpaulo } 243252726Srpaulo } 244252726Srpaulo 245252726Srpaulo ret = os_snprintf(buf, buflen, "%s", pin); 246252726Srpaulo if (ret < 0 || (size_t) ret >= buflen) 247214503Srpaulo return -1; 248214503Srpaulo 249252726Srpaulo return ret; 250252726Srpaulo} 251214503Srpaulo 252252726Srpaulo 253252726Srpaulo#ifdef CONFIG_WPS_NFC 254252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd, 255252726Srpaulo char *pos) 256252726Srpaulo{ 257252726Srpaulo size_t len; 258252726Srpaulo struct wpabuf *buf; 259252726Srpaulo int ret; 260252726Srpaulo 261252726Srpaulo len = os_strlen(pos); 262252726Srpaulo if (len & 0x01) 263252726Srpaulo return -1; 264252726Srpaulo len /= 2; 265252726Srpaulo 266252726Srpaulo buf = wpabuf_alloc(len); 267252726Srpaulo if (buf == NULL) 268252726Srpaulo return -1; 269252726Srpaulo if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 270252726Srpaulo wpabuf_free(buf); 271252726Srpaulo return -1; 272252726Srpaulo } 273252726Srpaulo 274252726Srpaulo ret = hostapd_wps_nfc_tag_read(hapd, buf); 275252726Srpaulo wpabuf_free(buf); 276252726Srpaulo 277252726Srpaulo return ret; 278214503Srpaulo} 279214503Srpaulo 280214503Srpaulo 281252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd, 282252726Srpaulo char *cmd, char *reply, 283252726Srpaulo size_t max_len) 284252726Srpaulo{ 285252726Srpaulo int ndef; 286252726Srpaulo struct wpabuf *buf; 287252726Srpaulo int res; 288252726Srpaulo 289252726Srpaulo if (os_strcmp(cmd, "WPS") == 0) 290252726Srpaulo ndef = 0; 291252726Srpaulo else if (os_strcmp(cmd, "NDEF") == 0) 292252726Srpaulo ndef = 1; 293252726Srpaulo else 294252726Srpaulo return -1; 295252726Srpaulo 296252726Srpaulo buf = hostapd_wps_nfc_config_token(hapd, ndef); 297252726Srpaulo if (buf == NULL) 298252726Srpaulo return -1; 299252726Srpaulo 300252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 301252726Srpaulo wpabuf_len(buf)); 302252726Srpaulo reply[res++] = '\n'; 303252726Srpaulo reply[res] = '\0'; 304252726Srpaulo 305252726Srpaulo wpabuf_free(buf); 306252726Srpaulo 307252726Srpaulo return res; 308252726Srpaulo} 309252726Srpaulo 310252726Srpaulo 311252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd, 312252726Srpaulo char *reply, size_t max_len, 313252726Srpaulo int ndef) 314252726Srpaulo{ 315252726Srpaulo struct wpabuf *buf; 316252726Srpaulo int res; 317252726Srpaulo 318252726Srpaulo buf = hostapd_wps_nfc_token_gen(hapd, ndef); 319252726Srpaulo if (buf == NULL) 320252726Srpaulo return -1; 321252726Srpaulo 322252726Srpaulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 323252726Srpaulo wpabuf_len(buf)); 324252726Srpaulo reply[res++] = '\n'; 325252726Srpaulo reply[res] = '\0'; 326252726Srpaulo 327252726Srpaulo wpabuf_free(buf); 328252726Srpaulo 329252726Srpaulo return res; 330252726Srpaulo} 331252726Srpaulo 332252726Srpaulo 333252726Srpaulostatic int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd, 334252726Srpaulo char *cmd, char *reply, 335252726Srpaulo size_t max_len) 336252726Srpaulo{ 337252726Srpaulo if (os_strcmp(cmd, "WPS") == 0) 338252726Srpaulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 339252726Srpaulo max_len, 0); 340252726Srpaulo 341252726Srpaulo if (os_strcmp(cmd, "NDEF") == 0) 342252726Srpaulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 343252726Srpaulo max_len, 1); 344252726Srpaulo 345252726Srpaulo if (os_strcmp(cmd, "enable") == 0) 346252726Srpaulo return hostapd_wps_nfc_token_enable(hapd); 347252726Srpaulo 348252726Srpaulo if (os_strcmp(cmd, "disable") == 0) { 349252726Srpaulo hostapd_wps_nfc_token_disable(hapd); 350252726Srpaulo return 0; 351252726Srpaulo } 352252726Srpaulo 353252726Srpaulo return -1; 354252726Srpaulo} 355252726Srpaulo#endif /* CONFIG_WPS_NFC */ 356252726Srpaulo 357252726Srpaulo 358214503Srpaulostatic int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, 359214503Srpaulo char *buf, size_t buflen) 360214503Srpaulo{ 361214503Srpaulo int timeout = 300; 362214503Srpaulo char *pos; 363214503Srpaulo const char *pin_txt; 364214503Srpaulo 365214503Srpaulo pos = os_strchr(txt, ' '); 366214503Srpaulo if (pos) 367214503Srpaulo *pos++ = '\0'; 368214503Srpaulo 369214503Srpaulo if (os_strcmp(txt, "disable") == 0) { 370214503Srpaulo hostapd_wps_ap_pin_disable(hapd); 371214503Srpaulo return os_snprintf(buf, buflen, "OK\n"); 372214503Srpaulo } 373214503Srpaulo 374214503Srpaulo if (os_strcmp(txt, "random") == 0) { 375214503Srpaulo if (pos) 376214503Srpaulo timeout = atoi(pos); 377214503Srpaulo pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); 378214503Srpaulo if (pin_txt == NULL) 379214503Srpaulo return -1; 380214503Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 381214503Srpaulo } 382214503Srpaulo 383214503Srpaulo if (os_strcmp(txt, "get") == 0) { 384214503Srpaulo pin_txt = hostapd_wps_ap_pin_get(hapd); 385214503Srpaulo if (pin_txt == NULL) 386214503Srpaulo return -1; 387214503Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 388214503Srpaulo } 389214503Srpaulo 390214503Srpaulo if (os_strcmp(txt, "set") == 0) { 391214503Srpaulo char *pin; 392214503Srpaulo if (pos == NULL) 393214503Srpaulo return -1; 394214503Srpaulo pin = pos; 395214503Srpaulo pos = os_strchr(pos, ' '); 396214503Srpaulo if (pos) { 397214503Srpaulo *pos++ = '\0'; 398214503Srpaulo timeout = atoi(pos); 399214503Srpaulo } 400214503Srpaulo if (os_strlen(pin) > buflen) 401214503Srpaulo return -1; 402214503Srpaulo if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) 403214503Srpaulo return -1; 404214503Srpaulo return os_snprintf(buf, buflen, "%s", pin); 405214503Srpaulo } 406214503Srpaulo 407214503Srpaulo return -1; 408214503Srpaulo} 409252726Srpaulo 410252726Srpaulo 411252726Srpaulostatic int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) 412252726Srpaulo{ 413252726Srpaulo char *pos; 414252726Srpaulo char *ssid, *auth, *encr = NULL, *key = NULL; 415252726Srpaulo 416252726Srpaulo ssid = txt; 417252726Srpaulo pos = os_strchr(txt, ' '); 418252726Srpaulo if (!pos) 419252726Srpaulo return -1; 420252726Srpaulo *pos++ = '\0'; 421252726Srpaulo 422252726Srpaulo auth = pos; 423252726Srpaulo pos = os_strchr(pos, ' '); 424252726Srpaulo if (pos) { 425252726Srpaulo *pos++ = '\0'; 426252726Srpaulo encr = pos; 427252726Srpaulo pos = os_strchr(pos, ' '); 428252726Srpaulo if (pos) { 429252726Srpaulo *pos++ = '\0'; 430252726Srpaulo key = pos; 431252726Srpaulo } 432252726Srpaulo } 433252726Srpaulo 434252726Srpaulo return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); 435252726Srpaulo} 436214503Srpaulo#endif /* CONFIG_WPS */ 437214503Srpaulo 438214503Srpaulo 439252726Srpaulo#ifdef CONFIG_WNM 440252726Srpaulo 441252726Srpaulostatic int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, 442252726Srpaulo const char *cmd) 443252726Srpaulo{ 444252726Srpaulo u8 addr[ETH_ALEN]; 445252726Srpaulo u8 buf[1000], *pos; 446252726Srpaulo struct ieee80211_mgmt *mgmt; 447252726Srpaulo int disassoc_timer; 448252726Srpaulo 449252726Srpaulo if (hwaddr_aton(cmd, addr)) 450252726Srpaulo return -1; 451252726Srpaulo if (cmd[17] != ' ') 452252726Srpaulo return -1; 453252726Srpaulo disassoc_timer = atoi(cmd + 17); 454252726Srpaulo 455252726Srpaulo os_memset(buf, 0, sizeof(buf)); 456252726Srpaulo mgmt = (struct ieee80211_mgmt *) buf; 457252726Srpaulo mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 458252726Srpaulo WLAN_FC_STYPE_ACTION); 459252726Srpaulo os_memcpy(mgmt->da, addr, ETH_ALEN); 460252726Srpaulo os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 461252726Srpaulo os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 462252726Srpaulo mgmt->u.action.category = WLAN_ACTION_WNM; 463252726Srpaulo mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 464252726Srpaulo mgmt->u.action.u.bss_tm_req.dialog_token = 1; 465252726Srpaulo mgmt->u.action.u.bss_tm_req.req_mode = 466252726Srpaulo WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 467252726Srpaulo mgmt->u.action.u.bss_tm_req.disassoc_timer = 468252726Srpaulo host_to_le16(disassoc_timer); 469252726Srpaulo mgmt->u.action.u.bss_tm_req.validity_interval = 0; 470252726Srpaulo 471252726Srpaulo pos = mgmt->u.action.u.bss_tm_req.variable; 472252726Srpaulo 473252726Srpaulo if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 474252726Srpaulo wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 475252726Srpaulo "Management Request frame"); 476252726Srpaulo return -1; 477252726Srpaulo } 478252726Srpaulo 479252726Srpaulo return 0; 480252726Srpaulo} 481252726Srpaulo 482252726Srpaulo 483252726Srpaulostatic int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, 484252726Srpaulo const char *cmd) 485252726Srpaulo{ 486252726Srpaulo u8 addr[ETH_ALEN]; 487252726Srpaulo const char *url; 488252726Srpaulo u8 buf[1000], *pos; 489252726Srpaulo struct ieee80211_mgmt *mgmt; 490252726Srpaulo size_t url_len; 491252726Srpaulo 492252726Srpaulo if (hwaddr_aton(cmd, addr)) 493252726Srpaulo return -1; 494252726Srpaulo url = cmd + 17; 495252726Srpaulo if (*url != ' ') 496252726Srpaulo return -1; 497252726Srpaulo url++; 498252726Srpaulo url_len = os_strlen(url); 499252726Srpaulo if (url_len > 255) 500252726Srpaulo return -1; 501252726Srpaulo 502252726Srpaulo os_memset(buf, 0, sizeof(buf)); 503252726Srpaulo mgmt = (struct ieee80211_mgmt *) buf; 504252726Srpaulo mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 505252726Srpaulo WLAN_FC_STYPE_ACTION); 506252726Srpaulo os_memcpy(mgmt->da, addr, ETH_ALEN); 507252726Srpaulo os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 508252726Srpaulo os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 509252726Srpaulo mgmt->u.action.category = WLAN_ACTION_WNM; 510252726Srpaulo mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 511252726Srpaulo mgmt->u.action.u.bss_tm_req.dialog_token = 1; 512252726Srpaulo mgmt->u.action.u.bss_tm_req.req_mode = 513252726Srpaulo WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 514252726Srpaulo mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); 515252726Srpaulo mgmt->u.action.u.bss_tm_req.validity_interval = 0; 516252726Srpaulo 517252726Srpaulo pos = mgmt->u.action.u.bss_tm_req.variable; 518252726Srpaulo 519252726Srpaulo /* Session Information URL */ 520252726Srpaulo *pos++ = url_len; 521252726Srpaulo os_memcpy(pos, url, url_len); 522252726Srpaulo pos += url_len; 523252726Srpaulo 524252726Srpaulo if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 525252726Srpaulo wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 526252726Srpaulo "Management Request frame"); 527252726Srpaulo return -1; 528252726Srpaulo } 529252726Srpaulo 530252726Srpaulo return 0; 531252726Srpaulo} 532252726Srpaulo 533252726Srpaulo#endif /* CONFIG_WNM */ 534252726Srpaulo 535252726Srpaulo 536252726Srpaulostatic int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 537252726Srpaulo char *buf, size_t buflen) 538252726Srpaulo{ 539252726Srpaulo int ret; 540252726Srpaulo char *pos, *end; 541252726Srpaulo 542252726Srpaulo pos = buf; 543252726Srpaulo end = buf + buflen; 544252726Srpaulo 545252726Srpaulo ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n" 546252726Srpaulo "ssid=%s\n", 547252726Srpaulo MAC2STR(hapd->own_addr), 548252726Srpaulo wpa_ssid_txt(hapd->conf->ssid.ssid, 549252726Srpaulo hapd->conf->ssid.ssid_len)); 550252726Srpaulo if (ret < 0 || ret >= end - pos) 551252726Srpaulo return pos - buf; 552252726Srpaulo pos += ret; 553252726Srpaulo 554252726Srpaulo#ifdef CONFIG_WPS 555252726Srpaulo ret = os_snprintf(pos, end - pos, "wps_state=%s\n", 556252726Srpaulo hapd->conf->wps_state == 0 ? "disabled" : 557252726Srpaulo (hapd->conf->wps_state == 1 ? "not configured" : 558252726Srpaulo "configured")); 559252726Srpaulo if (ret < 0 || ret >= end - pos) 560252726Srpaulo return pos - buf; 561252726Srpaulo pos += ret; 562252726Srpaulo 563252726Srpaulo if (hapd->conf->wps_state && hapd->conf->wpa && 564252726Srpaulo hapd->conf->ssid.wpa_passphrase) { 565252726Srpaulo ret = os_snprintf(pos, end - pos, "passphrase=%s\n", 566252726Srpaulo hapd->conf->ssid.wpa_passphrase); 567252726Srpaulo if (ret < 0 || ret >= end - pos) 568252726Srpaulo return pos - buf; 569252726Srpaulo pos += ret; 570252726Srpaulo } 571252726Srpaulo 572252726Srpaulo if (hapd->conf->wps_state && hapd->conf->wpa && 573252726Srpaulo hapd->conf->ssid.wpa_psk && 574252726Srpaulo hapd->conf->ssid.wpa_psk->group) { 575252726Srpaulo char hex[PMK_LEN * 2 + 1]; 576252726Srpaulo wpa_snprintf_hex(hex, sizeof(hex), 577252726Srpaulo hapd->conf->ssid.wpa_psk->psk, PMK_LEN); 578252726Srpaulo ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); 579252726Srpaulo if (ret < 0 || ret >= end - pos) 580252726Srpaulo return pos - buf; 581252726Srpaulo pos += ret; 582252726Srpaulo } 583252726Srpaulo#endif /* CONFIG_WPS */ 584252726Srpaulo 585252726Srpaulo if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { 586252726Srpaulo ret = os_snprintf(pos, end - pos, "key_mgmt="); 587252726Srpaulo if (ret < 0 || ret >= end - pos) 588252726Srpaulo return pos - buf; 589252726Srpaulo pos += ret; 590252726Srpaulo 591252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 592252726Srpaulo ret = os_snprintf(pos, end - pos, "WPA-PSK "); 593252726Srpaulo if (ret < 0 || ret >= end - pos) 594252726Srpaulo return pos - buf; 595252726Srpaulo pos += ret; 596252726Srpaulo } 597252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 598252726Srpaulo ret = os_snprintf(pos, end - pos, "WPA-EAP "); 599252726Srpaulo if (ret < 0 || ret >= end - pos) 600252726Srpaulo return pos - buf; 601252726Srpaulo pos += ret; 602252726Srpaulo } 603252726Srpaulo#ifdef CONFIG_IEEE80211R 604252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { 605252726Srpaulo ret = os_snprintf(pos, end - pos, "FT-PSK "); 606252726Srpaulo if (ret < 0 || ret >= end - pos) 607252726Srpaulo return pos - buf; 608252726Srpaulo pos += ret; 609252726Srpaulo } 610252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 611252726Srpaulo ret = os_snprintf(pos, end - pos, "FT-EAP "); 612252726Srpaulo if (ret < 0 || ret >= end - pos) 613252726Srpaulo return pos - buf; 614252726Srpaulo pos += ret; 615252726Srpaulo } 616252726Srpaulo#endif /* CONFIG_IEEE80211R */ 617252726Srpaulo#ifdef CONFIG_IEEE80211W 618252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 619252726Srpaulo ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); 620252726Srpaulo if (ret < 0 || ret >= end - pos) 621252726Srpaulo return pos - buf; 622252726Srpaulo pos += ret; 623252726Srpaulo } 624252726Srpaulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 625252726Srpaulo ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); 626252726Srpaulo if (ret < 0 || ret >= end - pos) 627252726Srpaulo return pos - buf; 628252726Srpaulo pos += ret; 629252726Srpaulo } 630252726Srpaulo#endif /* CONFIG_IEEE80211W */ 631252726Srpaulo 632252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 633252726Srpaulo if (ret < 0 || ret >= end - pos) 634252726Srpaulo return pos - buf; 635252726Srpaulo pos += ret; 636252726Srpaulo } 637252726Srpaulo 638252726Srpaulo if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) { 639252726Srpaulo ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n"); 640252726Srpaulo if (ret < 0 || ret >= end - pos) 641252726Srpaulo return pos - buf; 642252726Srpaulo pos += ret; 643252726Srpaulo } else if (hapd->conf->wpa && 644252726Srpaulo hapd->conf->wpa_group == WPA_CIPHER_GCMP) { 645252726Srpaulo ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n"); 646252726Srpaulo if (ret < 0 || ret >= end - pos) 647252726Srpaulo return pos - buf; 648252726Srpaulo pos += ret; 649252726Srpaulo } else if (hapd->conf->wpa && 650252726Srpaulo hapd->conf->wpa_group == WPA_CIPHER_TKIP) { 651252726Srpaulo ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n"); 652252726Srpaulo if (ret < 0 || ret >= end - pos) 653252726Srpaulo return pos - buf; 654252726Srpaulo pos += ret; 655252726Srpaulo } 656252726Srpaulo 657252726Srpaulo if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { 658252726Srpaulo ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); 659252726Srpaulo if (ret < 0 || ret >= end - pos) 660252726Srpaulo return pos - buf; 661252726Srpaulo pos += ret; 662252726Srpaulo 663252726Srpaulo if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) { 664252726Srpaulo ret = os_snprintf(pos, end - pos, "CCMP "); 665252726Srpaulo if (ret < 0 || ret >= end - pos) 666252726Srpaulo return pos - buf; 667252726Srpaulo pos += ret; 668252726Srpaulo } 669252726Srpaulo if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) { 670252726Srpaulo ret = os_snprintf(pos, end - pos, "GCMP "); 671252726Srpaulo if (ret < 0 || ret >= end - pos) 672252726Srpaulo return pos - buf; 673252726Srpaulo pos += ret; 674252726Srpaulo } 675252726Srpaulo if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) { 676252726Srpaulo ret = os_snprintf(pos, end - pos, "TKIP "); 677252726Srpaulo if (ret < 0 || ret >= end - pos) 678252726Srpaulo return pos - buf; 679252726Srpaulo pos += ret; 680252726Srpaulo } 681252726Srpaulo 682252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 683252726Srpaulo if (ret < 0 || ret >= end - pos) 684252726Srpaulo return pos - buf; 685252726Srpaulo pos += ret; 686252726Srpaulo } 687252726Srpaulo 688252726Srpaulo if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { 689252726Srpaulo ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); 690252726Srpaulo if (ret < 0 || ret >= end - pos) 691252726Srpaulo return pos - buf; 692252726Srpaulo pos += ret; 693252726Srpaulo 694252726Srpaulo if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) { 695252726Srpaulo ret = os_snprintf(pos, end - pos, "CCMP "); 696252726Srpaulo if (ret < 0 || ret >= end - pos) 697252726Srpaulo return pos - buf; 698252726Srpaulo pos += ret; 699252726Srpaulo } 700252726Srpaulo if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) { 701252726Srpaulo ret = os_snprintf(pos, end - pos, "GCMP "); 702252726Srpaulo if (ret < 0 || ret >= end - pos) 703252726Srpaulo return pos - buf; 704252726Srpaulo pos += ret; 705252726Srpaulo } 706252726Srpaulo if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) { 707252726Srpaulo ret = os_snprintf(pos, end - pos, "TKIP "); 708252726Srpaulo if (ret < 0 || ret >= end - pos) 709252726Srpaulo return pos - buf; 710252726Srpaulo pos += ret; 711252726Srpaulo } 712252726Srpaulo 713252726Srpaulo ret = os_snprintf(pos, end - pos, "\n"); 714252726Srpaulo if (ret < 0 || ret >= end - pos) 715252726Srpaulo return pos - buf; 716252726Srpaulo pos += ret; 717252726Srpaulo } 718252726Srpaulo 719252726Srpaulo return pos - buf; 720252726Srpaulo} 721252726Srpaulo 722252726Srpaulo 723252726Srpaulostatic int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) 724252726Srpaulo{ 725252726Srpaulo char *value; 726252726Srpaulo int ret = 0; 727252726Srpaulo 728252726Srpaulo value = os_strchr(cmd, ' '); 729252726Srpaulo if (value == NULL) 730252726Srpaulo return -1; 731252726Srpaulo *value++ = '\0'; 732252726Srpaulo 733252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); 734252726Srpaulo if (0) { 735252726Srpaulo#ifdef CONFIG_WPS_TESTING 736252726Srpaulo } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { 737252726Srpaulo long int val; 738252726Srpaulo val = strtol(value, NULL, 0); 739252726Srpaulo if (val < 0 || val > 0xff) { 740252726Srpaulo ret = -1; 741252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid " 742252726Srpaulo "wps_version_number %ld", val); 743252726Srpaulo } else { 744252726Srpaulo wps_version_number = val; 745252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " 746252726Srpaulo "version %u.%u", 747252726Srpaulo (wps_version_number & 0xf0) >> 4, 748252726Srpaulo wps_version_number & 0x0f); 749252726Srpaulo hostapd_wps_update_ie(hapd); 750252726Srpaulo } 751252726Srpaulo } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { 752252726Srpaulo wps_testing_dummy_cred = atoi(value); 753252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", 754252726Srpaulo wps_testing_dummy_cred); 755252726Srpaulo#endif /* CONFIG_WPS_TESTING */ 756252726Srpaulo#ifdef CONFIG_INTERWORKING 757252726Srpaulo } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) { 758252726Srpaulo int val = atoi(value); 759252726Srpaulo if (val <= 0) 760252726Srpaulo ret = -1; 761252726Srpaulo else 762252726Srpaulo hapd->gas_frag_limit = val; 763252726Srpaulo#endif /* CONFIG_INTERWORKING */ 764252726Srpaulo } else { 765252726Srpaulo ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); 766252726Srpaulo } 767252726Srpaulo 768252726Srpaulo return ret; 769252726Srpaulo} 770252726Srpaulo 771252726Srpaulo 772252726Srpaulostatic int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, 773252726Srpaulo char *buf, size_t buflen) 774252726Srpaulo{ 775252726Srpaulo int res; 776252726Srpaulo 777252726Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); 778252726Srpaulo 779252726Srpaulo if (os_strcmp(cmd, "version") == 0) { 780252726Srpaulo res = os_snprintf(buf, buflen, "%s", VERSION_STR); 781252726Srpaulo if (res < 0 || (unsigned int) res >= buflen) 782252726Srpaulo return -1; 783252726Srpaulo return res; 784252726Srpaulo } 785252726Srpaulo 786252726Srpaulo return -1; 787252726Srpaulo} 788252726Srpaulo 789252726Srpaulo 790252726Srpaulostatic int hostapd_ctrl_iface_enable(struct hostapd_iface *iface) 791252726Srpaulo{ 792252726Srpaulo if (hostapd_enable_iface(iface) < 0) { 793252726Srpaulo wpa_printf(MSG_ERROR, "Enabling of interface failed"); 794252726Srpaulo return -1; 795252726Srpaulo } 796252726Srpaulo return 0; 797252726Srpaulo} 798252726Srpaulo 799252726Srpaulo 800252726Srpaulostatic int hostapd_ctrl_iface_reload(struct hostapd_iface *iface) 801252726Srpaulo{ 802252726Srpaulo if (hostapd_reload_iface(iface) < 0) { 803252726Srpaulo wpa_printf(MSG_ERROR, "Reloading of interface failed"); 804252726Srpaulo return -1; 805252726Srpaulo } 806252726Srpaulo return 0; 807252726Srpaulo} 808252726Srpaulo 809252726Srpaulo 810252726Srpaulostatic int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) 811252726Srpaulo{ 812252726Srpaulo if (hostapd_disable_iface(iface) < 0) { 813252726Srpaulo wpa_printf(MSG_ERROR, "Disabling of interface failed"); 814252726Srpaulo return -1; 815252726Srpaulo } 816252726Srpaulo return 0; 817252726Srpaulo} 818252726Srpaulo 819252726Srpaulo 820214503Srpaulostatic void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 821214503Srpaulo void *sock_ctx) 822214503Srpaulo{ 823214503Srpaulo struct hostapd_data *hapd = eloop_ctx; 824214503Srpaulo char buf[256]; 825214503Srpaulo int res; 826214503Srpaulo struct sockaddr_un from; 827214503Srpaulo socklen_t fromlen = sizeof(from); 828214503Srpaulo char *reply; 829214503Srpaulo const int reply_size = 4096; 830214503Srpaulo int reply_len; 831252726Srpaulo int level = MSG_DEBUG; 832214503Srpaulo 833214503Srpaulo res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 834214503Srpaulo (struct sockaddr *) &from, &fromlen); 835214503Srpaulo if (res < 0) { 836214503Srpaulo perror("recvfrom(ctrl_iface)"); 837214503Srpaulo return; 838214503Srpaulo } 839214503Srpaulo buf[res] = '\0'; 840252726Srpaulo if (os_strcmp(buf, "PING") == 0) 841252726Srpaulo level = MSG_EXCESSIVE; 842252726Srpaulo wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); 843214503Srpaulo 844214503Srpaulo reply = os_malloc(reply_size); 845214503Srpaulo if (reply == NULL) { 846214503Srpaulo sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 847214503Srpaulo fromlen); 848214503Srpaulo return; 849214503Srpaulo } 850214503Srpaulo 851214503Srpaulo os_memcpy(reply, "OK\n", 3); 852214503Srpaulo reply_len = 3; 853214503Srpaulo 854214503Srpaulo if (os_strcmp(buf, "PING") == 0) { 855214503Srpaulo os_memcpy(reply, "PONG\n", 5); 856214503Srpaulo reply_len = 5; 857252726Srpaulo } else if (os_strncmp(buf, "RELOG", 5) == 0) { 858252726Srpaulo if (wpa_debug_reopen_file() < 0) 859252726Srpaulo reply_len = -1; 860214503Srpaulo } else if (os_strcmp(buf, "MIB") == 0) { 861214503Srpaulo reply_len = ieee802_11_get_mib(hapd, reply, reply_size); 862214503Srpaulo if (reply_len >= 0) { 863214503Srpaulo res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, 864214503Srpaulo reply_size - reply_len); 865214503Srpaulo if (res < 0) 866214503Srpaulo reply_len = -1; 867214503Srpaulo else 868214503Srpaulo reply_len += res; 869214503Srpaulo } 870214503Srpaulo if (reply_len >= 0) { 871214503Srpaulo res = ieee802_1x_get_mib(hapd, reply + reply_len, 872214503Srpaulo reply_size - reply_len); 873214503Srpaulo if (res < 0) 874214503Srpaulo reply_len = -1; 875214503Srpaulo else 876214503Srpaulo reply_len += res; 877214503Srpaulo } 878214503Srpaulo#ifndef CONFIG_NO_RADIUS 879214503Srpaulo if (reply_len >= 0) { 880214503Srpaulo res = radius_client_get_mib(hapd->radius, 881214503Srpaulo reply + reply_len, 882214503Srpaulo reply_size - reply_len); 883214503Srpaulo if (res < 0) 884214503Srpaulo reply_len = -1; 885214503Srpaulo else 886214503Srpaulo reply_len += res; 887214503Srpaulo } 888214503Srpaulo#endif /* CONFIG_NO_RADIUS */ 889214503Srpaulo } else if (os_strcmp(buf, "STA-FIRST") == 0) { 890214503Srpaulo reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, 891214503Srpaulo reply_size); 892214503Srpaulo } else if (os_strncmp(buf, "STA ", 4) == 0) { 893214503Srpaulo reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, 894214503Srpaulo reply_size); 895214503Srpaulo } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 896214503Srpaulo reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, 897214503Srpaulo reply_size); 898214503Srpaulo } else if (os_strcmp(buf, "ATTACH") == 0) { 899214503Srpaulo if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) 900214503Srpaulo reply_len = -1; 901214503Srpaulo } else if (os_strcmp(buf, "DETACH") == 0) { 902214503Srpaulo if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) 903214503Srpaulo reply_len = -1; 904214503Srpaulo } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 905214503Srpaulo if (hostapd_ctrl_iface_level(hapd, &from, fromlen, 906214503Srpaulo buf + 6)) 907214503Srpaulo reply_len = -1; 908214503Srpaulo } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { 909214503Srpaulo if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) 910214503Srpaulo reply_len = -1; 911214503Srpaulo } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 912214503Srpaulo if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) 913214503Srpaulo reply_len = -1; 914214503Srpaulo } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 915214503Srpaulo if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) 916214503Srpaulo reply_len = -1; 917214503Srpaulo#ifdef CONFIG_IEEE80211W 918214503Srpaulo#ifdef NEED_AP_MLME 919214503Srpaulo } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { 920214503Srpaulo if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) 921214503Srpaulo reply_len = -1; 922214503Srpaulo#endif /* NEED_AP_MLME */ 923214503Srpaulo#endif /* CONFIG_IEEE80211W */ 924214503Srpaulo#ifdef CONFIG_WPS 925214503Srpaulo } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 926214503Srpaulo if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) 927214503Srpaulo reply_len = -1; 928252726Srpaulo } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { 929252726Srpaulo reply_len = hostapd_ctrl_iface_wps_check_pin( 930252726Srpaulo hapd, buf + 14, reply, reply_size); 931214503Srpaulo } else if (os_strcmp(buf, "WPS_PBC") == 0) { 932252726Srpaulo if (hostapd_wps_button_pushed(hapd, NULL)) 933214503Srpaulo reply_len = -1; 934252726Srpaulo } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { 935252726Srpaulo if (hostapd_wps_cancel(hapd)) 936214503Srpaulo reply_len = -1; 937214503Srpaulo } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 938214503Srpaulo reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, 939214503Srpaulo reply, reply_size); 940252726Srpaulo } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { 941252726Srpaulo if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) 942252726Srpaulo reply_len = -1; 943252726Srpaulo#ifdef CONFIG_WPS_NFC 944252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { 945252726Srpaulo if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17)) 946252726Srpaulo reply_len = -1; 947252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { 948252726Srpaulo reply_len = hostapd_ctrl_iface_wps_nfc_config_token( 949252726Srpaulo hapd, buf + 21, reply, reply_size); 950252726Srpaulo } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { 951252726Srpaulo reply_len = hostapd_ctrl_iface_wps_nfc_token( 952252726Srpaulo hapd, buf + 14, reply, reply_size); 953252726Srpaulo#endif /* CONFIG_WPS_NFC */ 954214503Srpaulo#endif /* CONFIG_WPS */ 955252726Srpaulo#ifdef CONFIG_WNM 956252726Srpaulo } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { 957252726Srpaulo if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18)) 958252726Srpaulo reply_len = -1; 959252726Srpaulo } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { 960252726Srpaulo if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13)) 961252726Srpaulo reply_len = -1; 962252726Srpaulo#endif /* CONFIG_WNM */ 963252726Srpaulo } else if (os_strcmp(buf, "GET_CONFIG") == 0) { 964252726Srpaulo reply_len = hostapd_ctrl_iface_get_config(hapd, reply, 965252726Srpaulo reply_size); 966252726Srpaulo } else if (os_strncmp(buf, "SET ", 4) == 0) { 967252726Srpaulo if (hostapd_ctrl_iface_set(hapd, buf + 4)) 968252726Srpaulo reply_len = -1; 969252726Srpaulo } else if (os_strncmp(buf, "GET ", 4) == 0) { 970252726Srpaulo reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, 971252726Srpaulo reply_size); 972252726Srpaulo } else if (os_strncmp(buf, "ENABLE", 6) == 0) { 973252726Srpaulo if (hostapd_ctrl_iface_enable(hapd->iface)) 974252726Srpaulo reply_len = -1; 975252726Srpaulo } else if (os_strncmp(buf, "RELOAD", 6) == 0) { 976252726Srpaulo if (hostapd_ctrl_iface_reload(hapd->iface)) 977252726Srpaulo reply_len = -1; 978252726Srpaulo } else if (os_strncmp(buf, "DISABLE", 7) == 0) { 979252726Srpaulo if (hostapd_ctrl_iface_disable(hapd->iface)) 980252726Srpaulo reply_len = -1; 981214503Srpaulo } else { 982214503Srpaulo os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 983214503Srpaulo reply_len = 16; 984214503Srpaulo } 985214503Srpaulo 986214503Srpaulo if (reply_len < 0) { 987214503Srpaulo os_memcpy(reply, "FAIL\n", 5); 988214503Srpaulo reply_len = 5; 989214503Srpaulo } 990214503Srpaulo sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 991214503Srpaulo os_free(reply); 992214503Srpaulo} 993214503Srpaulo 994214503Srpaulo 995214503Srpaulostatic char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) 996214503Srpaulo{ 997214503Srpaulo char *buf; 998214503Srpaulo size_t len; 999214503Srpaulo 1000214503Srpaulo if (hapd->conf->ctrl_interface == NULL) 1001214503Srpaulo return NULL; 1002214503Srpaulo 1003214503Srpaulo len = os_strlen(hapd->conf->ctrl_interface) + 1004214503Srpaulo os_strlen(hapd->conf->iface) + 2; 1005214503Srpaulo buf = os_malloc(len); 1006214503Srpaulo if (buf == NULL) 1007214503Srpaulo return NULL; 1008214503Srpaulo 1009214503Srpaulo os_snprintf(buf, len, "%s/%s", 1010214503Srpaulo hapd->conf->ctrl_interface, hapd->conf->iface); 1011214503Srpaulo buf[len - 1] = '\0'; 1012214503Srpaulo return buf; 1013214503Srpaulo} 1014214503Srpaulo 1015214503Srpaulo 1016214503Srpaulostatic void hostapd_ctrl_iface_msg_cb(void *ctx, int level, 1017214503Srpaulo const char *txt, size_t len) 1018214503Srpaulo{ 1019214503Srpaulo struct hostapd_data *hapd = ctx; 1020214503Srpaulo if (hapd == NULL) 1021214503Srpaulo return; 1022214503Srpaulo hostapd_ctrl_iface_send(hapd, level, txt, len); 1023214503Srpaulo} 1024214503Srpaulo 1025214503Srpaulo 1026214503Srpauloint hostapd_ctrl_iface_init(struct hostapd_data *hapd) 1027214503Srpaulo{ 1028214503Srpaulo struct sockaddr_un addr; 1029214503Srpaulo int s = -1; 1030214503Srpaulo char *fname = NULL; 1031214503Srpaulo 1032252726Srpaulo if (hapd->ctrl_sock > -1) { 1033252726Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); 1034252726Srpaulo return 0; 1035252726Srpaulo } 1036214503Srpaulo 1037214503Srpaulo if (hapd->conf->ctrl_interface == NULL) 1038214503Srpaulo return 0; 1039214503Srpaulo 1040214503Srpaulo if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 1041214503Srpaulo if (errno == EEXIST) { 1042214503Srpaulo wpa_printf(MSG_DEBUG, "Using existing control " 1043214503Srpaulo "interface directory."); 1044214503Srpaulo } else { 1045214503Srpaulo perror("mkdir[ctrl_interface]"); 1046214503Srpaulo goto fail; 1047214503Srpaulo } 1048214503Srpaulo } 1049214503Srpaulo 1050214503Srpaulo if (hapd->conf->ctrl_interface_gid_set && 1051252726Srpaulo chown(hapd->conf->ctrl_interface, -1, 1052214503Srpaulo hapd->conf->ctrl_interface_gid) < 0) { 1053214503Srpaulo perror("chown[ctrl_interface]"); 1054214503Srpaulo return -1; 1055214503Srpaulo } 1056214503Srpaulo 1057252726Srpaulo#ifdef ANDROID 1058252726Srpaulo /* 1059252726Srpaulo * Android is using umask 0077 which would leave the control interface 1060252726Srpaulo * directory without group access. This breaks things since Wi-Fi 1061252726Srpaulo * framework assumes that this directory can be accessed by other 1062252726Srpaulo * applications in the wifi group. Fix this by adding group access even 1063252726Srpaulo * if umask value would prevent this. 1064252726Srpaulo */ 1065252726Srpaulo if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 1066252726Srpaulo wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", 1067252726Srpaulo strerror(errno)); 1068252726Srpaulo /* Try to continue anyway */ 1069252726Srpaulo } 1070252726Srpaulo#endif /* ANDROID */ 1071252726Srpaulo 1072214503Srpaulo if (os_strlen(hapd->conf->ctrl_interface) + 1 + 1073214503Srpaulo os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) 1074214503Srpaulo goto fail; 1075214503Srpaulo 1076214503Srpaulo s = socket(PF_UNIX, SOCK_DGRAM, 0); 1077214503Srpaulo if (s < 0) { 1078214503Srpaulo perror("socket(PF_UNIX)"); 1079214503Srpaulo goto fail; 1080214503Srpaulo } 1081214503Srpaulo 1082214503Srpaulo os_memset(&addr, 0, sizeof(addr)); 1083214503Srpaulo#ifdef __FreeBSD__ 1084214503Srpaulo addr.sun_len = sizeof(addr); 1085214503Srpaulo#endif /* __FreeBSD__ */ 1086214503Srpaulo addr.sun_family = AF_UNIX; 1087214503Srpaulo fname = hostapd_ctrl_iface_path(hapd); 1088214503Srpaulo if (fname == NULL) 1089214503Srpaulo goto fail; 1090214503Srpaulo os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 1091214503Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1092214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 1093214503Srpaulo strerror(errno)); 1094214503Srpaulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1095214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 1096214503Srpaulo " allow connections - assuming it was left" 1097214503Srpaulo "over from forced program termination"); 1098214503Srpaulo if (unlink(fname) < 0) { 1099214503Srpaulo perror("unlink[ctrl_iface]"); 1100214503Srpaulo wpa_printf(MSG_ERROR, "Could not unlink " 1101214503Srpaulo "existing ctrl_iface socket '%s'", 1102214503Srpaulo fname); 1103214503Srpaulo goto fail; 1104214503Srpaulo } 1105214503Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 1106214503Srpaulo 0) { 1107252726Srpaulo perror("hostapd-ctrl-iface: bind(PF_UNIX)"); 1108214503Srpaulo goto fail; 1109214503Srpaulo } 1110214503Srpaulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 1111214503Srpaulo "ctrl_iface socket '%s'", fname); 1112214503Srpaulo } else { 1113214503Srpaulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 1114214503Srpaulo "be in use - cannot override it"); 1115214503Srpaulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 1116214503Srpaulo "not used anymore", fname); 1117214503Srpaulo os_free(fname); 1118214503Srpaulo fname = NULL; 1119214503Srpaulo goto fail; 1120214503Srpaulo } 1121214503Srpaulo } 1122214503Srpaulo 1123214503Srpaulo if (hapd->conf->ctrl_interface_gid_set && 1124252726Srpaulo chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) { 1125214503Srpaulo perror("chown[ctrl_interface/ifname]"); 1126214503Srpaulo goto fail; 1127214503Srpaulo } 1128214503Srpaulo 1129214503Srpaulo if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 1130214503Srpaulo perror("chmod[ctrl_interface/ifname]"); 1131214503Srpaulo goto fail; 1132214503Srpaulo } 1133214503Srpaulo os_free(fname); 1134214503Srpaulo 1135214503Srpaulo hapd->ctrl_sock = s; 1136214503Srpaulo eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, 1137214503Srpaulo NULL); 1138214503Srpaulo hapd->msg_ctx = hapd; 1139214503Srpaulo wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); 1140214503Srpaulo 1141214503Srpaulo return 0; 1142214503Srpaulo 1143214503Srpaulofail: 1144214503Srpaulo if (s >= 0) 1145214503Srpaulo close(s); 1146214503Srpaulo if (fname) { 1147214503Srpaulo unlink(fname); 1148214503Srpaulo os_free(fname); 1149214503Srpaulo } 1150214503Srpaulo return -1; 1151214503Srpaulo} 1152214503Srpaulo 1153214503Srpaulo 1154214503Srpaulovoid hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) 1155214503Srpaulo{ 1156214503Srpaulo struct wpa_ctrl_dst *dst, *prev; 1157214503Srpaulo 1158214503Srpaulo if (hapd->ctrl_sock > -1) { 1159214503Srpaulo char *fname; 1160214503Srpaulo eloop_unregister_read_sock(hapd->ctrl_sock); 1161214503Srpaulo close(hapd->ctrl_sock); 1162214503Srpaulo hapd->ctrl_sock = -1; 1163214503Srpaulo fname = hostapd_ctrl_iface_path(hapd); 1164214503Srpaulo if (fname) 1165214503Srpaulo unlink(fname); 1166214503Srpaulo os_free(fname); 1167214503Srpaulo 1168214503Srpaulo if (hapd->conf->ctrl_interface && 1169214503Srpaulo rmdir(hapd->conf->ctrl_interface) < 0) { 1170214503Srpaulo if (errno == ENOTEMPTY) { 1171214503Srpaulo wpa_printf(MSG_DEBUG, "Control interface " 1172214503Srpaulo "directory not empty - leaving it " 1173214503Srpaulo "behind"); 1174214503Srpaulo } else { 1175214503Srpaulo perror("rmdir[ctrl_interface]"); 1176214503Srpaulo } 1177214503Srpaulo } 1178214503Srpaulo } 1179214503Srpaulo 1180214503Srpaulo dst = hapd->ctrl_dst; 1181214503Srpaulo while (dst) { 1182214503Srpaulo prev = dst; 1183214503Srpaulo dst = dst->next; 1184214503Srpaulo os_free(prev); 1185214503Srpaulo } 1186214503Srpaulo} 1187214503Srpaulo 1188214503Srpaulo 1189252726Srpaulostatic int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces, 1190252726Srpaulo char *buf) 1191252726Srpaulo{ 1192252726Srpaulo if (hostapd_add_iface(interfaces, buf) < 0) { 1193252726Srpaulo wpa_printf(MSG_ERROR, "Adding interface %s failed", buf); 1194252726Srpaulo return -1; 1195252726Srpaulo } 1196252726Srpaulo return 0; 1197252726Srpaulo} 1198252726Srpaulo 1199252726Srpaulo 1200252726Srpaulostatic int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, 1201252726Srpaulo char *buf) 1202252726Srpaulo{ 1203252726Srpaulo if (hostapd_remove_iface(interfaces, buf) < 0) { 1204252726Srpaulo wpa_printf(MSG_ERROR, "Removing interface %s failed", buf); 1205252726Srpaulo return -1; 1206252726Srpaulo } 1207252726Srpaulo return 0; 1208252726Srpaulo} 1209252726Srpaulo 1210252726Srpaulo 1211252726Srpaulostatic void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, 1212252726Srpaulo void *sock_ctx) 1213252726Srpaulo{ 1214252726Srpaulo void *interfaces = eloop_ctx; 1215252726Srpaulo char buf[256]; 1216252726Srpaulo int res; 1217252726Srpaulo struct sockaddr_un from; 1218252726Srpaulo socklen_t fromlen = sizeof(from); 1219252726Srpaulo char reply[24]; 1220252726Srpaulo int reply_len; 1221252726Srpaulo 1222252726Srpaulo res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 1223252726Srpaulo (struct sockaddr *) &from, &fromlen); 1224252726Srpaulo if (res < 0) { 1225252726Srpaulo perror("recvfrom(ctrl_iface)"); 1226252726Srpaulo return; 1227252726Srpaulo } 1228252726Srpaulo buf[res] = '\0'; 1229252726Srpaulo 1230252726Srpaulo os_memcpy(reply, "OK\n", 3); 1231252726Srpaulo reply_len = 3; 1232252726Srpaulo 1233252726Srpaulo if (os_strcmp(buf, "PING") == 0) { 1234252726Srpaulo os_memcpy(reply, "PONG\n", 5); 1235252726Srpaulo reply_len = 5; 1236252726Srpaulo } else if (os_strncmp(buf, "ADD ", 4) == 0) { 1237252726Srpaulo if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) 1238252726Srpaulo reply_len = -1; 1239252726Srpaulo } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { 1240252726Srpaulo if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) 1241252726Srpaulo reply_len = -1; 1242252726Srpaulo } else { 1243252726Srpaulo wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " 1244252726Srpaulo "ignored"); 1245252726Srpaulo reply_len = -1; 1246252726Srpaulo } 1247252726Srpaulo 1248252726Srpaulo if (reply_len < 0) { 1249252726Srpaulo os_memcpy(reply, "FAIL\n", 5); 1250252726Srpaulo reply_len = 5; 1251252726Srpaulo } 1252252726Srpaulo 1253252726Srpaulo sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 1254252726Srpaulo} 1255252726Srpaulo 1256252726Srpaulo 1257252726Srpaulostatic char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) 1258252726Srpaulo{ 1259252726Srpaulo char *buf; 1260252726Srpaulo size_t len; 1261252726Srpaulo 1262252726Srpaulo if (interface->global_iface_path == NULL) 1263252726Srpaulo return NULL; 1264252726Srpaulo 1265252726Srpaulo len = os_strlen(interface->global_iface_path) + 1266252726Srpaulo os_strlen(interface->global_iface_name) + 2; 1267252726Srpaulo buf = os_malloc(len); 1268252726Srpaulo if (buf == NULL) 1269252726Srpaulo return NULL; 1270252726Srpaulo 1271252726Srpaulo os_snprintf(buf, len, "%s/%s", interface->global_iface_path, 1272252726Srpaulo interface->global_iface_name); 1273252726Srpaulo buf[len - 1] = '\0'; 1274252726Srpaulo return buf; 1275252726Srpaulo} 1276252726Srpaulo 1277252726Srpaulo 1278252726Srpauloint hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) 1279252726Srpaulo{ 1280252726Srpaulo struct sockaddr_un addr; 1281252726Srpaulo int s = -1; 1282252726Srpaulo char *fname = NULL; 1283252726Srpaulo 1284252726Srpaulo if (interface->global_iface_path == NULL) { 1285252726Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface not configured!"); 1286252726Srpaulo return 0; 1287252726Srpaulo } 1288252726Srpaulo 1289252726Srpaulo if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) { 1290252726Srpaulo if (errno == EEXIST) { 1291252726Srpaulo wpa_printf(MSG_DEBUG, "Using existing control " 1292252726Srpaulo "interface directory."); 1293252726Srpaulo } else { 1294252726Srpaulo perror("mkdir[ctrl_interface]"); 1295252726Srpaulo goto fail; 1296252726Srpaulo } 1297252726Srpaulo } 1298252726Srpaulo 1299252726Srpaulo if (os_strlen(interface->global_iface_path) + 1 + 1300252726Srpaulo os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path)) 1301252726Srpaulo goto fail; 1302252726Srpaulo 1303252726Srpaulo s = socket(PF_UNIX, SOCK_DGRAM, 0); 1304252726Srpaulo if (s < 0) { 1305252726Srpaulo perror("socket(PF_UNIX)"); 1306252726Srpaulo goto fail; 1307252726Srpaulo } 1308252726Srpaulo 1309252726Srpaulo os_memset(&addr, 0, sizeof(addr)); 1310252726Srpaulo#ifdef __FreeBSD__ 1311252726Srpaulo addr.sun_len = sizeof(addr); 1312252726Srpaulo#endif /* __FreeBSD__ */ 1313252726Srpaulo addr.sun_family = AF_UNIX; 1314252726Srpaulo fname = hostapd_global_ctrl_iface_path(interface); 1315252726Srpaulo if (fname == NULL) 1316252726Srpaulo goto fail; 1317252726Srpaulo os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 1318252726Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1319252726Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 1320252726Srpaulo strerror(errno)); 1321252726Srpaulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1322252726Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 1323252726Srpaulo " allow connections - assuming it was left" 1324252726Srpaulo "over from forced program termination"); 1325252726Srpaulo if (unlink(fname) < 0) { 1326252726Srpaulo perror("unlink[ctrl_iface]"); 1327252726Srpaulo wpa_printf(MSG_ERROR, "Could not unlink " 1328252726Srpaulo "existing ctrl_iface socket '%s'", 1329252726Srpaulo fname); 1330252726Srpaulo goto fail; 1331252726Srpaulo } 1332252726Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 1333252726Srpaulo 0) { 1334252726Srpaulo perror("bind(PF_UNIX)"); 1335252726Srpaulo goto fail; 1336252726Srpaulo } 1337252726Srpaulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 1338252726Srpaulo "ctrl_iface socket '%s'", fname); 1339252726Srpaulo } else { 1340252726Srpaulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 1341252726Srpaulo "be in use - cannot override it"); 1342252726Srpaulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 1343252726Srpaulo "not used anymore", fname); 1344252726Srpaulo os_free(fname); 1345252726Srpaulo fname = NULL; 1346252726Srpaulo goto fail; 1347252726Srpaulo } 1348252726Srpaulo } 1349252726Srpaulo 1350252726Srpaulo if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 1351252726Srpaulo perror("chmod[ctrl_interface/ifname]"); 1352252726Srpaulo goto fail; 1353252726Srpaulo } 1354252726Srpaulo os_free(fname); 1355252726Srpaulo 1356252726Srpaulo interface->global_ctrl_sock = s; 1357252726Srpaulo eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, 1358252726Srpaulo interface, NULL); 1359252726Srpaulo 1360252726Srpaulo return 0; 1361252726Srpaulo 1362252726Srpaulofail: 1363252726Srpaulo if (s >= 0) 1364252726Srpaulo close(s); 1365252726Srpaulo if (fname) { 1366252726Srpaulo unlink(fname); 1367252726Srpaulo os_free(fname); 1368252726Srpaulo } 1369252726Srpaulo return -1; 1370252726Srpaulo} 1371252726Srpaulo 1372252726Srpaulo 1373252726Srpaulovoid hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) 1374252726Srpaulo{ 1375252726Srpaulo char *fname = NULL; 1376252726Srpaulo 1377252726Srpaulo if (interfaces->global_ctrl_sock > -1) { 1378252726Srpaulo eloop_unregister_read_sock(interfaces->global_ctrl_sock); 1379252726Srpaulo close(interfaces->global_ctrl_sock); 1380252726Srpaulo interfaces->global_ctrl_sock = -1; 1381252726Srpaulo fname = hostapd_global_ctrl_iface_path(interfaces); 1382252726Srpaulo if (fname) { 1383252726Srpaulo unlink(fname); 1384252726Srpaulo os_free(fname); 1385252726Srpaulo } 1386252726Srpaulo 1387252726Srpaulo if (interfaces->global_iface_path && 1388252726Srpaulo rmdir(interfaces->global_iface_path) < 0) { 1389252726Srpaulo if (errno == ENOTEMPTY) { 1390252726Srpaulo wpa_printf(MSG_DEBUG, "Control interface " 1391252726Srpaulo "directory not empty - leaving it " 1392252726Srpaulo "behind"); 1393252726Srpaulo } else { 1394252726Srpaulo perror("rmdir[ctrl_interface]"); 1395252726Srpaulo } 1396252726Srpaulo } 1397252726Srpaulo os_free(interfaces->global_iface_path); 1398252726Srpaulo interfaces->global_iface_path = NULL; 1399252726Srpaulo } 1400252726Srpaulo} 1401252726Srpaulo 1402252726Srpaulo 1403214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 1404214503Srpaulo const char *buf, size_t len) 1405214503Srpaulo{ 1406214503Srpaulo struct wpa_ctrl_dst *dst, *next; 1407214503Srpaulo struct msghdr msg; 1408214503Srpaulo int idx; 1409214503Srpaulo struct iovec io[2]; 1410214503Srpaulo char levelstr[10]; 1411214503Srpaulo 1412214503Srpaulo dst = hapd->ctrl_dst; 1413214503Srpaulo if (hapd->ctrl_sock < 0 || dst == NULL) 1414214503Srpaulo return; 1415214503Srpaulo 1416214503Srpaulo os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 1417214503Srpaulo io[0].iov_base = levelstr; 1418214503Srpaulo io[0].iov_len = os_strlen(levelstr); 1419214503Srpaulo io[1].iov_base = (char *) buf; 1420214503Srpaulo io[1].iov_len = len; 1421214503Srpaulo os_memset(&msg, 0, sizeof(msg)); 1422214503Srpaulo msg.msg_iov = io; 1423214503Srpaulo msg.msg_iovlen = 2; 1424214503Srpaulo 1425214503Srpaulo idx = 0; 1426214503Srpaulo while (dst) { 1427214503Srpaulo next = dst->next; 1428214503Srpaulo if (level >= dst->debug_level) { 1429214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 1430214503Srpaulo (u8 *) dst->addr.sun_path, dst->addrlen - 1431214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 1432214503Srpaulo msg.msg_name = &dst->addr; 1433214503Srpaulo msg.msg_namelen = dst->addrlen; 1434214503Srpaulo if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { 1435214503Srpaulo int _errno = errno; 1436214503Srpaulo wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " 1437214503Srpaulo "%d - %s", 1438214503Srpaulo idx, errno, strerror(errno)); 1439214503Srpaulo dst->errors++; 1440214503Srpaulo if (dst->errors > 10 || _errno == ENOENT) { 1441214503Srpaulo hostapd_ctrl_iface_detach( 1442214503Srpaulo hapd, &dst->addr, 1443214503Srpaulo dst->addrlen); 1444214503Srpaulo } 1445214503Srpaulo } else 1446214503Srpaulo dst->errors = 0; 1447214503Srpaulo } 1448214503Srpaulo idx++; 1449214503Srpaulo dst = next; 1450214503Srpaulo } 1451214503Srpaulo} 1452214503Srpaulo 1453214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 1454