ieee802_11_common.c 8.3 KB

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