Home | History | Annotate | Download | only in common
      1 /*
      2  * IEEE 802.11 Common routines
      3  * Copyright (c) 2002-2013, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "defs.h"
     13 #include "ieee802_11_defs.h"
     14 #include "ieee802_11_common.h"
     15 
     16 
     17 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
     18 					    struct ieee802_11_elems *elems,
     19 					    int show_errors)
     20 {
     21 	unsigned int oui;
     22 
     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
     25 	 * sub-type. */
     26 	if (elen < 4) {
     27 		if (show_errors) {
     28 			wpa_printf(MSG_MSGDUMP, "short vendor specific "
     29 				   "information element ignored (len=%lu)",
     30 				   (unsigned long) elen);
     31 		}
     32 		return -1;
     33 	}
     34 
     35 	oui = WPA_GET_BE24(pos);
     36 	switch (oui) {
     37 	case OUI_MICROSOFT:
     38 		/* Microsoft/Wi-Fi information elements are further typed and
     39 		 * subtyped */
     40 		switch (pos[3]) {
     41 		case 1:
     42 			/* Microsoft OUI (00:50:F2) with OUI Type 1:
     43 			 * real WPA information element */
     44 			elems->wpa_ie = pos;
     45 			elems->wpa_ie_len = elen;
     46 			break;
     47 		case WMM_OUI_TYPE:
     48 			/* WMM information element */
     49 			if (elen < 5) {
     50 				wpa_printf(MSG_MSGDUMP, "short WMM "
     51 					   "information element ignored "
     52 					   "(len=%lu)",
     53 					   (unsigned long) elen);
     54 				return -1;
     55 			}
     56 			switch (pos[4]) {
     57 			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
     58 			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
     59 				/*
     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
     63 				 * IEs.
     64 				 */
     65 				elems->wmm = pos;
     66 				elems->wmm_len = elen;
     67 				break;
     68 			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
     69 				elems->wmm_tspec = pos;
     70 				elems->wmm_tspec_len = elen;
     71 				break;
     72 			default:
     73 				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
     74 					   "information element ignored "
     75 					   "(subtype=%d len=%lu)",
     76 					   pos[4], (unsigned long) elen);
     77 				return -1;
     78 			}
     79 			break;
     80 		case 4:
     81 			/* Wi-Fi Protected Setup (WPS) IE */
     82 			elems->wps_ie = pos;
     83 			elems->wps_ie_len = elen;
     84 			break;
     85 		default:
     86 			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
     87 				   "information element ignored "
     88 				   "(type=%d len=%lu)",
     89 				   pos[3], (unsigned long) elen);
     90 			return -1;
     91 		}
     92 		break;
     93 
     94 	case OUI_WFA:
     95 		switch (pos[3]) {
     96 		case P2P_OUI_TYPE:
     97 			/* Wi-Fi Alliance - P2P IE */
     98 			elems->p2p = pos;
     99 			elems->p2p_len = elen;
    100 			break;
    101 		case WFD_OUI_TYPE:
    102 			/* Wi-Fi Alliance - WFD IE */
    103 			elems->wfd = pos;
    104 			elems->wfd_len = elen;
    105 			break;
    106 		case HS20_INDICATION_OUI_TYPE:
    107 			/* Hotspot 2.0 */
    108 			elems->hs20 = pos;
    109 			elems->hs20_len = elen;
    110 			break;
    111 		case HS20_OSEN_OUI_TYPE:
    112 			/* Hotspot 2.0 OSEN */
    113 			elems->osen = pos;
    114 			elems->osen_len = elen;
    115 			break;
    116 		default:
    117 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
    118 				   "information element ignored "
    119 				   "(type=%d len=%lu)",
    120 				   pos[3], (unsigned long) elen);
    121 			return -1;
    122 		}
    123 		break;
    124 
    125 	case OUI_BROADCOM:
    126 		switch (pos[3]) {
    127 		case VENDOR_HT_CAPAB_OUI_TYPE:
    128 			elems->vendor_ht_cap = pos;
    129 			elems->vendor_ht_cap_len = elen;
    130 			break;
    131 		default:
    132 			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
    133 				   "information element ignored "
    134 				   "(type=%d len=%lu)",
    135 				   pos[3], (unsigned long) elen);
    136 			return -1;
    137 		}
    138 		break;
    139 
    140 	default:
    141 		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
    142 			   "information element ignored (vendor OUI "
    143 			   "%02x:%02x:%02x len=%lu)",
    144 			   pos[0], pos[1], pos[2], (unsigned long) elen);
    145 		return -1;
    146 	}
    147 
    148 	return 0;
    149 }
    150 
    151 
    152 /**
    153  * ieee802_11_parse_elems - Parse information elements in management frames
    154  * @start: Pointer to the start of IEs
    155  * @len: Length of IE buffer in octets
    156  * @elems: Data structure for parsed elements
    157  * @show_errors: Whether to show parsing errors in debug log
    158  * Returns: Parsing result
    159  */
    160 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
    161 				struct ieee802_11_elems *elems,
    162 				int show_errors)
    163 {
    164 	size_t left = len;
    165 	const u8 *pos = start;
    166 	int unknown = 0;
    167 
    168 	os_memset(elems, 0, sizeof(*elems));
    169 
    170 	while (left >= 2) {
    171 		u8 id, elen;
    172 
    173 		id = *pos++;
    174 		elen = *pos++;
    175 		left -= 2;
    176 
    177 		if (elen > left) {
    178 			if (show_errors) {
    179 				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
    180 					   "parse failed (id=%d elen=%d "
    181 					   "left=%lu)",
    182 					   id, elen, (unsigned long) left);
    183 				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
    184 			}
    185 			return ParseFailed;
    186 		}
    187 
    188 		switch (id) {
    189 		case WLAN_EID_SSID:
    190 			elems->ssid = pos;
    191 			elems->ssid_len = elen;
    192 			break;
    193 		case WLAN_EID_SUPP_RATES:
    194 			elems->supp_rates = pos;
    195 			elems->supp_rates_len = elen;
    196 			break;
    197 		case WLAN_EID_DS_PARAMS:
    198 			elems->ds_params = pos;
    199 			elems->ds_params_len = elen;
    200 			break;
    201 		case WLAN_EID_CF_PARAMS:
    202 		case WLAN_EID_TIM:
    203 			break;
    204 		case WLAN_EID_CHALLENGE:
    205 			elems->challenge = pos;
    206 			elems->challenge_len = elen;
    207 			break;
    208 		case WLAN_EID_ERP_INFO:
    209 			elems->erp_info = pos;
    210 			elems->erp_info_len = elen;
    211 			break;
    212 		case WLAN_EID_EXT_SUPP_RATES:
    213 			elems->ext_supp_rates = pos;
    214 			elems->ext_supp_rates_len = elen;
    215 			break;
    216 		case WLAN_EID_VENDOR_SPECIFIC:
    217 			if (ieee802_11_parse_vendor_specific(pos, elen,
    218 							     elems,
    219 							     show_errors))
    220 				unknown++;
    221 			break;
    222 		case WLAN_EID_RSN:
    223 			elems->rsn_ie = pos;
    224 			elems->rsn_ie_len = elen;
    225 			break;
    226 		case WLAN_EID_PWR_CAPABILITY:
    227 			break;
    228 		case WLAN_EID_SUPPORTED_CHANNELS:
    229 			elems->supp_channels = pos;
    230 			elems->supp_channels_len = elen;
    231 			break;
    232 		case WLAN_EID_MOBILITY_DOMAIN:
    233 			elems->mdie = pos;
    234 			elems->mdie_len = elen;
    235 			break;
    236 		case WLAN_EID_FAST_BSS_TRANSITION:
    237 			elems->ftie = pos;
    238 			elems->ftie_len = elen;
    239 			break;
    240 		case WLAN_EID_TIMEOUT_INTERVAL:
    241 			elems->timeout_int = pos;
    242 			elems->timeout_int_len = elen;
    243 			break;
    244 		case WLAN_EID_HT_CAP:
    245 			elems->ht_capabilities = pos;
    246 			elems->ht_capabilities_len = elen;
    247 			break;
    248 		case WLAN_EID_HT_OPERATION:
    249 			elems->ht_operation = pos;
    250 			elems->ht_operation_len = elen;
    251 			break;
    252 		case WLAN_EID_VHT_CAP:
    253 			elems->vht_capabilities = pos;
    254 			elems->vht_capabilities_len = elen;
    255 			break;
    256 		case WLAN_EID_VHT_OPERATION:
    257 			elems->vht_operation = pos;
    258 			elems->vht_operation_len = elen;
    259 			break;
    260 		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
    261 			if (elen != 1)
    262 				break;
    263 			elems->vht_opmode_notif = pos;
    264 			break;
    265 		case WLAN_EID_LINK_ID:
    266 			if (elen < 18)
    267 				break;
    268 			elems->link_id = pos;
    269 			break;
    270 		case WLAN_EID_INTERWORKING:
    271 			elems->interworking = pos;
    272 			elems->interworking_len = elen;
    273 			break;
    274 		case WLAN_EID_QOS_MAP_SET:
    275 			if (elen < 16)
    276 				break;
    277 			elems->qos_map_set = pos;
    278 			elems->qos_map_set_len = elen;
    279 			break;
    280 		case WLAN_EID_EXT_CAPAB:
    281 			elems->ext_capab = pos;
    282 			elems->ext_capab_len = elen;
    283 			break;
    284 		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
    285 			if (elen < 3)
    286 				break;
    287 			elems->bss_max_idle_period = pos;
    288 			break;
    289 		case WLAN_EID_SSID_LIST:
    290 			elems->ssid_list = pos;
    291 			elems->ssid_list_len = elen;
    292 			break;
    293 		default:
    294 			unknown++;
    295 			if (!show_errors)
    296 				break;
    297 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
    298 				   "ignored unknown element (id=%d elen=%d)",
    299 				   id, elen);
    300 			break;
    301 		}
    302 
    303 		left -= elen;
    304 		pos += elen;
    305 	}
    306 
    307 	if (left)
    308 		return ParseFailed;
    309 
    310 	return unknown ? ParseUnknown : ParseOK;
    311 }
    312 
    313 
    314 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
    315 {
    316 	int count = 0;
    317 	const u8 *pos, *end;
    318 
    319 	if (ies == NULL)
    320 		return 0;
    321 
    322 	pos = ies;
    323 	end = ies + ies_len;
    324 
    325 	while (pos + 2 <= end) {
    326 		if (pos + 2 + pos[1] > end)
    327 			break;
    328 		count++;
    329 		pos += 2 + pos[1];
    330 	}
    331 
    332 	return count;
    333 }
    334 
    335 
    336 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
    337 					    u32 oui_type)
    338 {
    339 	struct wpabuf *buf;
    340 	const u8 *end, *pos, *ie;
    341 
    342 	pos = ies;
    343 	end = ies + ies_len;
    344 	ie = NULL;
    345 
    346 	while (pos + 1 < end) {
    347 		if (pos + 2 + pos[1] > end)
    348 			return NULL;
    349 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    350 		    WPA_GET_BE32(&pos[2]) == oui_type) {
    351 			ie = pos;
    352 			break;
    353 		}
    354 		pos += 2 + pos[1];
    355 	}
    356 
    357 	if (ie == NULL)
    358 		return NULL; /* No specified vendor IE found */
    359 
    360 	buf = wpabuf_alloc(ies_len);
    361 	if (buf == NULL)
    362 		return NULL;
    363 
    364 	/*
    365 	 * There may be multiple vendor IEs in the message, so need to
    366 	 * concatenate their data fields.
    367 	 */
    368 	while (pos + 1 < end) {
    369 		if (pos + 2 + pos[1] > end)
    370 			break;
    371 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
    372 		    WPA_GET_BE32(&pos[2]) == oui_type)
    373 			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
    374 		pos += 2 + pos[1];
    375 	}
    376 
    377 	return buf;
    378 }
    379 
    380 
    381 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
    382 {
    383 	u16 fc, type, stype;
    384 
    385 	/*
    386 	 * PS-Poll frames are 16 bytes. All other frames are
    387 	 * 24 bytes or longer.
    388 	 */
    389 	if (len < 16)
    390 		return NULL;
    391 
    392 	fc = le_to_host16(hdr->frame_control);
    393 	type = WLAN_FC_GET_TYPE(fc);
    394 	stype = WLAN_FC_GET_STYPE(fc);
    395 
    396 	switch (type) {
    397 	case WLAN_FC_TYPE_DATA:
    398 		if (len < 24)
    399 			return NULL;
    400 		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
    401 		case WLAN_FC_FROMDS | WLAN_FC_TODS:
    402 		case WLAN_FC_TODS:
    403 			return hdr->addr1;
    404 		case WLAN_FC_FROMDS:
    405 			return hdr->addr2;
    406 		default:
    407 			return NULL;
    408 		}
    409 	case WLAN_FC_TYPE_CTRL:
    410 		if (stype != WLAN_FC_STYPE_PSPOLL)
    411 			return NULL;
    412 		return hdr->addr1;
    413 	case WLAN_FC_TYPE_MGMT:
    414 		return hdr->addr3;
    415 	default:
    416 		return NULL;
    417 	}
    418 }
    419 
    420 
    421 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
    422 			  const char *name, const char *val)
    423 {
    424 	int num, v;
    425 	const char *pos;
    426 	struct hostapd_wmm_ac_params *ac;
    427 
    428 	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
    429 	pos = name + 7;
    430 	if (os_strncmp(pos, "be_", 3) == 0) {
    431 		num = 0;
    432 		pos += 3;
    433 	} else if (os_strncmp(pos, "bk_", 3) == 0) {
    434 		num = 1;
    435 		pos += 3;
    436 	} else if (os_strncmp(pos, "vi_", 3) == 0) {
    437 		num = 2;
    438 		pos += 3;
    439 	} else if (os_strncmp(pos, "vo_", 3) == 0) {
    440 		num = 3;
    441 		pos += 3;
    442 	} else {
    443 		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
    444 		return -1;
    445 	}
    446 
    447 	ac = &wmm_ac_params[num];
    448 
    449 	if (os_strcmp(pos, "aifs") == 0) {
    450 		v = atoi(val);
    451 		if (v < 1 || v > 255) {
    452 			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
    453 			return -1;
    454 		}
    455 		ac->aifs = v;
    456 	} else if (os_strcmp(pos, "cwmin") == 0) {
    457 		v = atoi(val);
    458 		if (v < 0 || v > 12) {
    459 			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
    460 			return -1;
    461 		}
    462 		ac->cwmin = v;
    463 	} else if (os_strcmp(pos, "cwmax") == 0) {
    464 		v = atoi(val);
    465 		if (v < 0 || v > 12) {
    466 			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
    467 			return -1;
    468 		}
    469 		ac->cwmax = v;
    470 	} else if (os_strcmp(pos, "txop_limit") == 0) {
    471 		v = atoi(val);
    472 		if (v < 0 || v > 0xffff) {
    473 			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
    474 			return -1;
    475 		}
    476 		ac->txop_limit = v;
    477 	} else if (os_strcmp(pos, "acm") == 0) {
    478 		v = atoi(val);
    479 		if (v < 0 || v > 1) {
    480 			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
    481 			return -1;
    482 		}
    483 		ac->admission_control_mandatory = v;
    484 	} else {
    485 		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
    486 		return -1;
    487 	}
    488 
    489 	return 0;
    490 }
    491 
    492 
    493 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
    494 {
    495 	enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
    496 
    497 	if (freq >= 2412 && freq <= 2472) {
    498 		mode = HOSTAPD_MODE_IEEE80211G;
    499 		*channel = (freq - 2407) / 5;
    500 	} else if (freq == 2484) {
    501 		mode = HOSTAPD_MODE_IEEE80211B;
    502 		*channel = 14;
    503 	} else if (freq >= 4900 && freq < 5000) {
    504 		mode = HOSTAPD_MODE_IEEE80211A;
    505 		*channel = (freq - 4000) / 5;
    506 	} else if (freq >= 5000 && freq < 5900) {
    507 		mode = HOSTAPD_MODE_IEEE80211A;
    508 		*channel = (freq - 5000) / 5;
    509 	} else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
    510 		mode = HOSTAPD_MODE_IEEE80211AD;
    511 		*channel = (freq - 56160) / 2160;
    512 	}
    513 
    514 	return mode;
    515 }
    516 
    517 
    518 static int is_11b(u8 rate)
    519 {
    520 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
    521 }
    522 
    523 
    524 int supp_rates_11b_only(struct ieee802_11_elems *elems)
    525 {
    526 	int num_11b = 0, num_others = 0;
    527 	int i;
    528 
    529 	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
    530 		return 0;
    531 
    532 	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
    533 		if (is_11b(elems->supp_rates[i]))
    534 			num_11b++;
    535 		else
    536 			num_others++;
    537 	}
    538 
    539 	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
    540 	     i++) {
    541 		if (is_11b(elems->ext_supp_rates[i]))
    542 			num_11b++;
    543 		else
    544 			num_others++;
    545 	}
    546 
    547 	return num_11b > 0 && num_others == 0;
    548 }
    549 
    550 
    551 const char * fc2str(u16 fc)
    552 {
    553 	u16 stype = WLAN_FC_GET_STYPE(fc);
    554 #define C2S(x) case x: return #x;
    555 
    556 	switch (WLAN_FC_GET_TYPE(fc)) {
    557 	case WLAN_FC_TYPE_MGMT:
    558 		switch (stype) {
    559 		C2S(WLAN_FC_STYPE_ASSOC_REQ)
    560 		C2S(WLAN_FC_STYPE_ASSOC_RESP)
    561 		C2S(WLAN_FC_STYPE_REASSOC_REQ)
    562 		C2S(WLAN_FC_STYPE_REASSOC_RESP)
    563 		C2S(WLAN_FC_STYPE_PROBE_REQ)
    564 		C2S(WLAN_FC_STYPE_PROBE_RESP)
    565 		C2S(WLAN_FC_STYPE_BEACON)
    566 		C2S(WLAN_FC_STYPE_ATIM)
    567 		C2S(WLAN_FC_STYPE_DISASSOC)
    568 		C2S(WLAN_FC_STYPE_AUTH)
    569 		C2S(WLAN_FC_STYPE_DEAUTH)
    570 		C2S(WLAN_FC_STYPE_ACTION)
    571 		}
    572 		break;
    573 	case WLAN_FC_TYPE_CTRL:
    574 		switch (stype) {
    575 		C2S(WLAN_FC_STYPE_PSPOLL)
    576 		C2S(WLAN_FC_STYPE_RTS)
    577 		C2S(WLAN_FC_STYPE_CTS)
    578 		C2S(WLAN_FC_STYPE_ACK)
    579 		C2S(WLAN_FC_STYPE_CFEND)
    580 		C2S(WLAN_FC_STYPE_CFENDACK)
    581 		}
    582 		break;
    583 	case WLAN_FC_TYPE_DATA:
    584 		switch (stype) {
    585 		C2S(WLAN_FC_STYPE_DATA)
    586 		C2S(WLAN_FC_STYPE_DATA_CFACK)
    587 		C2S(WLAN_FC_STYPE_DATA_CFPOLL)
    588 		C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
    589 		C2S(WLAN_FC_STYPE_NULLFUNC)
    590 		C2S(WLAN_FC_STYPE_CFACK)
    591 		C2S(WLAN_FC_STYPE_CFPOLL)
    592 		C2S(WLAN_FC_STYPE_CFACKPOLL)
    593 		C2S(WLAN_FC_STYPE_QOS_DATA)
    594 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
    595 		C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
    596 		C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
    597 		C2S(WLAN_FC_STYPE_QOS_NULL)
    598 		C2S(WLAN_FC_STYPE_QOS_CFPOLL)
    599 		C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
    600 		}
    601 		break;
    602 	}
    603 	return "WLAN_FC_TYPE_UNKNOWN";
    604 #undef C2S
    605 }
    606