ieee802_11_common.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/* 2 * IEEE 802.11 Common routines 3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "ieee802_11_defs.h" 19#include "ieee802_11_common.h" 20 21 22static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, 23 struct ieee802_11_elems *elems, 24 int show_errors) 25{ 26 unsigned int oui; 27 28 /* first 3 bytes in vendor specific information element are the IEEE 29 * OUI of the vendor. The following byte is used a vendor specific 30 * sub-type. */ 31 if (elen < 4) { 32 if (show_errors) { 33 wpa_printf(MSG_MSGDUMP, "short vendor specific " 34 "information element ignored (len=%lu)", 35 (unsigned long) elen); 36 } 37 return -1; 38 } 39 40 oui = WPA_GET_BE24(pos); 41 switch (oui) { 42 case OUI_MICROSOFT: 43 /* Microsoft/Wi-Fi information elements are further typed and 44 * subtyped */ 45 switch (pos[3]) { 46 case 1: 47 /* Microsoft OUI (00:50:F2) with OUI Type 1: 48 * real WPA information element */ 49 elems->wpa_ie = pos; 50 elems->wpa_ie_len = elen; 51 break; 52 case WMM_OUI_TYPE: 53 /* WMM information element */ 54 if (elen < 5) { 55 wpa_printf(MSG_MSGDUMP, "short WMM " 56 "information element ignored " 57 "(len=%lu)", 58 (unsigned long) elen); 59 return -1; 60 } 61 switch (pos[4]) { 62 case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: 63 case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: 64 /* 65 * Share same pointer since only one of these 66 * is used and they start with same data. 67 * Length field can be used to distinguish the 68 * IEs. 69 */ 70 elems->wmm = pos; 71 elems->wmm_len = elen; 72 break; 73 case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: 74 elems->wmm_tspec = pos; 75 elems->wmm_tspec_len = elen; 76 break; 77 default: 78 wpa_printf(MSG_EXCESSIVE, "unknown WMM " 79 "information element ignored " 80 "(subtype=%d len=%lu)", 81 pos[4], (unsigned long) elen); 82 return -1; 83 } 84 break; 85 case 4: 86 /* Wi-Fi Protected Setup (WPS) IE */ 87 elems->wps_ie = pos; 88 elems->wps_ie_len = elen; 89 break; 90 default: 91 wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " 92 "information element ignored " 93 "(type=%d len=%lu)", 94 pos[3], (unsigned long) elen); 95 return -1; 96 } 97 break; 98 99 case OUI_WFA: 100 switch (pos[3]) { 101 case P2P_OUI_TYPE: 102 /* Wi-Fi Alliance - P2P IE */ 103 elems->p2p = pos; 104 elems->p2p_len = elen; 105 break; 106 default: 107 wpa_printf(MSG_MSGDUMP, "Unknown WFA " 108 "information element ignored " 109 "(type=%d len=%lu)\n", 110 pos[3], (unsigned long) elen); 111 return -1; 112 } 113 break; 114 115 case OUI_BROADCOM: 116 switch (pos[3]) { 117 case VENDOR_HT_CAPAB_OUI_TYPE: 118 elems->vendor_ht_cap = pos; 119 elems->vendor_ht_cap_len = elen; 120 break; 121 default: 122 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " 123 "information element ignored " 124 "(type=%d len=%lu)", 125 pos[3], (unsigned long) elen); 126 return -1; 127 } 128 break; 129 130 default: 131 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " 132 "information element ignored (vendor OUI " 133 "%02x:%02x:%02x len=%lu)", 134 pos[0], pos[1], pos[2], (unsigned long) elen); 135 return -1; 136 } 137 138 return 0; 139} 140 141 142/** 143 * ieee802_11_parse_elems - Parse information elements in management frames 144 * @start: Pointer to the start of IEs 145 * @len: Length of IE buffer in octets 146 * @elems: Data structure for parsed elements 147 * @show_errors: Whether to show parsing errors in debug log 148 * Returns: Parsing result 149 */ 150ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 151 struct ieee802_11_elems *elems, 152 int show_errors) 153{ 154 size_t left = len; 155 const u8 *pos = start; 156 int unknown = 0; 157 158 os_memset(elems, 0, sizeof(*elems)); 159 160 while (left >= 2) { 161 u8 id, elen; 162 163 id = *pos++; 164 elen = *pos++; 165 left -= 2; 166 167 if (elen > left) { 168 if (show_errors) { 169 wpa_printf(MSG_DEBUG, "IEEE 802.11 element " 170 "parse failed (id=%d elen=%d " 171 "left=%lu)", 172 id, elen, (unsigned long) left); 173 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); 174 } 175 return ParseFailed; 176 } 177 178 switch (id) { 179 case WLAN_EID_SSID: 180 elems->ssid = pos; 181 elems->ssid_len = elen; 182 break; 183 case WLAN_EID_SUPP_RATES: 184 elems->supp_rates = pos; 185 elems->supp_rates_len = elen; 186 break; 187 case WLAN_EID_FH_PARAMS: 188 elems->fh_params = pos; 189 elems->fh_params_len = elen; 190 break; 191 case WLAN_EID_DS_PARAMS: 192 elems->ds_params = pos; 193 elems->ds_params_len = elen; 194 break; 195 case WLAN_EID_CF_PARAMS: 196 elems->cf_params = pos; 197 elems->cf_params_len = elen; 198 break; 199 case WLAN_EID_TIM: 200 elems->tim = pos; 201 elems->tim_len = elen; 202 break; 203 case WLAN_EID_IBSS_PARAMS: 204 elems->ibss_params = pos; 205 elems->ibss_params_len = elen; 206 break; 207 case WLAN_EID_CHALLENGE: 208 elems->challenge = pos; 209 elems->challenge_len = elen; 210 break; 211 case WLAN_EID_ERP_INFO: 212 elems->erp_info = pos; 213 elems->erp_info_len = elen; 214 break; 215 case WLAN_EID_EXT_SUPP_RATES: 216 elems->ext_supp_rates = pos; 217 elems->ext_supp_rates_len = elen; 218 break; 219 case WLAN_EID_VENDOR_SPECIFIC: 220 if (ieee802_11_parse_vendor_specific(pos, elen, 221 elems, 222 show_errors)) 223 unknown++; 224 break; 225 case WLAN_EID_RSN: 226 elems->rsn_ie = pos; 227 elems->rsn_ie_len = elen; 228 break; 229 case WLAN_EID_PWR_CAPABILITY: 230 elems->power_cap = pos; 231 elems->power_cap_len = elen; 232 break; 233 case WLAN_EID_SUPPORTED_CHANNELS: 234 elems->supp_channels = pos; 235 elems->supp_channels_len = elen; 236 break; 237 case WLAN_EID_MOBILITY_DOMAIN: 238 elems->mdie = pos; 239 elems->mdie_len = elen; 240 break; 241 case WLAN_EID_FAST_BSS_TRANSITION: 242 elems->ftie = pos; 243 elems->ftie_len = elen; 244 break; 245 case WLAN_EID_TIMEOUT_INTERVAL: 246 elems->timeout_int = pos; 247 elems->timeout_int_len = elen; 248 break; 249 case WLAN_EID_HT_CAP: 250 elems->ht_capabilities = pos; 251 elems->ht_capabilities_len = elen; 252 break; 253 case WLAN_EID_HT_OPERATION: 254 elems->ht_operation = pos; 255 elems->ht_operation_len = elen; 256 break; 257 case WLAN_EID_LINK_ID: 258 if (elen < 18) 259 break; 260 elems->link_id = pos; 261 break; 262 case WLAN_EID_INTERWORKING: 263 elems->interworking = pos; 264 elems->interworking_len = elen; 265 break; 266 default: 267 unknown++; 268 if (!show_errors) 269 break; 270 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " 271 "ignored unknown element (id=%d elen=%d)", 272 id, elen); 273 break; 274 } 275 276 left -= elen; 277 pos += elen; 278 } 279 280 if (left) 281 return ParseFailed; 282 283 return unknown ? ParseUnknown : ParseOK; 284} 285 286 287int ieee802_11_ie_count(const u8 *ies, size_t ies_len) 288{ 289 int count = 0; 290 const u8 *pos, *end; 291 292 if (ies == NULL) 293 return 0; 294 295 pos = ies; 296 end = ies + ies_len; 297 298 while (pos + 2 <= end) { 299 if (pos + 2 + pos[1] > end) 300 break; 301 count++; 302 pos += 2 + pos[1]; 303 } 304 305 return count; 306} 307 308 309struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 310 u32 oui_type) 311{ 312 struct wpabuf *buf; 313 const u8 *end, *pos, *ie; 314 315 pos = ies; 316 end = ies + ies_len; 317 ie = NULL; 318 319 while (pos + 1 < end) { 320 if (pos + 2 + pos[1] > end) 321 return NULL; 322 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 323 WPA_GET_BE32(&pos[2]) == oui_type) { 324 ie = pos; 325 break; 326 } 327 pos += 2 + pos[1]; 328 } 329 330 if (ie == NULL) 331 return NULL; /* No specified vendor IE found */ 332 333 buf = wpabuf_alloc(ies_len); 334 if (buf == NULL) 335 return NULL; 336 337 /* 338 * There may be multiple vendor IEs in the message, so need to 339 * concatenate their data fields. 340 */ 341 while (pos + 1 < end) { 342 if (pos + 2 + pos[1] > end) 343 break; 344 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && 345 WPA_GET_BE32(&pos[2]) == oui_type) 346 wpabuf_put_data(buf, pos + 6, pos[1] - 4); 347 pos += 2 + pos[1]; 348 } 349 350 return buf; 351} 352 353 354const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) 355{ 356 u16 fc, type, stype; 357 358 /* 359 * PS-Poll frames are 16 bytes. All other frames are 360 * 24 bytes or longer. 361 */ 362 if (len < 16) 363 return NULL; 364 365 fc = le_to_host16(hdr->frame_control); 366 type = WLAN_FC_GET_TYPE(fc); 367 stype = WLAN_FC_GET_STYPE(fc); 368 369 switch (type) { 370 case WLAN_FC_TYPE_DATA: 371 if (len < 24) 372 return NULL; 373 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { 374 case WLAN_FC_FROMDS | WLAN_FC_TODS: 375 case WLAN_FC_TODS: 376 return hdr->addr1; 377 case WLAN_FC_FROMDS: 378 return hdr->addr2; 379 default: 380 return NULL; 381 } 382 case WLAN_FC_TYPE_CTRL: 383 if (stype != WLAN_FC_STYPE_PSPOLL) 384 return NULL; 385 return hdr->addr1; 386 case WLAN_FC_TYPE_MGMT: 387 return hdr->addr3; 388 default: 389 return NULL; 390 } 391} 392