$search
00001 /* 00002 * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response 00003 * Copyright (c) 2002-2004, Instant802 Networks, Inc. 00004 * Copyright (c) 2005-2006, Devicescape Software, Inc. 00005 * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License version 2 as 00009 * published by the Free Software Foundation. 00010 * 00011 * Alternatively, this software may be distributed under the terms of BSD 00012 * license. 00013 * 00014 * See README and COPYING for more details. 00015 */ 00016 00017 #include "utils/includes.h" 00018 00019 #ifndef CONFIG_NATIVE_WINDOWS 00020 00021 #include "utils/common.h" 00022 #include "common/ieee802_11_defs.h" 00023 #include "common/ieee802_11_common.h" 00024 #include "drivers/driver.h" 00025 #include "hostapd.h" 00026 #include "ieee802_11.h" 00027 #include "wpa_auth.h" 00028 #include "wmm.h" 00029 #include "ap_config.h" 00030 #include "sta_info.h" 00031 #include "beacon.h" 00032 00033 00034 static u8 ieee802_11_erp_info(struct hostapd_data *hapd) 00035 { 00036 u8 erp = 0; 00037 00038 if (hapd->iface->current_mode == NULL || 00039 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 00040 return 0; 00041 00042 switch (hapd->iconf->cts_protection_type) { 00043 case CTS_PROTECTION_FORCE_ENABLED: 00044 erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION; 00045 break; 00046 case CTS_PROTECTION_FORCE_DISABLED: 00047 erp = 0; 00048 break; 00049 case CTS_PROTECTION_AUTOMATIC: 00050 if (hapd->iface->olbc) 00051 erp |= ERP_INFO_USE_PROTECTION; 00052 /* continue */ 00053 case CTS_PROTECTION_AUTOMATIC_NO_OLBC: 00054 if (hapd->iface->num_sta_non_erp > 0) { 00055 erp |= ERP_INFO_NON_ERP_PRESENT | 00056 ERP_INFO_USE_PROTECTION; 00057 } 00058 break; 00059 } 00060 if (hapd->iface->num_sta_no_short_preamble > 0) 00061 erp |= ERP_INFO_BARKER_PREAMBLE_MODE; 00062 00063 return erp; 00064 } 00065 00066 00067 static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) 00068 { 00069 *eid++ = WLAN_EID_DS_PARAMS; 00070 *eid++ = 1; 00071 *eid++ = hapd->iconf->channel; 00072 return eid; 00073 } 00074 00075 00076 static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) 00077 { 00078 if (hapd->iface->current_mode == NULL || 00079 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 00080 return eid; 00081 00082 /* Set NonERP_present and use_protection bits if there 00083 * are any associated NonERP stations. */ 00084 /* TODO: use_protection bit can be set to zero even if 00085 * there are NonERP stations present. This optimization 00086 * might be useful if NonERP stations are "quiet". 00087 * See 802.11g/D6 E-1 for recommended practice. 00088 * In addition, Non ERP present might be set, if AP detects Non ERP 00089 * operation on other APs. */ 00090 00091 /* Add ERP Information element */ 00092 *eid++ = WLAN_EID_ERP_INFO; 00093 *eid++ = 1; 00094 *eid++ = ieee802_11_erp_info(hapd); 00095 00096 return eid; 00097 } 00098 00099 00100 static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, 00101 struct hostapd_channel_data *start, 00102 struct hostapd_channel_data *prev) 00103 { 00104 if (end - pos < 3) 00105 return pos; 00106 00107 /* first channel number */ 00108 *pos++ = start->chan; 00109 /* number of channels */ 00110 *pos++ = (prev->chan - start->chan) / chan_spacing + 1; 00111 /* maximum transmit power level */ 00112 *pos++ = start->max_tx_power; 00113 00114 return pos; 00115 } 00116 00117 00118 static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, 00119 int max_len) 00120 { 00121 u8 *pos = eid; 00122 u8 *end = eid + max_len; 00123 int i; 00124 struct hostapd_hw_modes *mode; 00125 struct hostapd_channel_data *start, *prev; 00126 int chan_spacing = 1; 00127 00128 if (!hapd->iconf->ieee80211d || max_len < 6 || 00129 hapd->iface->current_mode == NULL) 00130 return eid; 00131 00132 *pos++ = WLAN_EID_COUNTRY; 00133 pos++; /* length will be set later */ 00134 os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ 00135 pos += 3; 00136 00137 mode = hapd->iface->current_mode; 00138 if (mode->mode == HOSTAPD_MODE_IEEE80211A) 00139 chan_spacing = 4; 00140 00141 start = prev = NULL; 00142 for (i = 0; i < mode->num_channels; i++) { 00143 struct hostapd_channel_data *chan = &mode->channels[i]; 00144 if (chan->flag & HOSTAPD_CHAN_DISABLED) 00145 continue; 00146 if (start && prev && 00147 prev->chan + chan_spacing == chan->chan && 00148 start->max_tx_power == chan->max_tx_power) { 00149 prev = chan; 00150 continue; /* can use same entry */ 00151 } 00152 00153 if (start) { 00154 pos = hostapd_eid_country_add(pos, end, chan_spacing, 00155 start, prev); 00156 start = NULL; 00157 } 00158 00159 /* Start new group */ 00160 start = prev = chan; 00161 } 00162 00163 if (start) { 00164 pos = hostapd_eid_country_add(pos, end, chan_spacing, 00165 start, prev); 00166 } 00167 00168 if ((pos - eid) & 1) { 00169 if (end - pos < 1) 00170 return eid; 00171 *pos++ = 0; /* pad for 16-bit alignment */ 00172 } 00173 00174 eid[1] = (pos - eid) - 2; 00175 00176 return pos; 00177 } 00178 00179 00180 static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, 00181 struct sta_info *sta) 00182 { 00183 const u8 *ie; 00184 size_t ielen; 00185 00186 ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); 00187 if (ie == NULL || ielen > len) 00188 return eid; 00189 00190 os_memcpy(eid, ie, ielen); 00191 return eid + ielen; 00192 } 00193 00194 00195 void handle_probe_req(struct hostapd_data *hapd, 00196 const struct ieee80211_mgmt *mgmt, size_t len) 00197 { 00198 struct ieee80211_mgmt *resp; 00199 struct ieee802_11_elems elems; 00200 char *ssid; 00201 u8 *pos, *epos; 00202 const u8 *ie; 00203 size_t ssid_len, ie_len; 00204 struct sta_info *sta = NULL; 00205 size_t buflen; 00206 size_t i; 00207 00208 ie = mgmt->u.probe_req.variable; 00209 ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); 00210 00211 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) 00212 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 00213 mgmt->sa, ie, ie_len) > 0) 00214 return; 00215 00216 if (!hapd->iconf->send_probe_response) 00217 return; 00218 00219 if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { 00220 wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, 00221 MAC2STR(mgmt->sa)); 00222 return; 00223 } 00224 00225 ssid = NULL; 00226 ssid_len = 0; 00227 00228 if ((!elems.ssid || !elems.supp_rates)) { 00229 wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " 00230 "without SSID or supported rates element", 00231 MAC2STR(mgmt->sa)); 00232 return; 00233 } 00234 00235 if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) { 00236 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " 00237 "broadcast SSID ignored", MAC2STR(mgmt->sa)); 00238 return; 00239 } 00240 00241 sta = ap_get_sta(hapd, mgmt->sa); 00242 00243 if (elems.ssid_len == 0 || 00244 (elems.ssid_len == hapd->conf->ssid.ssid_len && 00245 os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 00246 0)) { 00247 ssid = hapd->conf->ssid.ssid; 00248 ssid_len = hapd->conf->ssid.ssid_len; 00249 if (sta) 00250 sta->ssid_probe = &hapd->conf->ssid; 00251 } 00252 00253 if (!ssid) { 00254 if (!(mgmt->da[0] & 0x01)) { 00255 char ssid_txt[33]; 00256 ieee802_11_print_ssid(ssid_txt, elems.ssid, 00257 elems.ssid_len); 00258 wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR 00259 " for foreign SSID '%s'", 00260 MAC2STR(mgmt->sa), ssid_txt); 00261 } 00262 return; 00263 } 00264 00265 /* TODO: verify that supp_rates contains at least one matching rate 00266 * with AP configuration */ 00267 #define MAX_PROBERESP_LEN 768 00268 buflen = MAX_PROBERESP_LEN; 00269 #ifdef CONFIG_WPS 00270 if (hapd->wps_probe_resp_ie) 00271 buflen += wpabuf_len(hapd->wps_probe_resp_ie); 00272 #endif /* CONFIG_WPS */ 00273 resp = os_zalloc(buflen); 00274 if (resp == NULL) 00275 return; 00276 epos = ((u8 *) resp) + MAX_PROBERESP_LEN; 00277 00278 resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 00279 WLAN_FC_STYPE_PROBE_RESP); 00280 os_memcpy(resp->da, mgmt->sa, ETH_ALEN); 00281 os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); 00282 00283 os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); 00284 resp->u.probe_resp.beacon_int = 00285 host_to_le16(hapd->iconf->beacon_int); 00286 00287 /* hardware or low-level driver will setup seq_ctrl and timestamp */ 00288 resp->u.probe_resp.capab_info = 00289 host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); 00290 00291 pos = resp->u.probe_resp.variable; 00292 *pos++ = WLAN_EID_SSID; 00293 *pos++ = ssid_len; 00294 os_memcpy(pos, ssid, ssid_len); 00295 pos += ssid_len; 00296 00297 /* Supported rates */ 00298 pos = hostapd_eid_supp_rates(hapd, pos); 00299 00300 /* DS Params */ 00301 pos = hostapd_eid_ds_params(hapd, pos); 00302 00303 pos = hostapd_eid_country(hapd, pos, epos - pos); 00304 00305 /* ERP Information element */ 00306 pos = hostapd_eid_erp_info(hapd, pos); 00307 00308 /* Extended supported rates */ 00309 pos = hostapd_eid_ext_supp_rates(hapd, pos); 00310 00311 pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); 00312 00313 /* Wi-Fi Alliance WMM */ 00314 pos = hostapd_eid_wmm(hapd, pos); 00315 00316 #ifdef CONFIG_IEEE80211N 00317 pos = hostapd_eid_ht_capabilities(hapd, pos); 00318 pos = hostapd_eid_ht_operation(hapd, pos); 00319 #endif /* CONFIG_IEEE80211N */ 00320 00321 #ifdef CONFIG_WPS 00322 if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { 00323 os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), 00324 wpabuf_len(hapd->wps_probe_resp_ie)); 00325 pos += wpabuf_len(hapd->wps_probe_resp_ie); 00326 } 00327 #endif /* CONFIG_WPS */ 00328 00329 if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0) 00330 perror("handle_probe_req: send"); 00331 00332 os_free(resp); 00333 00334 wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s " 00335 "SSID", MAC2STR(mgmt->sa), 00336 elems.ssid_len == 0 ? "broadcast" : "our"); 00337 } 00338 00339 00340 void ieee802_11_set_beacon(struct hostapd_data *hapd) 00341 { 00342 struct ieee80211_mgmt *head; 00343 u8 *pos, *tail, *tailpos; 00344 u16 capab_info; 00345 size_t head_len, tail_len; 00346 00347 #define BEACON_HEAD_BUF_SIZE 256 00348 #define BEACON_TAIL_BUF_SIZE 512 00349 head = os_zalloc(BEACON_HEAD_BUF_SIZE); 00350 tail_len = BEACON_TAIL_BUF_SIZE; 00351 #ifdef CONFIG_WPS 00352 if (hapd->conf->wps_state && hapd->wps_beacon_ie) 00353 tail_len += wpabuf_len(hapd->wps_beacon_ie); 00354 #endif /* CONFIG_WPS */ 00355 tailpos = tail = os_malloc(tail_len); 00356 if (head == NULL || tail == NULL) { 00357 wpa_printf(MSG_ERROR, "Failed to set beacon data"); 00358 os_free(head); 00359 os_free(tail); 00360 return; 00361 } 00362 00363 head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 00364 WLAN_FC_STYPE_BEACON); 00365 head->duration = host_to_le16(0); 00366 os_memset(head->da, 0xff, ETH_ALEN); 00367 00368 os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); 00369 os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); 00370 head->u.beacon.beacon_int = 00371 host_to_le16(hapd->iconf->beacon_int); 00372 00373 /* hardware or low-level driver will setup seq_ctrl and timestamp */ 00374 capab_info = hostapd_own_capab_info(hapd, NULL, 0); 00375 head->u.beacon.capab_info = host_to_le16(capab_info); 00376 pos = &head->u.beacon.variable[0]; 00377 00378 /* SSID */ 00379 *pos++ = WLAN_EID_SSID; 00380 if (hapd->conf->ignore_broadcast_ssid == 2) { 00381 /* clear the data, but keep the correct length of the SSID */ 00382 *pos++ = hapd->conf->ssid.ssid_len; 00383 os_memset(pos, 0, hapd->conf->ssid.ssid_len); 00384 pos += hapd->conf->ssid.ssid_len; 00385 } else if (hapd->conf->ignore_broadcast_ssid) { 00386 *pos++ = 0; /* empty SSID */ 00387 } else { 00388 *pos++ = hapd->conf->ssid.ssid_len; 00389 os_memcpy(pos, hapd->conf->ssid.ssid, 00390 hapd->conf->ssid.ssid_len); 00391 pos += hapd->conf->ssid.ssid_len; 00392 } 00393 00394 /* Supported rates */ 00395 pos = hostapd_eid_supp_rates(hapd, pos); 00396 00397 /* DS Params */ 00398 pos = hostapd_eid_ds_params(hapd, pos); 00399 00400 head_len = pos - (u8 *) head; 00401 00402 tailpos = hostapd_eid_country(hapd, tailpos, 00403 tail + BEACON_TAIL_BUF_SIZE - tailpos); 00404 00405 /* ERP Information element */ 00406 tailpos = hostapd_eid_erp_info(hapd, tailpos); 00407 00408 /* Extended supported rates */ 00409 tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); 00410 00411 tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - 00412 tailpos, NULL); 00413 00414 /* Wi-Fi Alliance WMM */ 00415 tailpos = hostapd_eid_wmm(hapd, tailpos); 00416 00417 #ifdef CONFIG_IEEE80211N 00418 tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); 00419 tailpos = hostapd_eid_ht_operation(hapd, tailpos); 00420 #endif /* CONFIG_IEEE80211N */ 00421 00422 #ifdef CONFIG_WPS 00423 if (hapd->conf->wps_state && hapd->wps_beacon_ie) { 00424 os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), 00425 wpabuf_len(hapd->wps_beacon_ie)); 00426 tailpos += wpabuf_len(hapd->wps_beacon_ie); 00427 } 00428 #endif /* CONFIG_WPS */ 00429 00430 tail_len = tailpos > tail ? tailpos - tail : 0; 00431 00432 if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len, 00433 tail, tail_len, hapd->conf->dtim_period, 00434 hapd->iconf->beacon_int)) 00435 wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " 00436 "period"); 00437 00438 os_free(tail); 00439 os_free(head); 00440 00441 hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & 00442 ERP_INFO_USE_PROTECTION)); 00443 } 00444 00445 00446 void ieee802_11_set_beacons(struct hostapd_iface *iface) 00447 { 00448 size_t i; 00449 for (i = 0; i < iface->num_bss; i++) 00450 ieee802_11_set_beacon(iface->bss[i]); 00451 } 00452 00453 #endif /* CONFIG_NATIVE_WINDOWS */