beacon.c
Go to the documentation of this file.
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 */


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:33