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_FH_PARAMS:
193 elems->fh_params = pos;
194 elems->fh_params_len = elen;
196 case WLAN_EID_DS_PARAMS:
197 elems->ds_params = pos;
198 elems->ds_params_len = elen;
200 case WLAN_EID_CF_PARAMS:
201 elems->cf_params = pos;
202 elems->cf_params_len = elen;
206 elems->tim_len = elen;
208 case WLAN_EID_IBSS_PARAMS:
209 elems->ibss_params = pos;
210 elems->ibss_params_len = elen;
212 case WLAN_EID_CHALLENGE:
213 elems->challenge = pos;
214 elems->challenge_len = elen;
216 case WLAN_EID_ERP_INFO:
217 elems->erp_info = pos;
218 elems->erp_info_len = elen;
220 case WLAN_EID_EXT_SUPP_RATES:
221 elems->ext_supp_rates = pos;
222 elems->ext_supp_rates_len = elen;
224 case WLAN_EID_VENDOR_SPECIFIC:
225 if (ieee802_11_parse_vendor_specific(pos, elen,
232 elems->rsn_ie_len = elen;
234 case WLAN_EID_PWR_CAPABILITY:
235 elems->power_cap = pos;
236 elems->power_cap_len = elen;
238 case WLAN_EID_SUPPORTED_CHANNELS:
239 elems->supp_channels = pos;
240 elems->supp_channels_len = elen;
242 case WLAN_EID_MOBILITY_DOMAIN:
244 elems->mdie_len = elen;
246 case WLAN_EID_FAST_BSS_TRANSITION:
248 elems->ftie_len = elen;
250 case WLAN_EID_TIMEOUT_INTERVAL:
251 elems->timeout_int = pos;
252 elems->timeout_int_len = elen;
254 case WLAN_EID_HT_CAP:
255 elems->ht_capabilities = pos;
256 elems->ht_capabilities_len = elen;
258 case WLAN_EID_HT_OPERATION:
259 elems->ht_operation = pos;
260 elems->ht_operation_len = elen;
262 case WLAN_EID_VHT_CAP:
263 elems->vht_capabilities = pos;
264 elems->vht_capabilities_len = elen;
266 case WLAN_EID_VHT_OPERATION:
267 elems->vht_operation = pos;
268 elems->vht_operation_len = elen;
270 case WLAN_EID_LINK_ID:
273 elems->link_id = pos;
275 case WLAN_EID_INTERWORKING:
276 elems->interworking = pos;
277 elems->interworking_len = elen;
279 case WLAN_EID_EXT_CAPAB:
280 elems->ext_capab = pos;
281 elems->ext_capab_len = elen;
283 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
286 elems->bss_max_idle_period = pos;
288 case WLAN_EID_SSID_LIST:
289 elems->ssid_list = pos;
290 elems->ssid_list_len = elen;
296 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
297 "ignored unknown element (id=%d elen=%d)",
309 return unknown ? ParseUnknown : ParseOK;
313 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
324 while (pos + 2 <= end) {
325 if (pos + 2 + pos[1] > end)
335 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
339 const u8 *end, *pos, *ie;
345 while (pos + 1 < end) {
346 if (pos + 2 + pos[1] > end)
348 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
349 WPA_GET_BE32(&pos[2]) == oui_type) {
357 return NULL; /* No specified vendor IE found */
359 buf = wpabuf_alloc(ies_len);
364 * There may be multiple vendor IEs in the message, so need to
365 * concatenate their data fields.
367 while (pos + 1 < end) {
368 if (pos + 2 + pos[1] > end)
370 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
371 WPA_GET_BE32(&pos[2]) == oui_type)
372 wpabuf_put_data(buf, pos + 6, pos[1] - 4);
380 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
385 * PS-Poll frames are 16 bytes. All other frames are
386 * 24 bytes or longer.
391 fc = le_to_host16(hdr->frame_control);
392 type = WLAN_FC_GET_TYPE(fc);
393 stype = WLAN_FC_GET_STYPE(fc);
396 case WLAN_FC_TYPE_DATA:
399 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
400 case WLAN_FC_FROMDS | WLAN_FC_TODS:
408 case WLAN_FC_TYPE_CTRL:
409 if (stype != WLAN_FC_STYPE_PSPOLL)
412 case WLAN_FC_TYPE_MGMT:
420 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
421 const char *name, const char *val)
425 struct hostapd_wmm_ac_params *ac;
427 /* skip 'wme_ac_' or 'wmm_ac_' prefix */
429 if (os_strncmp(pos, "be_", 3) == 0) {
432 } else if (os_strncmp(pos, "bk_", 3) == 0) {
435 } else if (os_strncmp(pos, "vi_", 3) == 0) {
438 } else if (os_strncmp(pos, "vo_", 3) == 0) {
442 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
446 ac = &wmm_ac_params[num];
448 if (os_strcmp(pos, "aifs") == 0) {
450 if (v < 1 || v > 255) {
451 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
455 } else if (os_strcmp(pos, "cwmin") == 0) {
457 if (v < 0 || v > 12) {
458 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
462 } else if (os_strcmp(pos, "cwmax") == 0) {
464 if (v < 0 || v > 12) {
465 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
469 } else if (os_strcmp(pos, "txop_limit") == 0) {
471 if (v < 0 || v > 0xffff) {
472 wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
476 } else if (os_strcmp(pos, "acm") == 0) {
478 if (v < 0 || v > 1) {
479 wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
482 ac->admission_control_mandatory = v;
484 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
492 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
494 enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
496 if (freq >= 2412 && freq <= 2472) {
497 mode = HOSTAPD_MODE_IEEE80211G;
498 *channel = (freq - 2407) / 5;
499 } else if (freq == 2484) {
500 mode = HOSTAPD_MODE_IEEE80211B;
502 } else if (freq >= 4900 && freq < 5000) {
503 mode = HOSTAPD_MODE_IEEE80211A;
504 *channel = (freq - 4000) / 5;
505 } else if (freq >= 5000 && freq < 5900) {
506 mode = HOSTAPD_MODE_IEEE80211A;
507 *channel = (freq - 5000) / 5;
508 } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
509 mode = HOSTAPD_MODE_IEEE80211AD;
510 *channel = (freq - 56160) / 2160;