ctrl_iface_ap.c revision 04f534e89ed127da4077485376f24debc50d80d5
1/* 2 * Control interface for shared AP commands 3 * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "utils/includes.h" 10 11#include "utils/common.h" 12#include "common/ieee802_11_defs.h" 13#include "hostapd.h" 14#include "ieee802_1x.h" 15#include "wpa_auth.h" 16#include "ieee802_11.h" 17#include "sta_info.h" 18#include "wps_hostapd.h" 19#include "p2p_hostapd.h" 20#include "ctrl_iface_ap.h" 21#include "ap_drv_ops.h" 22 23 24static int hostapd_get_sta_conn_time(struct sta_info *sta, 25 char *buf, size_t buflen) 26{ 27 struct os_reltime age; 28 int len = 0, ret; 29 30 if (!sta->connected_time.sec) 31 return 0; 32 33 os_reltime_age(&sta->connected_time, &age); 34 35 ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n", 36 (unsigned int) age.sec); 37 if (ret < 0 || (size_t) ret >= buflen - len) 38 return len; 39 len += ret; 40 41 return len; 42} 43 44 45static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, 46 struct sta_info *sta, 47 char *buf, size_t buflen) 48{ 49 int len, res, ret; 50 51 if (sta == NULL) { 52 ret = os_snprintf(buf, buflen, "FAIL\n"); 53 if (ret < 0 || (size_t) ret >= buflen) 54 return 0; 55 return ret; 56 } 57 58 len = 0; 59 ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", 60 MAC2STR(sta->addr)); 61 if (ret < 0 || (size_t) ret >= buflen - len) 62 return len; 63 len += ret; 64 65 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); 66 if (res >= 0) 67 len += res; 68 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); 69 if (res >= 0) 70 len += res; 71 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); 72 if (res >= 0) 73 len += res; 74 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, 75 buflen - len); 76 if (res >= 0) 77 len += res; 78 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len); 79 if (res >= 0) 80 len += res; 81 82 res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len); 83 if (res >= 0) 84 len += res; 85 86 return len; 87} 88 89 90int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, 91 char *buf, size_t buflen) 92{ 93 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); 94} 95 96 97int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, 98 char *buf, size_t buflen) 99{ 100 u8 addr[ETH_ALEN]; 101 int ret; 102 103 if (hwaddr_aton(txtaddr, addr)) { 104 ret = os_snprintf(buf, buflen, "FAIL\n"); 105 if (ret < 0 || (size_t) ret >= buflen) 106 return 0; 107 return ret; 108 } 109 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), 110 buf, buflen); 111} 112 113 114int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, 115 char *buf, size_t buflen) 116{ 117 u8 addr[ETH_ALEN]; 118 struct sta_info *sta; 119 int ret; 120 121 if (hwaddr_aton(txtaddr, addr) || 122 (sta = ap_get_sta(hapd, addr)) == NULL) { 123 ret = os_snprintf(buf, buflen, "FAIL\n"); 124 if (ret < 0 || (size_t) ret >= buflen) 125 return 0; 126 return ret; 127 } 128 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); 129} 130 131 132#ifdef CONFIG_P2P_MANAGER 133static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, 134 u8 minor_reason_code, const u8 *addr) 135{ 136 struct ieee80211_mgmt *mgmt; 137 int ret; 138 u8 *pos; 139 140 if (hapd->driver->send_frame == NULL) 141 return -1; 142 143 mgmt = os_zalloc(sizeof(*mgmt) + 100); 144 if (mgmt == NULL) 145 return -1; 146 147 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR 148 " with minor reason code %u (stype=%u)", 149 MAC2STR(addr), minor_reason_code, stype); 150 151 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); 152 os_memcpy(mgmt->da, addr, ETH_ALEN); 153 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 154 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 155 if (stype == WLAN_FC_STYPE_DEAUTH) { 156 mgmt->u.deauth.reason_code = 157 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 158 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); 159 } else { 160 mgmt->u.disassoc.reason_code = 161 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 162 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); 163 } 164 165 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 166 *pos++ = 4 + 3 + 1; 167 WPA_PUT_BE24(pos, OUI_WFA); 168 pos += 3; 169 *pos++ = P2P_OUI_TYPE; 170 171 *pos++ = P2P_ATTR_MINOR_REASON_CODE; 172 WPA_PUT_LE16(pos, 1); 173 pos += 2; 174 *pos++ = minor_reason_code; 175 176 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, 177 pos - (u8 *) mgmt, 1); 178 os_free(mgmt); 179 180 return ret < 0 ? -1 : 0; 181} 182#endif /* CONFIG_P2P_MANAGER */ 183 184 185int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 186 const char *txtaddr) 187{ 188 u8 addr[ETH_ALEN]; 189 struct sta_info *sta; 190 const char *pos; 191 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 192 193 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", 194 txtaddr); 195 196 if (hwaddr_aton(txtaddr, addr)) 197 return -1; 198 199 pos = os_strstr(txtaddr, " test="); 200 if (pos) { 201 struct ieee80211_mgmt mgmt; 202 int encrypt; 203 if (hapd->driver->send_frame == NULL) 204 return -1; 205 pos += 6; 206 encrypt = atoi(pos); 207 os_memset(&mgmt, 0, sizeof(mgmt)); 208 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 209 WLAN_FC_STYPE_DEAUTH); 210 os_memcpy(mgmt.da, addr, ETH_ALEN); 211 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 212 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 213 mgmt.u.deauth.reason_code = 214 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 215 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 216 IEEE80211_HDRLEN + 217 sizeof(mgmt.u.deauth), 218 encrypt) < 0) 219 return -1; 220 return 0; 221 } 222 223#ifdef CONFIG_P2P_MANAGER 224 pos = os_strstr(txtaddr, " p2p="); 225 if (pos) { 226 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH, 227 atoi(pos + 5), addr); 228 } 229#endif /* CONFIG_P2P_MANAGER */ 230 231 pos = os_strstr(txtaddr, " reason="); 232 if (pos) 233 reason = atoi(pos + 8); 234 235 hostapd_drv_sta_deauth(hapd, addr, reason); 236 sta = ap_get_sta(hapd, addr); 237 if (sta) 238 ap_sta_deauthenticate(hapd, sta, reason); 239 else if (addr[0] == 0xff) 240 hostapd_free_stas(hapd); 241 242 return 0; 243} 244 245 246int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 247 const char *txtaddr) 248{ 249 u8 addr[ETH_ALEN]; 250 struct sta_info *sta; 251 const char *pos; 252 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 253 254 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", 255 txtaddr); 256 257 if (hwaddr_aton(txtaddr, addr)) 258 return -1; 259 260 pos = os_strstr(txtaddr, " test="); 261 if (pos) { 262 struct ieee80211_mgmt mgmt; 263 int encrypt; 264 if (hapd->driver->send_frame == NULL) 265 return -1; 266 pos += 6; 267 encrypt = atoi(pos); 268 os_memset(&mgmt, 0, sizeof(mgmt)); 269 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 270 WLAN_FC_STYPE_DISASSOC); 271 os_memcpy(mgmt.da, addr, ETH_ALEN); 272 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 273 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 274 mgmt.u.disassoc.reason_code = 275 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 276 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 277 IEEE80211_HDRLEN + 278 sizeof(mgmt.u.deauth), 279 encrypt) < 0) 280 return -1; 281 return 0; 282 } 283 284#ifdef CONFIG_P2P_MANAGER 285 pos = os_strstr(txtaddr, " p2p="); 286 if (pos) { 287 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC, 288 atoi(pos + 5), addr); 289 } 290#endif /* CONFIG_P2P_MANAGER */ 291 292 pos = os_strstr(txtaddr, " reason="); 293 if (pos) 294 reason = atoi(pos + 8); 295 296 hostapd_drv_sta_disassoc(hapd, addr, reason); 297 sta = ap_get_sta(hapd, addr); 298 if (sta) 299 ap_sta_disassociate(hapd, sta, reason); 300 else if (addr[0] == 0xff) 301 hostapd_free_stas(hapd); 302 303 return 0; 304} 305 306 307int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, 308 size_t buflen) 309{ 310 struct hostapd_iface *iface = hapd->iface; 311 int len = 0, ret; 312 size_t i; 313 314 ret = os_snprintf(buf + len, buflen - len, 315 "state=%s\n" 316 "phy=%s\n" 317 "freq=%d\n" 318 "num_sta_non_erp=%d\n" 319 "num_sta_no_short_slot_time=%d\n" 320 "num_sta_no_short_preamble=%d\n" 321 "olbc=%d\n" 322 "num_sta_ht_no_gf=%d\n" 323 "num_sta_no_ht=%d\n" 324 "num_sta_ht_20_mhz=%d\n" 325 "olbc_ht=%d\n" 326 "ht_op_mode=0x%x\n", 327 hostapd_state_text(iface->state), 328 iface->phy, 329 iface->freq, 330 iface->num_sta_non_erp, 331 iface->num_sta_no_short_slot_time, 332 iface->num_sta_no_short_preamble, 333 iface->olbc, 334 iface->num_sta_ht_no_gf, 335 iface->num_sta_no_ht, 336 iface->num_sta_ht_20mhz, 337 iface->olbc_ht, 338 iface->ht_op_mode); 339 if (ret < 0 || (size_t) ret >= buflen - len) 340 return len; 341 len += ret; 342 343 ret = os_snprintf(buf + len, buflen - len, 344 "channel=%u\n" 345 "secondary_channel=%d\n" 346 "ieee80211n=%d\n" 347 "ieee80211ac=%d\n" 348 "vht_oper_chwidth=%d\n" 349 "vht_oper_centr_freq_seg0_idx=%d\n" 350 "vht_oper_centr_freq_seg1_idx=%d\n", 351 iface->conf->channel, 352 iface->conf->secondary_channel, 353 iface->conf->ieee80211n, 354 iface->conf->ieee80211ac, 355 iface->conf->vht_oper_chwidth, 356 iface->conf->vht_oper_centr_freq_seg0_idx, 357 iface->conf->vht_oper_centr_freq_seg1_idx); 358 if (ret < 0 || (size_t) ret >= buflen - len) 359 return len; 360 len += ret; 361 362 for (i = 0; i < iface->num_bss; i++) { 363 struct hostapd_data *bss = iface->bss[i]; 364 ret = os_snprintf(buf + len, buflen - len, 365 "bss[%d]=%s\n" 366 "bssid[%d]=" MACSTR "\n" 367 "ssid[%d]=%s\n" 368 "num_sta[%d]=%d\n", 369 (int) i, bss->conf->iface, 370 (int) i, MAC2STR(bss->own_addr), 371 (int) i, 372 wpa_ssid_txt(bss->conf->ssid.ssid, 373 bss->conf->ssid.ssid_len), 374 (int) i, bss->num_sta); 375 if (ret < 0 || (size_t) ret >= buflen - len) 376 return len; 377 len += ret; 378 } 379 380 return len; 381} 382 383 384int hostapd_parse_csa_settings(const char *pos, 385 struct csa_settings *settings) 386{ 387 char *end; 388 389 if (!settings) 390 return -1; 391 392 os_memset(settings, 0, sizeof(*settings)); 393 settings->cs_count = strtol(pos, &end, 10); 394 if (pos == end) { 395 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided"); 396 return -1; 397 } 398 399 settings->freq_params.freq = atoi(end); 400 if (settings->freq_params.freq == 0) { 401 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided"); 402 return -1; 403 } 404 405#define SET_CSA_SETTING(str) \ 406 do { \ 407 const char *pos2 = os_strstr(pos, " " #str "="); \ 408 if (pos2) { \ 409 pos2 += sizeof(" " #str "=") - 1; \ 410 settings->freq_params.str = atoi(pos2); \ 411 } \ 412 } while (0) 413 414 SET_CSA_SETTING(center_freq1); 415 SET_CSA_SETTING(center_freq2); 416 SET_CSA_SETTING(bandwidth); 417 SET_CSA_SETTING(sec_channel_offset); 418 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); 419 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); 420 settings->block_tx = !!os_strstr(pos, " blocktx"); 421#undef SET_CSA_SETTING 422 423 return 0; 424} 425