1 /* 2 * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response 3 * Copyright (c) 2002-2004, Instant802 Networks, Inc. 4 * Copyright (c) 2005-2006, Devicescape Software, Inc. 5 * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Alternatively, this software may be distributed under the terms of BSD 12 * license. 13 * 14 * See README and COPYING for more details. 15 */ 16 17 #include "utils/includes.h" 18 19 #ifndef CONFIG_NATIVE_WINDOWS 20 21 #include "utils/common.h" 22 #include "common/ieee802_11_defs.h" 23 #include "common/ieee802_11_common.h" 24 #include "drivers/driver.h" 25 #include "hostapd.h" 26 #include "ieee802_11.h" 27 #include "wpa_auth.h" 28 #include "wmm.h" 29 #include "ap_config.h" 30 #include "sta_info.h" 31 #include "beacon.h" 32 33 34 static u8 ieee802_11_erp_info(struct hostapd_data *hapd) 35 { 36 u8 erp = 0; 37 38 if (hapd->iface->current_mode == NULL || 39 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 40 return 0; 41 42 switch (hapd->iconf->cts_protection_type) { 43 case CTS_PROTECTION_FORCE_ENABLED: 44 erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION; 45 break; 46 case CTS_PROTECTION_FORCE_DISABLED: 47 erp = 0; 48 break; 49 case CTS_PROTECTION_AUTOMATIC: 50 if (hapd->iface->olbc) 51 erp |= ERP_INFO_USE_PROTECTION; 52 /* continue */ 53 case CTS_PROTECTION_AUTOMATIC_NO_OLBC: 54 if (hapd->iface->num_sta_non_erp > 0) { 55 erp |= ERP_INFO_NON_ERP_PRESENT | 56 ERP_INFO_USE_PROTECTION; 57 } 58 break; 59 } 60 if (hapd->iface->num_sta_no_short_preamble > 0) 61 erp |= ERP_INFO_BARKER_PREAMBLE_MODE; 62 63 return erp; 64 } 65 66 67 static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) 68 { 69 *eid++ = WLAN_EID_DS_PARAMS; 70 *eid++ = 1; 71 *eid++ = hapd->iconf->channel; 72 return eid; 73 } 74 75 76 static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) 77 { 78 if (hapd->iface->current_mode == NULL || 79 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 80 return eid; 81 82 /* Set NonERP_present and use_protection bits if there 83 * are any associated NonERP stations. */ 84 /* TODO: use_protection bit can be set to zero even if 85 * there are NonERP stations present. This optimization 86 * might be useful if NonERP stations are "quiet". 87 * See 802.11g/D6 E-1 for recommended practice. 88 * In addition, Non ERP present might be set, if AP detects Non ERP 89 * operation on other APs. */ 90 91 /* Add ERP Information element */ 92 *eid++ = WLAN_EID_ERP_INFO; 93 *eid++ = 1; 94 *eid++ = ieee802_11_erp_info(hapd); 95 96 return eid; 97 } 98 99 100 static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, 101 struct hostapd_channel_data *start, 102 struct hostapd_channel_data *prev) 103 { 104 if (end - pos < 3) 105 return pos; 106 107 /* first channel number */ 108 *pos++ = start->chan; 109 /* number of channels */ 110 *pos++ = (prev->chan - start->chan) / chan_spacing + 1; 111 /* maximum transmit power level */ 112 *pos++ = start->max_tx_power; 113 114 return pos; 115 } 116 117 118 static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, 119 int max_len) 120 { 121 u8 *pos = eid; 122 u8 *end = eid + max_len; 123 int i; 124 struct hostapd_hw_modes *mode; 125 struct hostapd_channel_data *start, *prev; 126 int chan_spacing = 1; 127 128 if (!hapd->iconf->ieee80211d || max_len < 6 || 129 hapd->iface->current_mode == NULL) 130 return eid; 131 132 *pos++ = WLAN_EID_COUNTRY; 133 pos++; /* length will be set later */ 134 os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ 135 pos += 3; 136 137 mode = hapd->iface->current_mode; 138 if (mode->mode == HOSTAPD_MODE_IEEE80211A) 139 chan_spacing = 4; 140 141 start = prev = NULL; 142 for (i = 0; i < mode->num_channels; i++) { 143 struct hostapd_channel_data *chan = &mode->channels[i]; 144 if (chan->flag & HOSTAPD_CHAN_DISABLED) 145 continue; 146 if (start && prev && 147 prev->chan + chan_spacing == chan->chan && 148 start->max_tx_power == chan->max_tx_power) { 149 prev = chan; 150 continue; /* can use same entry */ 151 } 152 153 if (start) { 154 pos = hostapd_eid_country_add(pos, end, chan_spacing, 155 start, prev); 156 start = NULL; 157 } 158 159 /* Start new group */ 160 start = prev = chan; 161 } 162 163 if (start) { 164 pos = hostapd_eid_country_add(pos, end, chan_spacing, 165 start, prev); 166 } 167 168 if ((pos - eid) & 1) { 169 if (end - pos < 1) 170 return eid; 171 *pos++ = 0; /* pad for 16-bit alignment */ 172 } 173 174 eid[1] = (pos - eid) - 2; 175 176 return pos; 177 } 178 179 180 static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, 181 struct sta_info *sta) 182 { 183 const u8 *ie; 184 size_t ielen; 185 186 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); 187 if (ie == NULL || ielen > len) 188 return eid; 189 190 os_memcpy(eid, ie, ielen); 191 return eid + ielen; 192 } 193 194 195 void handle_probe_req(struct hostapd_data *hapd, 196 const struct ieee80211_mgmt *mgmt, size_t len) 197 { 198 struct ieee80211_mgmt *resp; 199 struct ieee802_11_elems elems; 200 char *ssid; 201 u8 *pos, *epos; 202 const u8 *ie; 203 size_t ssid_len, ie_len; 204 struct sta_info *sta = NULL; 205 size_t buflen; 206 size_t i; 207 208 ie = mgmt->u.probe_req.variable; 209 ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); 210 211 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) 212 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 213 mgmt->sa, ie, ie_len) > 0) 214 return; 215 216 if (!hapd->iconf->send_probe_response) 217 return; 218 219 if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { 220 wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, 221 MAC2STR(mgmt->sa)); 222 return; 223 } 224 225 ssid = NULL; 226 ssid_len = 0; 227 228 if ((!elems.ssid || !elems.supp_rates)) { 229 wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " 230 "without SSID or supported rates element", 231 MAC2STR(mgmt->sa)); 232 return; 233 } 234 235 if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) { 236 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " 237 "broadcast SSID ignored", MAC2STR(mgmt->sa)); 238 return; 239 } 240 241 sta = ap_get_sta(hapd, mgmt->sa); 242 243 if (elems.ssid_len == 0 || 244 (elems.ssid_len == hapd->conf->ssid.ssid_len && 245 os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 246 0)) { 247 ssid = hapd->conf->ssid.ssid; 248 ssid_len = hapd->conf->ssid.ssid_len; 249 if (sta) 250 sta->ssid_probe = &hapd->conf->ssid; 251 } 252 253 if (!ssid) { 254 if (!(mgmt->da[0] & 0x01)) { 255 char ssid_txt[33]; 256 ieee802_11_print_ssid(ssid_txt, elems.ssid, 257 elems.ssid_len); 258 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR 259 " for foreign SSID '%s'", 260 MAC2STR(mgmt->sa), ssid_txt); 261 } 262 return; 263 } 264 265 /* TODO: verify that supp_rates contains at least one matching rate 266 * with AP configuration */ 267 #define MAX_PROBERESP_LEN 768 268 buflen = MAX_PROBERESP_LEN; 269 #ifdef CONFIG_WPS 270 if (hapd->wps_probe_resp_ie) 271 buflen += wpabuf_len(hapd->wps_probe_resp_ie); 272 #endif /* CONFIG_WPS */ 273 resp = os_zalloc(buflen); 274 if (resp == NULL) 275 return; 276 epos = ((u8 *) resp) + MAX_PROBERESP_LEN; 277 278 resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 279 WLAN_FC_STYPE_PROBE_RESP); 280 os_memcpy(resp->da, mgmt->sa, ETH_ALEN); 281 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); 282 283 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); 284 resp->u.probe_resp.beacon_int = 285 host_to_le16(hapd->iconf->beacon_int); 286 287 /* hardware or low-level driver will setup seq_ctrl and timestamp */ 288 resp->u.probe_resp.capab_info = 289 host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); 290 291 pos = resp->u.probe_resp.variable; 292 *pos++ = WLAN_EID_SSID; 293 *pos++ = ssid_len; 294 os_memcpy(pos, ssid, ssid_len); 295 pos += ssid_len; 296 297 /* Supported rates */ 298 pos = hostapd_eid_supp_rates(hapd, pos); 299 300 /* DS Params */ 301 pos = hostapd_eid_ds_params(hapd, pos); 302 303 pos = hostapd_eid_country(hapd, pos, epos - pos); 304 305 /* ERP Information element */ 306 pos = hostapd_eid_erp_info(hapd, pos); 307 308 /* Extended supported rates */ 309 pos = hostapd_eid_ext_supp_rates(hapd, pos); 310 311 pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); 312 313 /* Wi-Fi Alliance WMM */ 314 pos = hostapd_eid_wmm(hapd, pos); 315 316 #ifdef CONFIG_IEEE80211N 317 pos = hostapd_eid_ht_capabilities(hapd, pos); 318 pos = hostapd_eid_ht_operation(hapd, pos); 319 #endif /* CONFIG_IEEE80211N */ 320 321 #ifdef CONFIG_WPS 322 if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { 323 os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), 324 wpabuf_len(hapd->wps_probe_resp_ie)); 325 pos += wpabuf_len(hapd->wps_probe_resp_ie); 326 } 327 #endif /* CONFIG_WPS */ 328 329 if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0) 330 perror("handle_probe_req: send"); 331 332 os_free(resp); 333 334 wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s " 335 "SSID", MAC2STR(mgmt->sa), 336 elems.ssid_len == 0 ? "broadcast" : "our"); 337 } 338 339 340 void ieee802_11_set_beacon(struct hostapd_data *hapd) 341 { 342 struct ieee80211_mgmt *head; 343 u8 *pos, *tail, *tailpos; 344 u16 capab_info; 345 size_t head_len, tail_len; 346 347 #define BEACON_HEAD_BUF_SIZE 256 348 #define BEACON_TAIL_BUF_SIZE 512 349 head = os_zalloc(BEACON_HEAD_BUF_SIZE); 350 tail_len = BEACON_TAIL_BUF_SIZE; 351 #ifdef CONFIG_WPS 352 if (hapd->conf->wps_state && hapd->wps_beacon_ie) 353 tail_len += wpabuf_len(hapd->wps_beacon_ie); 354 #endif /* CONFIG_WPS */ 355 tailpos = tail = os_malloc(tail_len); 356 if (head == NULL || tail == NULL) { 357 wpa_printf(MSG_ERROR, "Failed to set beacon data"); 358 os_free(head); 359 os_free(tail); 360 return; 361 } 362 363 head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 364 WLAN_FC_STYPE_BEACON); 365 head->duration = host_to_le16(0); 366 os_memset(head->da, 0xff, ETH_ALEN); 367 368 os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); 369 os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); 370 head->u.beacon.beacon_int = 371 host_to_le16(hapd->iconf->beacon_int); 372 373 /* hardware or low-level driver will setup seq_ctrl and timestamp */ 374 capab_info = hostapd_own_capab_info(hapd, NULL, 0); 375 head->u.beacon.capab_info = host_to_le16(capab_info); 376 pos = &head->u.beacon.variable[0]; 377 378 /* SSID */ 379 *pos++ = WLAN_EID_SSID; 380 if (hapd->conf->ignore_broadcast_ssid == 2) { 381 /* clear the data, but keep the correct length of the SSID */ 382 *pos++ = hapd->conf->ssid.ssid_len; 383 os_memset(pos, 0, hapd->conf->ssid.ssid_len); 384 pos += hapd->conf->ssid.ssid_len; 385 } else if (hapd->conf->ignore_broadcast_ssid) { 386 *pos++ = 0; /* empty SSID */ 387 } else { 388 *pos++ = hapd->conf->ssid.ssid_len; 389 os_memcpy(pos, hapd->conf->ssid.ssid, 390 hapd->conf->ssid.ssid_len); 391 pos += hapd->conf->ssid.ssid_len; 392 } 393 394 /* Supported rates */ 395 pos = hostapd_eid_supp_rates(hapd, pos); 396 397 /* DS Params */ 398 pos = hostapd_eid_ds_params(hapd, pos); 399 400 head_len = pos - (u8 *) head; 401 402 tailpos = hostapd_eid_country(hapd, tailpos, 403 tail + BEACON_TAIL_BUF_SIZE - tailpos); 404 405 /* ERP Information element */ 406 tailpos = hostapd_eid_erp_info(hapd, tailpos); 407 408 /* Extended supported rates */ 409 tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); 410 411 tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - 412 tailpos, NULL); 413 414 /* Wi-Fi Alliance WMM */ 415 tailpos = hostapd_eid_wmm(hapd, tailpos); 416 417 #ifdef CONFIG_IEEE80211N 418 tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); 419 tailpos = hostapd_eid_ht_operation(hapd, tailpos); 420 #endif /* CONFIG_IEEE80211N */ 421 422 #ifdef CONFIG_WPS 423 if (hapd->conf->wps_state && hapd->wps_beacon_ie) { 424 os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), 425 wpabuf_len(hapd->wps_beacon_ie)); 426 tailpos += wpabuf_len(hapd->wps_beacon_ie); 427 } 428 #endif /* CONFIG_WPS */ 429 430 tail_len = tailpos > tail ? tailpos - tail : 0; 431 432 if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len, 433 tail, tail_len, hapd->conf->dtim_period, 434 hapd->iconf->beacon_int)) 435 wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " 436 "period"); 437 438 os_free(tail); 439 os_free(head); 440 441 hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & 442 ERP_INFO_USE_PROTECTION)); 443 } 444 445 446 void ieee802_11_set_beacons(struct hostapd_iface *iface) 447 { 448 size_t i; 449 for (i = 0; i < iface->num_bss; i++) 450 ieee802_11_set_beacon(iface->bss[i]); 451 } 452 453 #endif /* CONFIG_NATIVE_WINDOWS */ 454