1214503Srpaulo/* 2214503Srpaulo * hostapd / UNIX domain socket -based control interface 3214503Srpaulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4214503Srpaulo * 5214503Srpaulo * This program is free software; you can redistribute it and/or modify 6214503Srpaulo * it under the terms of the GNU General Public License version 2 as 7214503Srpaulo * published by the Free Software Foundation. 8214503Srpaulo * 9214503Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214503Srpaulo * license. 11214503Srpaulo * 12214503Srpaulo * See README and COPYING for more details. 13214503Srpaulo */ 14214503Srpaulo 15214503Srpaulo#include "utils/includes.h" 16214503Srpaulo 17214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 18214503Srpaulo 19214503Srpaulo#include <sys/un.h> 20214503Srpaulo#include <sys/stat.h> 21214503Srpaulo#include <stddef.h> 22214503Srpaulo 23214503Srpaulo#include "utils/common.h" 24214503Srpaulo#include "utils/eloop.h" 25214503Srpaulo#include "common/ieee802_11_defs.h" 26214503Srpaulo#include "drivers/driver.h" 27214503Srpaulo#include "radius/radius_client.h" 28214503Srpaulo#include "ap/hostapd.h" 29214503Srpaulo#include "ap/ap_config.h" 30214503Srpaulo#include "ap/ieee802_1x.h" 31214503Srpaulo#include "ap/wpa_auth.h" 32214503Srpaulo#include "ap/ieee802_11.h" 33214503Srpaulo#include "ap/sta_info.h" 34214503Srpaulo#include "ap/accounting.h" 35214503Srpaulo#include "ap/wps_hostapd.h" 36214503Srpaulo#include "ap/ctrl_iface_ap.h" 37214503Srpaulo#include "ctrl_iface.h" 38214503Srpaulo 39214503Srpaulo 40214503Srpaulostruct wpa_ctrl_dst { 41214503Srpaulo struct wpa_ctrl_dst *next; 42214503Srpaulo struct sockaddr_un addr; 43214503Srpaulo socklen_t addrlen; 44214503Srpaulo int debug_level; 45214503Srpaulo int errors; 46214503Srpaulo}; 47214503Srpaulo 48214503Srpaulo 49214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 50214503Srpaulo const char *buf, size_t len); 51214503Srpaulo 52214503Srpaulo 53214503Srpaulostatic int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, 54214503Srpaulo struct sockaddr_un *from, 55214503Srpaulo socklen_t fromlen) 56214503Srpaulo{ 57214503Srpaulo struct wpa_ctrl_dst *dst; 58214503Srpaulo 59214503Srpaulo dst = os_zalloc(sizeof(*dst)); 60214503Srpaulo if (dst == NULL) 61214503Srpaulo return -1; 62214503Srpaulo os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 63214503Srpaulo dst->addrlen = fromlen; 64214503Srpaulo dst->debug_level = MSG_INFO; 65214503Srpaulo dst->next = hapd->ctrl_dst; 66214503Srpaulo hapd->ctrl_dst = dst; 67214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 68214503Srpaulo (u8 *) from->sun_path, 69214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)); 70214503Srpaulo return 0; 71214503Srpaulo} 72214503Srpaulo 73214503Srpaulo 74214503Srpaulostatic int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, 75214503Srpaulo struct sockaddr_un *from, 76214503Srpaulo socklen_t fromlen) 77214503Srpaulo{ 78214503Srpaulo struct wpa_ctrl_dst *dst, *prev = NULL; 79214503Srpaulo 80214503Srpaulo dst = hapd->ctrl_dst; 81214503Srpaulo while (dst) { 82214503Srpaulo if (fromlen == dst->addrlen && 83214503Srpaulo os_memcmp(from->sun_path, dst->addr.sun_path, 84214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 85214503Srpaulo == 0) { 86214503Srpaulo if (prev == NULL) 87214503Srpaulo hapd->ctrl_dst = dst->next; 88214503Srpaulo else 89214503Srpaulo prev->next = dst->next; 90214503Srpaulo os_free(dst); 91214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 92214503Srpaulo (u8 *) from->sun_path, 93214503Srpaulo fromlen - 94214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 95214503Srpaulo return 0; 96214503Srpaulo } 97214503Srpaulo prev = dst; 98214503Srpaulo dst = dst->next; 99214503Srpaulo } 100214503Srpaulo return -1; 101214503Srpaulo} 102214503Srpaulo 103214503Srpaulo 104214503Srpaulostatic int hostapd_ctrl_iface_level(struct hostapd_data *hapd, 105214503Srpaulo struct sockaddr_un *from, 106214503Srpaulo socklen_t fromlen, 107214503Srpaulo char *level) 108214503Srpaulo{ 109214503Srpaulo struct wpa_ctrl_dst *dst; 110214503Srpaulo 111214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 112214503Srpaulo 113214503Srpaulo dst = hapd->ctrl_dst; 114214503Srpaulo while (dst) { 115214503Srpaulo if (fromlen == dst->addrlen && 116214503Srpaulo os_memcmp(from->sun_path, dst->addr.sun_path, 117214503Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 118214503Srpaulo == 0) { 119214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 120214503Srpaulo "level", (u8 *) from->sun_path, fromlen - 121214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 122214503Srpaulo dst->debug_level = atoi(level); 123214503Srpaulo return 0; 124214503Srpaulo } 125214503Srpaulo dst = dst->next; 126214503Srpaulo } 127214503Srpaulo 128214503Srpaulo return -1; 129214503Srpaulo} 130214503Srpaulo 131214503Srpaulo 132214503Srpaulostatic int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, 133214503Srpaulo const char *txtaddr) 134214503Srpaulo{ 135214503Srpaulo u8 addr[ETH_ALEN]; 136214503Srpaulo struct sta_info *sta; 137214503Srpaulo 138214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); 139214503Srpaulo 140214503Srpaulo if (hwaddr_aton(txtaddr, addr)) 141214503Srpaulo return -1; 142214503Srpaulo 143214503Srpaulo sta = ap_get_sta(hapd, addr); 144214503Srpaulo if (sta) 145214503Srpaulo return 0; 146214503Srpaulo 147214503Srpaulo wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " 148214503Srpaulo "notification", MAC2STR(addr)); 149214503Srpaulo sta = ap_sta_add(hapd, addr); 150214503Srpaulo if (sta == NULL) 151214503Srpaulo return -1; 152214503Srpaulo 153214503Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 154214503Srpaulo return 0; 155214503Srpaulo} 156214503Srpaulo 157214503Srpaulo 158214503Srpaulostatic int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 159214503Srpaulo const char *txtaddr) 160214503Srpaulo{ 161214503Srpaulo u8 addr[ETH_ALEN]; 162214503Srpaulo struct sta_info *sta; 163214503Srpaulo const char *pos; 164214503Srpaulo 165214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr); 166214503Srpaulo 167214503Srpaulo if (hwaddr_aton(txtaddr, addr)) 168214503Srpaulo return -1; 169214503Srpaulo 170214503Srpaulo pos = os_strstr(txtaddr, " test="); 171214503Srpaulo if (pos) { 172214503Srpaulo struct ieee80211_mgmt mgmt; 173214503Srpaulo int encrypt; 174214503Srpaulo if (hapd->driver->send_frame == NULL) 175214503Srpaulo return -1; 176214503Srpaulo pos += 6; 177214503Srpaulo encrypt = atoi(pos); 178214503Srpaulo os_memset(&mgmt, 0, sizeof(mgmt)); 179214503Srpaulo mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 180214503Srpaulo WLAN_FC_STYPE_DEAUTH); 181214503Srpaulo os_memcpy(mgmt.da, addr, ETH_ALEN); 182214503Srpaulo os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 183214503Srpaulo os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 184214503Srpaulo mgmt.u.deauth.reason_code = 185214503Srpaulo host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 186214503Srpaulo if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 187214503Srpaulo IEEE80211_HDRLEN + 188214503Srpaulo sizeof(mgmt.u.deauth), 189214503Srpaulo encrypt) < 0) 190214503Srpaulo return -1; 191214503Srpaulo return 0; 192214503Srpaulo } 193214503Srpaulo 194214503Srpaulo hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); 195214503Srpaulo sta = ap_get_sta(hapd, addr); 196214503Srpaulo if (sta) 197214503Srpaulo ap_sta_deauthenticate(hapd, sta, 198214503Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 199214503Srpaulo 200214503Srpaulo return 0; 201214503Srpaulo} 202214503Srpaulo 203214503Srpaulo 204214503Srpaulostatic int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 205214503Srpaulo const char *txtaddr) 206214503Srpaulo{ 207214503Srpaulo u8 addr[ETH_ALEN]; 208214503Srpaulo struct sta_info *sta; 209214503Srpaulo const char *pos; 210214503Srpaulo 211214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr); 212214503Srpaulo 213214503Srpaulo if (hwaddr_aton(txtaddr, addr)) 214214503Srpaulo return -1; 215214503Srpaulo 216214503Srpaulo pos = os_strstr(txtaddr, " test="); 217214503Srpaulo if (pos) { 218214503Srpaulo struct ieee80211_mgmt mgmt; 219214503Srpaulo int encrypt; 220214503Srpaulo if (hapd->driver->send_frame == NULL) 221214503Srpaulo return -1; 222214503Srpaulo pos += 6; 223214503Srpaulo encrypt = atoi(pos); 224214503Srpaulo os_memset(&mgmt, 0, sizeof(mgmt)); 225214503Srpaulo mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 226214503Srpaulo WLAN_FC_STYPE_DISASSOC); 227214503Srpaulo os_memcpy(mgmt.da, addr, ETH_ALEN); 228214503Srpaulo os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 229214503Srpaulo os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 230214503Srpaulo mgmt.u.disassoc.reason_code = 231214503Srpaulo host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 232214503Srpaulo if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 233214503Srpaulo IEEE80211_HDRLEN + 234214503Srpaulo sizeof(mgmt.u.deauth), 235214503Srpaulo encrypt) < 0) 236214503Srpaulo return -1; 237214503Srpaulo return 0; 238214503Srpaulo } 239214503Srpaulo 240214503Srpaulo hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); 241214503Srpaulo sta = ap_get_sta(hapd, addr); 242214503Srpaulo if (sta) 243214503Srpaulo ap_sta_disassociate(hapd, sta, 244214503Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 245214503Srpaulo 246214503Srpaulo return 0; 247214503Srpaulo} 248214503Srpaulo 249214503Srpaulo 250214503Srpaulo#ifdef CONFIG_IEEE80211W 251214503Srpaulo#ifdef NEED_AP_MLME 252214503Srpaulostatic int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, 253214503Srpaulo const char *txtaddr) 254214503Srpaulo{ 255214503Srpaulo u8 addr[ETH_ALEN]; 256214503Srpaulo u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; 257214503Srpaulo 258214503Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); 259214503Srpaulo 260214503Srpaulo if (hwaddr_aton(txtaddr, addr) || 261214503Srpaulo os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) 262214503Srpaulo return -1; 263214503Srpaulo 264214503Srpaulo ieee802_11_send_sa_query_req(hapd, addr, trans_id); 265214503Srpaulo 266214503Srpaulo return 0; 267214503Srpaulo} 268214503Srpaulo#endif /* NEED_AP_MLME */ 269214503Srpaulo#endif /* CONFIG_IEEE80211W */ 270214503Srpaulo 271214503Srpaulo 272214503Srpaulo#ifdef CONFIG_WPS 273214503Srpaulostatic int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) 274214503Srpaulo{ 275214503Srpaulo char *pin = os_strchr(txt, ' '); 276214503Srpaulo char *timeout_txt; 277214503Srpaulo int timeout; 278214503Srpaulo 279214503Srpaulo if (pin == NULL) 280214503Srpaulo return -1; 281214503Srpaulo *pin++ = '\0'; 282214503Srpaulo 283214503Srpaulo timeout_txt = os_strchr(pin, ' '); 284214503Srpaulo if (timeout_txt) { 285214503Srpaulo *timeout_txt++ = '\0'; 286214503Srpaulo timeout = atoi(timeout_txt); 287214503Srpaulo } else 288214503Srpaulo timeout = 0; 289214503Srpaulo 290214503Srpaulo return hostapd_wps_add_pin(hapd, txt, pin, timeout); 291214503Srpaulo} 292214503Srpaulo 293214503Srpaulo 294214503Srpaulo#ifdef CONFIG_WPS_OOB 295214503Srpaulostatic int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt) 296214503Srpaulo{ 297214503Srpaulo char *path, *method, *name; 298214503Srpaulo 299214503Srpaulo path = os_strchr(txt, ' '); 300214503Srpaulo if (path == NULL) 301214503Srpaulo return -1; 302214503Srpaulo *path++ = '\0'; 303214503Srpaulo 304214503Srpaulo method = os_strchr(path, ' '); 305214503Srpaulo if (method == NULL) 306214503Srpaulo return -1; 307214503Srpaulo *method++ = '\0'; 308214503Srpaulo 309214503Srpaulo name = os_strchr(method, ' '); 310214503Srpaulo if (name != NULL) 311214503Srpaulo *name++ = '\0'; 312214503Srpaulo 313214503Srpaulo return hostapd_wps_start_oob(hapd, txt, path, method, name); 314214503Srpaulo} 315214503Srpaulo#endif /* CONFIG_WPS_OOB */ 316214503Srpaulo 317214503Srpaulo 318214503Srpaulostatic int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, 319214503Srpaulo char *buf, size_t buflen) 320214503Srpaulo{ 321214503Srpaulo int timeout = 300; 322214503Srpaulo char *pos; 323214503Srpaulo const char *pin_txt; 324214503Srpaulo 325214503Srpaulo pos = os_strchr(txt, ' '); 326214503Srpaulo if (pos) 327214503Srpaulo *pos++ = '\0'; 328214503Srpaulo 329214503Srpaulo if (os_strcmp(txt, "disable") == 0) { 330214503Srpaulo hostapd_wps_ap_pin_disable(hapd); 331214503Srpaulo return os_snprintf(buf, buflen, "OK\n"); 332214503Srpaulo } 333214503Srpaulo 334214503Srpaulo if (os_strcmp(txt, "random") == 0) { 335214503Srpaulo if (pos) 336214503Srpaulo timeout = atoi(pos); 337214503Srpaulo pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); 338214503Srpaulo if (pin_txt == NULL) 339214503Srpaulo return -1; 340214503Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 341214503Srpaulo } 342214503Srpaulo 343214503Srpaulo if (os_strcmp(txt, "get") == 0) { 344214503Srpaulo pin_txt = hostapd_wps_ap_pin_get(hapd); 345214503Srpaulo if (pin_txt == NULL) 346214503Srpaulo return -1; 347214503Srpaulo return os_snprintf(buf, buflen, "%s", pin_txt); 348214503Srpaulo } 349214503Srpaulo 350214503Srpaulo if (os_strcmp(txt, "set") == 0) { 351214503Srpaulo char *pin; 352214503Srpaulo if (pos == NULL) 353214503Srpaulo return -1; 354214503Srpaulo pin = pos; 355214503Srpaulo pos = os_strchr(pos, ' '); 356214503Srpaulo if (pos) { 357214503Srpaulo *pos++ = '\0'; 358214503Srpaulo timeout = atoi(pos); 359214503Srpaulo } 360214503Srpaulo if (os_strlen(pin) > buflen) 361214503Srpaulo return -1; 362214503Srpaulo if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) 363214503Srpaulo return -1; 364214503Srpaulo return os_snprintf(buf, buflen, "%s", pin); 365214503Srpaulo } 366214503Srpaulo 367214503Srpaulo return -1; 368214503Srpaulo} 369214503Srpaulo#endif /* CONFIG_WPS */ 370214503Srpaulo 371214503Srpaulo 372214503Srpaulostatic void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 373214503Srpaulo void *sock_ctx) 374214503Srpaulo{ 375214503Srpaulo struct hostapd_data *hapd = eloop_ctx; 376214503Srpaulo char buf[256]; 377214503Srpaulo int res; 378214503Srpaulo struct sockaddr_un from; 379214503Srpaulo socklen_t fromlen = sizeof(from); 380214503Srpaulo char *reply; 381214503Srpaulo const int reply_size = 4096; 382214503Srpaulo int reply_len; 383214503Srpaulo 384214503Srpaulo res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 385214503Srpaulo (struct sockaddr *) &from, &fromlen); 386214503Srpaulo if (res < 0) { 387214503Srpaulo perror("recvfrom(ctrl_iface)"); 388214503Srpaulo return; 389214503Srpaulo } 390214503Srpaulo buf[res] = '\0'; 391214503Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); 392214503Srpaulo 393214503Srpaulo reply = os_malloc(reply_size); 394214503Srpaulo if (reply == NULL) { 395214503Srpaulo sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 396214503Srpaulo fromlen); 397214503Srpaulo return; 398214503Srpaulo } 399214503Srpaulo 400214503Srpaulo os_memcpy(reply, "OK\n", 3); 401214503Srpaulo reply_len = 3; 402214503Srpaulo 403214503Srpaulo if (os_strcmp(buf, "PING") == 0) { 404214503Srpaulo os_memcpy(reply, "PONG\n", 5); 405214503Srpaulo reply_len = 5; 406214503Srpaulo } else if (os_strcmp(buf, "MIB") == 0) { 407214503Srpaulo reply_len = ieee802_11_get_mib(hapd, reply, reply_size); 408214503Srpaulo if (reply_len >= 0) { 409214503Srpaulo res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, 410214503Srpaulo reply_size - reply_len); 411214503Srpaulo if (res < 0) 412214503Srpaulo reply_len = -1; 413214503Srpaulo else 414214503Srpaulo reply_len += res; 415214503Srpaulo } 416214503Srpaulo if (reply_len >= 0) { 417214503Srpaulo res = ieee802_1x_get_mib(hapd, reply + reply_len, 418214503Srpaulo reply_size - reply_len); 419214503Srpaulo if (res < 0) 420214503Srpaulo reply_len = -1; 421214503Srpaulo else 422214503Srpaulo reply_len += res; 423214503Srpaulo } 424214503Srpaulo#ifndef CONFIG_NO_RADIUS 425214503Srpaulo if (reply_len >= 0) { 426214503Srpaulo res = radius_client_get_mib(hapd->radius, 427214503Srpaulo reply + reply_len, 428214503Srpaulo reply_size - reply_len); 429214503Srpaulo if (res < 0) 430214503Srpaulo reply_len = -1; 431214503Srpaulo else 432214503Srpaulo reply_len += res; 433214503Srpaulo } 434214503Srpaulo#endif /* CONFIG_NO_RADIUS */ 435214503Srpaulo } else if (os_strcmp(buf, "STA-FIRST") == 0) { 436214503Srpaulo reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, 437214503Srpaulo reply_size); 438214503Srpaulo } else if (os_strncmp(buf, "STA ", 4) == 0) { 439214503Srpaulo reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, 440214503Srpaulo reply_size); 441214503Srpaulo } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 442214503Srpaulo reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, 443214503Srpaulo reply_size); 444214503Srpaulo } else if (os_strcmp(buf, "ATTACH") == 0) { 445214503Srpaulo if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) 446214503Srpaulo reply_len = -1; 447214503Srpaulo } else if (os_strcmp(buf, "DETACH") == 0) { 448214503Srpaulo if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) 449214503Srpaulo reply_len = -1; 450214503Srpaulo } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 451214503Srpaulo if (hostapd_ctrl_iface_level(hapd, &from, fromlen, 452214503Srpaulo buf + 6)) 453214503Srpaulo reply_len = -1; 454214503Srpaulo } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { 455214503Srpaulo if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) 456214503Srpaulo reply_len = -1; 457214503Srpaulo } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 458214503Srpaulo if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) 459214503Srpaulo reply_len = -1; 460214503Srpaulo } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 461214503Srpaulo if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) 462214503Srpaulo reply_len = -1; 463214503Srpaulo#ifdef CONFIG_IEEE80211W 464214503Srpaulo#ifdef NEED_AP_MLME 465214503Srpaulo } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { 466214503Srpaulo if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) 467214503Srpaulo reply_len = -1; 468214503Srpaulo#endif /* NEED_AP_MLME */ 469214503Srpaulo#endif /* CONFIG_IEEE80211W */ 470214503Srpaulo#ifdef CONFIG_WPS 471214503Srpaulo } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 472214503Srpaulo if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) 473214503Srpaulo reply_len = -1; 474214503Srpaulo } else if (os_strcmp(buf, "WPS_PBC") == 0) { 475214503Srpaulo if (hostapd_wps_button_pushed(hapd)) 476214503Srpaulo reply_len = -1; 477214503Srpaulo#ifdef CONFIG_WPS_OOB 478214503Srpaulo } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) { 479214503Srpaulo if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8)) 480214503Srpaulo reply_len = -1; 481214503Srpaulo#endif /* CONFIG_WPS_OOB */ 482214503Srpaulo } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 483214503Srpaulo reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, 484214503Srpaulo reply, reply_size); 485214503Srpaulo#endif /* CONFIG_WPS */ 486214503Srpaulo } else { 487214503Srpaulo os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 488214503Srpaulo reply_len = 16; 489214503Srpaulo } 490214503Srpaulo 491214503Srpaulo if (reply_len < 0) { 492214503Srpaulo os_memcpy(reply, "FAIL\n", 5); 493214503Srpaulo reply_len = 5; 494214503Srpaulo } 495214503Srpaulo sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 496214503Srpaulo os_free(reply); 497214503Srpaulo} 498214503Srpaulo 499214503Srpaulo 500214503Srpaulostatic char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) 501214503Srpaulo{ 502214503Srpaulo char *buf; 503214503Srpaulo size_t len; 504214503Srpaulo 505214503Srpaulo if (hapd->conf->ctrl_interface == NULL) 506214503Srpaulo return NULL; 507214503Srpaulo 508214503Srpaulo len = os_strlen(hapd->conf->ctrl_interface) + 509214503Srpaulo os_strlen(hapd->conf->iface) + 2; 510214503Srpaulo buf = os_malloc(len); 511214503Srpaulo if (buf == NULL) 512214503Srpaulo return NULL; 513214503Srpaulo 514214503Srpaulo os_snprintf(buf, len, "%s/%s", 515214503Srpaulo hapd->conf->ctrl_interface, hapd->conf->iface); 516214503Srpaulo buf[len - 1] = '\0'; 517214503Srpaulo return buf; 518214503Srpaulo} 519214503Srpaulo 520214503Srpaulo 521214503Srpaulostatic void hostapd_ctrl_iface_msg_cb(void *ctx, int level, 522214503Srpaulo const char *txt, size_t len) 523214503Srpaulo{ 524214503Srpaulo struct hostapd_data *hapd = ctx; 525214503Srpaulo if (hapd == NULL) 526214503Srpaulo return; 527214503Srpaulo hostapd_ctrl_iface_send(hapd, level, txt, len); 528214503Srpaulo} 529214503Srpaulo 530214503Srpaulo 531214503Srpauloint hostapd_ctrl_iface_init(struct hostapd_data *hapd) 532214503Srpaulo{ 533214503Srpaulo struct sockaddr_un addr; 534214503Srpaulo int s = -1; 535214503Srpaulo char *fname = NULL; 536214503Srpaulo 537214503Srpaulo hapd->ctrl_sock = -1; 538214503Srpaulo 539214503Srpaulo if (hapd->conf->ctrl_interface == NULL) 540214503Srpaulo return 0; 541214503Srpaulo 542214503Srpaulo if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 543214503Srpaulo if (errno == EEXIST) { 544214503Srpaulo wpa_printf(MSG_DEBUG, "Using existing control " 545214503Srpaulo "interface directory."); 546214503Srpaulo } else { 547214503Srpaulo perror("mkdir[ctrl_interface]"); 548214503Srpaulo goto fail; 549214503Srpaulo } 550214503Srpaulo } 551214503Srpaulo 552214503Srpaulo if (hapd->conf->ctrl_interface_gid_set && 553214503Srpaulo chown(hapd->conf->ctrl_interface, 0, 554214503Srpaulo hapd->conf->ctrl_interface_gid) < 0) { 555214503Srpaulo perror("chown[ctrl_interface]"); 556214503Srpaulo return -1; 557214503Srpaulo } 558214503Srpaulo 559214503Srpaulo if (os_strlen(hapd->conf->ctrl_interface) + 1 + 560214503Srpaulo os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) 561214503Srpaulo goto fail; 562214503Srpaulo 563214503Srpaulo s = socket(PF_UNIX, SOCK_DGRAM, 0); 564214503Srpaulo if (s < 0) { 565214503Srpaulo perror("socket(PF_UNIX)"); 566214503Srpaulo goto fail; 567214503Srpaulo } 568214503Srpaulo 569214503Srpaulo os_memset(&addr, 0, sizeof(addr)); 570214503Srpaulo#ifdef __FreeBSD__ 571214503Srpaulo addr.sun_len = sizeof(addr); 572214503Srpaulo#endif /* __FreeBSD__ */ 573214503Srpaulo addr.sun_family = AF_UNIX; 574214503Srpaulo fname = hostapd_ctrl_iface_path(hapd); 575214503Srpaulo if (fname == NULL) 576214503Srpaulo goto fail; 577214503Srpaulo os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 578214503Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 579214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 580214503Srpaulo strerror(errno)); 581214503Srpaulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 582214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 583214503Srpaulo " allow connections - assuming it was left" 584214503Srpaulo "over from forced program termination"); 585214503Srpaulo if (unlink(fname) < 0) { 586214503Srpaulo perror("unlink[ctrl_iface]"); 587214503Srpaulo wpa_printf(MSG_ERROR, "Could not unlink " 588214503Srpaulo "existing ctrl_iface socket '%s'", 589214503Srpaulo fname); 590214503Srpaulo goto fail; 591214503Srpaulo } 592214503Srpaulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 593214503Srpaulo 0) { 594214503Srpaulo perror("bind(PF_UNIX)"); 595214503Srpaulo goto fail; 596214503Srpaulo } 597214503Srpaulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 598214503Srpaulo "ctrl_iface socket '%s'", fname); 599214503Srpaulo } else { 600214503Srpaulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 601214503Srpaulo "be in use - cannot override it"); 602214503Srpaulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 603214503Srpaulo "not used anymore", fname); 604214503Srpaulo os_free(fname); 605214503Srpaulo fname = NULL; 606214503Srpaulo goto fail; 607214503Srpaulo } 608214503Srpaulo } 609214503Srpaulo 610214503Srpaulo if (hapd->conf->ctrl_interface_gid_set && 611214503Srpaulo chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) { 612214503Srpaulo perror("chown[ctrl_interface/ifname]"); 613214503Srpaulo goto fail; 614214503Srpaulo } 615214503Srpaulo 616214503Srpaulo if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 617214503Srpaulo perror("chmod[ctrl_interface/ifname]"); 618214503Srpaulo goto fail; 619214503Srpaulo } 620214503Srpaulo os_free(fname); 621214503Srpaulo 622214503Srpaulo hapd->ctrl_sock = s; 623214503Srpaulo eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, 624214503Srpaulo NULL); 625214503Srpaulo hapd->msg_ctx = hapd; 626214503Srpaulo wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); 627214503Srpaulo 628214503Srpaulo return 0; 629214503Srpaulo 630214503Srpaulofail: 631214503Srpaulo if (s >= 0) 632214503Srpaulo close(s); 633214503Srpaulo if (fname) { 634214503Srpaulo unlink(fname); 635214503Srpaulo os_free(fname); 636214503Srpaulo } 637214503Srpaulo return -1; 638214503Srpaulo} 639214503Srpaulo 640214503Srpaulo 641214503Srpaulovoid hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) 642214503Srpaulo{ 643214503Srpaulo struct wpa_ctrl_dst *dst, *prev; 644214503Srpaulo 645214503Srpaulo if (hapd->ctrl_sock > -1) { 646214503Srpaulo char *fname; 647214503Srpaulo eloop_unregister_read_sock(hapd->ctrl_sock); 648214503Srpaulo close(hapd->ctrl_sock); 649214503Srpaulo hapd->ctrl_sock = -1; 650214503Srpaulo fname = hostapd_ctrl_iface_path(hapd); 651214503Srpaulo if (fname) 652214503Srpaulo unlink(fname); 653214503Srpaulo os_free(fname); 654214503Srpaulo 655214503Srpaulo if (hapd->conf->ctrl_interface && 656214503Srpaulo rmdir(hapd->conf->ctrl_interface) < 0) { 657214503Srpaulo if (errno == ENOTEMPTY) { 658214503Srpaulo wpa_printf(MSG_DEBUG, "Control interface " 659214503Srpaulo "directory not empty - leaving it " 660214503Srpaulo "behind"); 661214503Srpaulo } else { 662214503Srpaulo perror("rmdir[ctrl_interface]"); 663214503Srpaulo } 664214503Srpaulo } 665214503Srpaulo } 666214503Srpaulo 667214503Srpaulo dst = hapd->ctrl_dst; 668214503Srpaulo while (dst) { 669214503Srpaulo prev = dst; 670214503Srpaulo dst = dst->next; 671214503Srpaulo os_free(prev); 672214503Srpaulo } 673214503Srpaulo} 674214503Srpaulo 675214503Srpaulo 676214503Srpaulostatic void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 677214503Srpaulo const char *buf, size_t len) 678214503Srpaulo{ 679214503Srpaulo struct wpa_ctrl_dst *dst, *next; 680214503Srpaulo struct msghdr msg; 681214503Srpaulo int idx; 682214503Srpaulo struct iovec io[2]; 683214503Srpaulo char levelstr[10]; 684214503Srpaulo 685214503Srpaulo dst = hapd->ctrl_dst; 686214503Srpaulo if (hapd->ctrl_sock < 0 || dst == NULL) 687214503Srpaulo return; 688214503Srpaulo 689214503Srpaulo os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 690214503Srpaulo io[0].iov_base = levelstr; 691214503Srpaulo io[0].iov_len = os_strlen(levelstr); 692214503Srpaulo io[1].iov_base = (char *) buf; 693214503Srpaulo io[1].iov_len = len; 694214503Srpaulo os_memset(&msg, 0, sizeof(msg)); 695214503Srpaulo msg.msg_iov = io; 696214503Srpaulo msg.msg_iovlen = 2; 697214503Srpaulo 698214503Srpaulo idx = 0; 699214503Srpaulo while (dst) { 700214503Srpaulo next = dst->next; 701214503Srpaulo if (level >= dst->debug_level) { 702214503Srpaulo wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 703214503Srpaulo (u8 *) dst->addr.sun_path, dst->addrlen - 704214503Srpaulo offsetof(struct sockaddr_un, sun_path)); 705214503Srpaulo msg.msg_name = &dst->addr; 706214503Srpaulo msg.msg_namelen = dst->addrlen; 707214503Srpaulo if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { 708214503Srpaulo int _errno = errno; 709214503Srpaulo wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " 710214503Srpaulo "%d - %s", 711214503Srpaulo idx, errno, strerror(errno)); 712214503Srpaulo dst->errors++; 713214503Srpaulo if (dst->errors > 10 || _errno == ENOENT) { 714214503Srpaulo hostapd_ctrl_iface_detach( 715214503Srpaulo hapd, &dst->addr, 716214503Srpaulo dst->addrlen); 717214503Srpaulo } 718214503Srpaulo } else 719214503Srpaulo dst->errors = 0; 720214503Srpaulo } 721214503Srpaulo idx++; 722214503Srpaulo dst = next; 723214503Srpaulo } 724214503Srpaulo} 725214503Srpaulo 726214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 727