ieee802_11_common.c 12 KB

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