2 * IEEE 802.11 Common routines
3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "ieee802_11_defs.h"
14 #include "ieee802_11_common.h"
17 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
18 struct ieee802_11_elems *elems,
23 /* first 3 bytes in vendor specific information element are the IEEE
24 * OUI of the vendor. The following byte is used a vendor specific
28 wpa_printf(MSG_MSGDUMP, "short vendor specific "
29 "information element ignored (len=%lu)",
30 (unsigned long) elen);
35 oui = WPA_GET_BE24(pos);
38 /* Microsoft/Wi-Fi information elements are further typed and
42 /* Microsoft OUI (00:50:F2) with OUI Type 1:
43 * real WPA information element */
45 elems->wpa_ie_len = elen;
48 /* WMM information element */
50 wpa_printf(MSG_MSGDUMP, "short WMM "
51 "information element ignored "
53 (unsigned long) elen);
57 case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
58 case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
60 * Share same pointer since only one of these
61 * is used and they start with same data.
62 * Length field can be used to distinguish the
66 elems->wmm_len = elen;
68 case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
69 elems->wmm_tspec = pos;
70 elems->wmm_tspec_len = elen;
73 wpa_printf(MSG_EXCESSIVE, "unknown WMM "
74 "information element ignored "
75 "(subtype=%d len=%lu)",
76 pos[4], (unsigned long) elen);
81 /* Wi-Fi Protected Setup (WPS) IE */
83 elems->wps_ie_len = elen;
86 wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
87 "information element ignored "
89 pos[3], (unsigned long) elen);
97 /* Wi-Fi Alliance - P2P IE */
99 elems->p2p_len = elen;
102 /* Wi-Fi Alliance - WFD IE */
104 elems->wfd_len = elen;
106 case HS20_INDICATION_OUI_TYPE:
109 elems->hs20_len = elen;
112 wpa_printf(MSG_MSGDUMP, "Unknown WFA "
113 "information element ignored "
114 "(type=%d len=%lu)\n",
115 pos[3], (unsigned long) elen);
122 case VENDOR_HT_CAPAB_OUI_TYPE:
123 elems->vendor_ht_cap = pos;
124 elems->vendor_ht_cap_len = elen;
127 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
128 "information element ignored "
130 pos[3], (unsigned long) elen);
136 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
137 "information element ignored (vendor OUI "
138 "%02x:%02x:%02x len=%lu)",
139 pos[0], pos[1], pos[2], (unsigned long) elen);
148 * ieee802_11_parse_elems - Parse information elements in management frames
149 * @start: Pointer to the start of IEs
150 * @len: Length of IE buffer in octets
151 * @elems: Data structure for parsed elements
152 * @show_errors: Whether to show parsing errors in debug log
153 * Returns: Parsing result
155 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
156 struct ieee802_11_elems *elems,
160 const u8 *pos = start;
163 os_memset(elems, 0, sizeof(*elems));
174 wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
175 "parse failed (id=%d elen=%d "
177 id, elen, (unsigned long) left);
178 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
186 elems->ssid_len = elen;
188 case WLAN_EID_SUPP_RATES:
189 elems->supp_rates = pos;
190 elems->supp_rates_len = elen;
192 case WLAN_EID_DS_PARAMS:
193 elems->ds_params = pos;
194 elems->ds_params_len = elen;
196 case WLAN_EID_CF_PARAMS:
199 case WLAN_EID_CHALLENGE:
200 elems->challenge = pos;
201 elems->challenge_len = elen;
203 case WLAN_EID_ERP_INFO:
204 elems->erp_info = pos;
205 elems->erp_info_len = elen;
207 case WLAN_EID_EXT_SUPP_RATES:
208 elems->ext_supp_rates = pos;
209 elems->ext_supp_rates_len = elen;
211 case WLAN_EID_VENDOR_SPECIFIC:
212 if (ieee802_11_parse_vendor_specific(pos, elen,
219 elems->rsn_ie_len = elen;
221 case WLAN_EID_PWR_CAPABILITY:
223 case WLAN_EID_SUPPORTED_CHANNELS:
224 elems->supp_channels = pos;
225 elems->supp_channels_len = elen;
227 case WLAN_EID_MOBILITY_DOMAIN:
229 elems->mdie_len = elen;
231 case WLAN_EID_FAST_BSS_TRANSITION:
233 elems->ftie_len = elen;
235 case WLAN_EID_TIMEOUT_INTERVAL:
236 elems->timeout_int = pos;
237 elems->timeout_int_len = elen;
239 case WLAN_EID_HT_CAP:
240 elems->ht_capabilities = pos;
241 elems->ht_capabilities_len = elen;
243 case WLAN_EID_HT_OPERATION:
244 elems->ht_operation = pos;
245 elems->ht_operation_len = elen;
247 case WLAN_EID_VHT_CAP:
248 elems->vht_capabilities = pos;
249 elems->vht_capabilities_len = elen;
251 case WLAN_EID_VHT_OPERATION:
252 elems->vht_operation = pos;
253 elems->vht_operation_len = elen;
255 case WLAN_EID_LINK_ID:
258 elems->link_id = pos;
260 case WLAN_EID_INTERWORKING:
261 elems->interworking = pos;
262 elems->interworking_len = elen;
264 case WLAN_EID_QOS_MAP_SET:
267 elems->qos_map_set = pos;
268 elems->qos_map_set_len = elen;
270 case WLAN_EID_EXT_CAPAB:
271 elems->ext_capab = pos;
272 elems->ext_capab_len = elen;
274 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
277 elems->bss_max_idle_period = pos;
279 case WLAN_EID_SSID_LIST:
280 elems->ssid_list = pos;
281 elems->ssid_list_len = elen;
287 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
288 "ignored unknown element (id=%d elen=%d)",
300 return unknown ? ParseUnknown : ParseOK;
304 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
315 while (pos + 2 <= end) {
316 if (pos + 2 + pos[1] > end)
326 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
330 const u8 *end, *pos, *ie;
336 while (pos + 1 < end) {
337 if (pos + 2 + pos[1] > end)
339 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
340 WPA_GET_BE32(&pos[2]) == oui_type) {
348 return NULL; /* No specified vendor IE found */
350 buf = wpabuf_alloc(ies_len);
355 * There may be multiple vendor IEs in the message, so need to
356 * concatenate their data fields.
358 while (pos + 1 < end) {
359 if (pos + 2 + pos[1] > end)
361 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
362 WPA_GET_BE32(&pos[2]) == oui_type)
363 wpabuf_put_data(buf, pos + 6, pos[1] - 4);
371 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
376 * PS-Poll frames are 16 bytes. All other frames are
377 * 24 bytes or longer.
382 fc = le_to_host16(hdr->frame_control);
383 type = WLAN_FC_GET_TYPE(fc);
384 stype = WLAN_FC_GET_STYPE(fc);
387 case WLAN_FC_TYPE_DATA:
390 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
391 case WLAN_FC_FROMDS | WLAN_FC_TODS:
399 case WLAN_FC_TYPE_CTRL:
400 if (stype != WLAN_FC_STYPE_PSPOLL)
403 case WLAN_FC_TYPE_MGMT:
411 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
412 const char *name, const char *val)
416 struct hostapd_wmm_ac_params *ac;
418 /* skip 'wme_ac_' or 'wmm_ac_' prefix */
420 if (os_strncmp(pos, "be_", 3) == 0) {
423 } else if (os_strncmp(pos, "bk_", 3) == 0) {
426 } else if (os_strncmp(pos, "vi_", 3) == 0) {
429 } else if (os_strncmp(pos, "vo_", 3) == 0) {
433 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
437 ac = &wmm_ac_params[num];
439 if (os_strcmp(pos, "aifs") == 0) {
441 if (v < 1 || v > 255) {
442 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
446 } else if (os_strcmp(pos, "cwmin") == 0) {
448 if (v < 0 || v > 12) {
449 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
453 } else if (os_strcmp(pos, "cwmax") == 0) {
455 if (v < 0 || v > 12) {
456 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
460 } else if (os_strcmp(pos, "txop_limit") == 0) {
462 if (v < 0 || v > 0xffff) {
463 wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
467 } else if (os_strcmp(pos, "acm") == 0) {
469 if (v < 0 || v > 1) {
470 wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
473 ac->admission_control_mandatory = v;
475 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
483 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
485 enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
487 if (freq >= 2412 && freq <= 2472) {
488 mode = HOSTAPD_MODE_IEEE80211G;
489 *channel = (freq - 2407) / 5;
490 } else if (freq == 2484) {
491 mode = HOSTAPD_MODE_IEEE80211B;
493 } else if (freq >= 4900 && freq < 5000) {
494 mode = HOSTAPD_MODE_IEEE80211A;
495 *channel = (freq - 4000) / 5;
496 } else if (freq >= 5000 && freq < 5900) {
497 mode = HOSTAPD_MODE_IEEE80211A;
498 *channel = (freq - 5000) / 5;
499 } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
500 mode = HOSTAPD_MODE_IEEE80211AD;
501 *channel = (freq - 56160) / 2160;
508 static int is_11b(u8 rate)
510 return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
514 int supp_rates_11b_only(struct ieee802_11_elems *elems)
516 int num_11b = 0, num_others = 0;
519 if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
522 for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
523 if (is_11b(elems->supp_rates[i]))
529 for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
531 if (is_11b(elems->ext_supp_rates[i]))
537 return num_11b > 0 && num_others == 0;