bss.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. /*
  2. * BSS table
  3. * Copyright (c) 2009-2012, 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 "utils/includes.h"
  9. #include "utils/common.h"
  10. #include "utils/eloop.h"
  11. #include "common/ieee802_11_defs.h"
  12. #include "drivers/driver.h"
  13. #include "wpa_supplicant_i.h"
  14. #include "config.h"
  15. #include "notify.h"
  16. #include "scan.h"
  17. #include "bss.h"
  18. /**
  19. * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
  20. */
  21. #define WPA_BSS_EXPIRATION_PERIOD 10
  22. #define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
  23. #define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
  24. #define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
  25. #define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
  26. #define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
  27. #define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
  28. #define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
  29. #define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
  30. #define WPA_BSS_IES_CHANGED_FLAG BIT(8)
  31. static void wpa_bss_set_hessid(struct wpa_bss *bss)
  32. {
  33. #ifdef CONFIG_INTERWORKING
  34. const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
  35. if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
  36. os_memset(bss->hessid, 0, ETH_ALEN);
  37. return;
  38. }
  39. if (ie[1] == 7)
  40. os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
  41. else
  42. os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
  43. #endif /* CONFIG_INTERWORKING */
  44. }
  45. /**
  46. * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
  47. * Returns: Allocated ANQP data structure or %NULL on failure
  48. *
  49. * The allocated ANQP data structure has its users count set to 1. It may be
  50. * shared by multiple BSS entries and each shared entry is freed with
  51. * wpa_bss_anqp_free().
  52. */
  53. struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
  54. {
  55. struct wpa_bss_anqp *anqp;
  56. anqp = os_zalloc(sizeof(*anqp));
  57. if (anqp == NULL)
  58. return NULL;
  59. anqp->users = 1;
  60. return anqp;
  61. }
  62. /**
  63. * wpa_bss_anqp_clone - Clone an ANQP data structure
  64. * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
  65. * Returns: Cloned ANQP data structure or %NULL on failure
  66. */
  67. static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
  68. {
  69. struct wpa_bss_anqp *n;
  70. n = os_zalloc(sizeof(*n));
  71. if (n == NULL)
  72. return NULL;
  73. #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
  74. #ifdef CONFIG_INTERWORKING
  75. ANQP_DUP(venue_name);
  76. ANQP_DUP(network_auth_type);
  77. ANQP_DUP(roaming_consortium);
  78. ANQP_DUP(ip_addr_type_availability);
  79. ANQP_DUP(nai_realm);
  80. ANQP_DUP(anqp_3gpp);
  81. ANQP_DUP(domain_name);
  82. #endif /* CONFIG_INTERWORKING */
  83. #ifdef CONFIG_HS20
  84. ANQP_DUP(hs20_capability_list);
  85. ANQP_DUP(hs20_operator_friendly_name);
  86. ANQP_DUP(hs20_wan_metrics);
  87. ANQP_DUP(hs20_connection_capability);
  88. ANQP_DUP(hs20_operating_class);
  89. ANQP_DUP(hs20_osu_providers_list);
  90. #endif /* CONFIG_HS20 */
  91. #undef ANQP_DUP
  92. return n;
  93. }
  94. /**
  95. * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
  96. * @bss: BSS entry
  97. * Returns: 0 on success, -1 on failure
  98. *
  99. * This function ensures the specific BSS entry has an ANQP data structure that
  100. * is not shared with any other BSS entry.
  101. */
  102. int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
  103. {
  104. struct wpa_bss_anqp *anqp;
  105. if (bss->anqp && bss->anqp->users > 1) {
  106. /* allocated, but shared - clone an unshared copy */
  107. anqp = wpa_bss_anqp_clone(bss->anqp);
  108. if (anqp == NULL)
  109. return -1;
  110. anqp->users = 1;
  111. bss->anqp->users--;
  112. bss->anqp = anqp;
  113. return 0;
  114. }
  115. if (bss->anqp)
  116. return 0; /* already allocated and not shared */
  117. /* not allocated - allocate a new storage area */
  118. bss->anqp = wpa_bss_anqp_alloc();
  119. return bss->anqp ? 0 : -1;
  120. }
  121. /**
  122. * wpa_bss_anqp_free - Free an ANQP data structure
  123. * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
  124. */
  125. static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
  126. {
  127. if (anqp == NULL)
  128. return;
  129. anqp->users--;
  130. if (anqp->users > 0) {
  131. /* Another BSS entry holds a pointer to this ANQP info */
  132. return;
  133. }
  134. #ifdef CONFIG_INTERWORKING
  135. wpabuf_free(anqp->venue_name);
  136. wpabuf_free(anqp->network_auth_type);
  137. wpabuf_free(anqp->roaming_consortium);
  138. wpabuf_free(anqp->ip_addr_type_availability);
  139. wpabuf_free(anqp->nai_realm);
  140. wpabuf_free(anqp->anqp_3gpp);
  141. wpabuf_free(anqp->domain_name);
  142. #endif /* CONFIG_INTERWORKING */
  143. #ifdef CONFIG_HS20
  144. wpabuf_free(anqp->hs20_capability_list);
  145. wpabuf_free(anqp->hs20_operator_friendly_name);
  146. wpabuf_free(anqp->hs20_wan_metrics);
  147. wpabuf_free(anqp->hs20_connection_capability);
  148. wpabuf_free(anqp->hs20_operating_class);
  149. wpabuf_free(anqp->hs20_osu_providers_list);
  150. #endif /* CONFIG_HS20 */
  151. os_free(anqp);
  152. }
  153. static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
  154. struct wpa_bss *old_bss,
  155. struct wpa_bss *new_bss)
  156. {
  157. struct wpa_radio_work *work;
  158. struct wpa_connect_work *cwork;
  159. work = radio_work_pending(wpa_s, "sme-connect");
  160. if (!work)
  161. work = radio_work_pending(wpa_s, "connect");
  162. if (!work)
  163. return;
  164. cwork = work->ctx;
  165. if (cwork->bss != old_bss)
  166. return;
  167. wpa_printf(MSG_DEBUG,
  168. "Update BSS pointer for the pending connect radio work");
  169. cwork->bss = new_bss;
  170. if (!new_bss)
  171. cwork->bss_removed = 1;
  172. }
  173. static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
  174. const char *reason)
  175. {
  176. if (wpa_s->last_scan_res) {
  177. unsigned int i;
  178. for (i = 0; i < wpa_s->last_scan_res_used; i++) {
  179. if (wpa_s->last_scan_res[i] == bss) {
  180. os_memmove(&wpa_s->last_scan_res[i],
  181. &wpa_s->last_scan_res[i + 1],
  182. (wpa_s->last_scan_res_used - i - 1)
  183. * sizeof(struct wpa_bss *));
  184. wpa_s->last_scan_res_used--;
  185. break;
  186. }
  187. }
  188. }
  189. wpa_bss_update_pending_connect(wpa_s, bss, NULL);
  190. dl_list_del(&bss->list);
  191. dl_list_del(&bss->list_id);
  192. wpa_s->num_bss--;
  193. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
  194. " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
  195. wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
  196. wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
  197. wpa_bss_anqp_free(bss->anqp);
  198. os_free(bss);
  199. }
  200. /**
  201. * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
  202. * @wpa_s: Pointer to wpa_supplicant data
  203. * @bssid: BSSID
  204. * @ssid: SSID
  205. * @ssid_len: Length of @ssid
  206. * Returns: Pointer to the BSS entry or %NULL if not found
  207. */
  208. struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
  209. const u8 *ssid, size_t ssid_len)
  210. {
  211. struct wpa_bss *bss;
  212. if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
  213. return NULL;
  214. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  215. if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
  216. bss->ssid_len == ssid_len &&
  217. os_memcmp(bss->ssid, ssid, ssid_len) == 0)
  218. return bss;
  219. }
  220. return NULL;
  221. }
  222. static void calculate_update_time(const struct os_reltime *fetch_time,
  223. unsigned int age_ms,
  224. struct os_reltime *update_time)
  225. {
  226. os_time_t usec;
  227. update_time->sec = fetch_time->sec;
  228. update_time->usec = fetch_time->usec;
  229. update_time->sec -= age_ms / 1000;
  230. usec = (age_ms % 1000) * 1000;
  231. if (update_time->usec < usec) {
  232. update_time->sec--;
  233. update_time->usec += 1000000;
  234. }
  235. update_time->usec -= usec;
  236. }
  237. static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
  238. struct os_reltime *fetch_time)
  239. {
  240. dst->flags = src->flags;
  241. os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
  242. dst->freq = src->freq;
  243. dst->beacon_int = src->beacon_int;
  244. dst->caps = src->caps;
  245. dst->qual = src->qual;
  246. dst->noise = src->noise;
  247. dst->level = src->level;
  248. dst->tsf = src->tsf;
  249. calculate_update_time(fetch_time, src->age, &dst->last_update);
  250. }
  251. static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  252. {
  253. struct wpa_ssid *ssid;
  254. for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
  255. if (ssid->ssid == NULL || ssid->ssid_len == 0)
  256. continue;
  257. if (ssid->ssid_len == bss->ssid_len &&
  258. os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
  259. return 1;
  260. }
  261. return 0;
  262. }
  263. static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
  264. {
  265. return bss == wpa_s->current_bss ||
  266. (!is_zero_ether_addr(bss->bssid) &&
  267. (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
  268. os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0));
  269. }
  270. static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
  271. {
  272. struct wpa_bss *bss;
  273. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  274. if (!wpa_bss_known(wpa_s, bss)) {
  275. wpa_bss_remove(wpa_s, bss, __func__);
  276. return 0;
  277. }
  278. }
  279. return -1;
  280. }
  281. static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
  282. {
  283. struct wpa_bss *bss;
  284. /*
  285. * Remove the oldest entry that does not match with any configured
  286. * network.
  287. */
  288. if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
  289. return 0;
  290. /*
  291. * Remove the oldest entry that isn't currently in use.
  292. */
  293. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  294. if (!wpa_bss_in_use(wpa_s, bss)) {
  295. wpa_bss_remove(wpa_s, bss, __func__);
  296. return 0;
  297. }
  298. }
  299. return -1;
  300. }
  301. static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
  302. const u8 *ssid, size_t ssid_len,
  303. struct wpa_scan_res *res,
  304. struct os_reltime *fetch_time)
  305. {
  306. struct wpa_bss *bss;
  307. bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
  308. if (bss == NULL)
  309. return NULL;
  310. bss->id = wpa_s->bss_next_id++;
  311. bss->last_update_idx = wpa_s->bss_update_idx;
  312. wpa_bss_copy_res(bss, res, fetch_time);
  313. os_memcpy(bss->ssid, ssid, ssid_len);
  314. bss->ssid_len = ssid_len;
  315. bss->ie_len = res->ie_len;
  316. bss->beacon_ie_len = res->beacon_ie_len;
  317. os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
  318. wpa_bss_set_hessid(bss);
  319. if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
  320. wpa_bss_remove_oldest(wpa_s) != 0) {
  321. wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
  322. "because all BSSes are in use. We should normally "
  323. "not get here!", (int) wpa_s->num_bss + 1);
  324. wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
  325. }
  326. dl_list_add_tail(&wpa_s->bss, &bss->list);
  327. dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
  328. wpa_s->num_bss++;
  329. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
  330. " SSID '%s'",
  331. bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
  332. wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
  333. return bss;
  334. }
  335. static int are_ies_equal(const struct wpa_bss *old,
  336. const struct wpa_scan_res *new, u32 ie)
  337. {
  338. const u8 *old_ie, *new_ie;
  339. struct wpabuf *old_ie_buff = NULL;
  340. struct wpabuf *new_ie_buff = NULL;
  341. int new_ie_len, old_ie_len, ret, is_multi;
  342. switch (ie) {
  343. case WPA_IE_VENDOR_TYPE:
  344. old_ie = wpa_bss_get_vendor_ie(old, ie);
  345. new_ie = wpa_scan_get_vendor_ie(new, ie);
  346. is_multi = 0;
  347. break;
  348. case WPS_IE_VENDOR_TYPE:
  349. old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
  350. new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
  351. is_multi = 1;
  352. break;
  353. case WLAN_EID_RSN:
  354. case WLAN_EID_SUPP_RATES:
  355. case WLAN_EID_EXT_SUPP_RATES:
  356. old_ie = wpa_bss_get_ie(old, ie);
  357. new_ie = wpa_scan_get_ie(new, ie);
  358. is_multi = 0;
  359. break;
  360. default:
  361. wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
  362. return 0;
  363. }
  364. if (is_multi) {
  365. /* in case of multiple IEs stored in buffer */
  366. old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
  367. new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
  368. old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
  369. new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
  370. } else {
  371. /* in case of single IE */
  372. old_ie_len = old_ie ? old_ie[1] + 2 : 0;
  373. new_ie_len = new_ie ? new_ie[1] + 2 : 0;
  374. }
  375. if (!old_ie || !new_ie)
  376. ret = !old_ie && !new_ie;
  377. else
  378. ret = (old_ie_len == new_ie_len &&
  379. os_memcmp(old_ie, new_ie, old_ie_len) == 0);
  380. wpabuf_free(old_ie_buff);
  381. wpabuf_free(new_ie_buff);
  382. return ret;
  383. }
  384. static u32 wpa_bss_compare_res(const struct wpa_bss *old,
  385. const struct wpa_scan_res *new)
  386. {
  387. u32 changes = 0;
  388. int caps_diff = old->caps ^ new->caps;
  389. if (old->freq != new->freq)
  390. changes |= WPA_BSS_FREQ_CHANGED_FLAG;
  391. if (old->level != new->level)
  392. changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
  393. if (caps_diff & IEEE80211_CAP_PRIVACY)
  394. changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
  395. if (caps_diff & IEEE80211_CAP_IBSS)
  396. changes |= WPA_BSS_MODE_CHANGED_FLAG;
  397. if (old->ie_len == new->ie_len &&
  398. os_memcmp(old + 1, new + 1, old->ie_len) == 0)
  399. return changes;
  400. changes |= WPA_BSS_IES_CHANGED_FLAG;
  401. if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
  402. changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
  403. if (!are_ies_equal(old, new, WLAN_EID_RSN))
  404. changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
  405. if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
  406. changes |= WPA_BSS_WPS_CHANGED_FLAG;
  407. if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
  408. !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
  409. changes |= WPA_BSS_RATES_CHANGED_FLAG;
  410. return changes;
  411. }
  412. static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
  413. const struct wpa_bss *bss)
  414. {
  415. if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
  416. wpas_notify_bss_freq_changed(wpa_s, bss->id);
  417. if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
  418. wpas_notify_bss_signal_changed(wpa_s, bss->id);
  419. if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
  420. wpas_notify_bss_privacy_changed(wpa_s, bss->id);
  421. if (changes & WPA_BSS_MODE_CHANGED_FLAG)
  422. wpas_notify_bss_mode_changed(wpa_s, bss->id);
  423. if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
  424. wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
  425. if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
  426. wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
  427. if (changes & WPA_BSS_WPS_CHANGED_FLAG)
  428. wpas_notify_bss_wps_changed(wpa_s, bss->id);
  429. if (changes & WPA_BSS_IES_CHANGED_FLAG)
  430. wpas_notify_bss_ies_changed(wpa_s, bss->id);
  431. if (changes & WPA_BSS_RATES_CHANGED_FLAG)
  432. wpas_notify_bss_rates_changed(wpa_s, bss->id);
  433. wpas_notify_bss_seen(wpa_s, bss->id);
  434. }
  435. static struct wpa_bss *
  436. wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
  437. struct wpa_scan_res *res, struct os_reltime *fetch_time)
  438. {
  439. u32 changes;
  440. changes = wpa_bss_compare_res(bss, res);
  441. bss->scan_miss_count = 0;
  442. bss->last_update_idx = wpa_s->bss_update_idx;
  443. wpa_bss_copy_res(bss, res, fetch_time);
  444. /* Move the entry to the end of the list */
  445. dl_list_del(&bss->list);
  446. #ifdef CONFIG_P2P
  447. if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
  448. !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) {
  449. /*
  450. * This can happen when non-P2P station interface runs a scan
  451. * without P2P IE in the Probe Request frame. P2P GO would reply
  452. * to that with a Probe Response that does not include P2P IE.
  453. * Do not update the IEs in this BSS entry to avoid such loss of
  454. * information that may be needed for P2P operations to
  455. * determine group information.
  456. */
  457. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
  458. MACSTR " since that would remove P2P IE information",
  459. MAC2STR(bss->bssid));
  460. } else
  461. #endif /* CONFIG_P2P */
  462. if (bss->ie_len + bss->beacon_ie_len >=
  463. res->ie_len + res->beacon_ie_len) {
  464. os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
  465. bss->ie_len = res->ie_len;
  466. bss->beacon_ie_len = res->beacon_ie_len;
  467. } else {
  468. struct wpa_bss *nbss;
  469. struct dl_list *prev = bss->list_id.prev;
  470. dl_list_del(&bss->list_id);
  471. nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
  472. res->beacon_ie_len);
  473. if (nbss) {
  474. unsigned int i;
  475. for (i = 0; i < wpa_s->last_scan_res_used; i++) {
  476. if (wpa_s->last_scan_res[i] == bss) {
  477. wpa_s->last_scan_res[i] = nbss;
  478. break;
  479. }
  480. }
  481. if (wpa_s->current_bss == bss)
  482. wpa_s->current_bss = nbss;
  483. wpa_bss_update_pending_connect(wpa_s, bss, nbss);
  484. bss = nbss;
  485. os_memcpy(bss + 1, res + 1,
  486. res->ie_len + res->beacon_ie_len);
  487. bss->ie_len = res->ie_len;
  488. bss->beacon_ie_len = res->beacon_ie_len;
  489. }
  490. dl_list_add(prev, &bss->list_id);
  491. }
  492. if (changes & WPA_BSS_IES_CHANGED_FLAG)
  493. wpa_bss_set_hessid(bss);
  494. dl_list_add_tail(&wpa_s->bss, &bss->list);
  495. notify_bss_changes(wpa_s, changes, bss);
  496. return bss;
  497. }
  498. /**
  499. * wpa_bss_update_start - Start a BSS table update from scan results
  500. * @wpa_s: Pointer to wpa_supplicant data
  501. *
  502. * This function is called at the start of each BSS table update round for new
  503. * scan results. The actual scan result entries are indicated with calls to
  504. * wpa_bss_update_scan_res() and the update round is finished with a call to
  505. * wpa_bss_update_end().
  506. */
  507. void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
  508. {
  509. wpa_s->bss_update_idx++;
  510. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
  511. wpa_s->bss_update_idx);
  512. wpa_s->last_scan_res_used = 0;
  513. }
  514. /**
  515. * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
  516. * @wpa_s: Pointer to wpa_supplicant data
  517. * @res: Scan result
  518. * @fetch_time: Time when the result was fetched from the driver
  519. *
  520. * This function updates a BSS table entry (or adds one) based on a scan result.
  521. * This is called separately for each scan result between the calls to
  522. * wpa_bss_update_start() and wpa_bss_update_end().
  523. */
  524. void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
  525. struct wpa_scan_res *res,
  526. struct os_reltime *fetch_time)
  527. {
  528. const u8 *ssid, *p2p, *mesh;
  529. struct wpa_bss *bss;
  530. if (wpa_s->conf->ignore_old_scan_res) {
  531. struct os_reltime update;
  532. calculate_update_time(fetch_time, res->age, &update);
  533. if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
  534. struct os_reltime age;
  535. os_reltime_sub(&wpa_s->scan_trigger_time, &update,
  536. &age);
  537. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
  538. "table entry that is %u.%06u seconds older "
  539. "than our scan trigger",
  540. (unsigned int) age.sec,
  541. (unsigned int) age.usec);
  542. return;
  543. }
  544. }
  545. ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
  546. if (ssid == NULL) {
  547. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
  548. MACSTR, MAC2STR(res->bssid));
  549. return;
  550. }
  551. if (ssid[1] > 32) {
  552. wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
  553. MACSTR, MAC2STR(res->bssid));
  554. return;
  555. }
  556. p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
  557. #ifdef CONFIG_P2P
  558. if (p2p == NULL &&
  559. wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
  560. /*
  561. * If it's a P2P specific interface, then don't update
  562. * the scan result without a P2P IE.
  563. */
  564. wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
  565. " update for P2P interface", MAC2STR(res->bssid));
  566. return;
  567. }
  568. #endif /* CONFIG_P2P */
  569. if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
  570. os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
  571. return; /* Skip P2P listen discovery results here */
  572. /* TODO: add option for ignoring BSSes we are not interested in
  573. * (to save memory) */
  574. mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
  575. if (mesh && mesh[1] <= 32)
  576. ssid = mesh;
  577. bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
  578. if (bss == NULL)
  579. bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
  580. else {
  581. bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
  582. if (wpa_s->last_scan_res) {
  583. unsigned int i;
  584. for (i = 0; i < wpa_s->last_scan_res_used; i++) {
  585. if (bss == wpa_s->last_scan_res[i]) {
  586. /* Already in the list */
  587. return;
  588. }
  589. }
  590. }
  591. }
  592. if (bss == NULL)
  593. return;
  594. if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
  595. struct wpa_bss **n;
  596. unsigned int siz;
  597. if (wpa_s->last_scan_res_size == 0)
  598. siz = 32;
  599. else
  600. siz = wpa_s->last_scan_res_size * 2;
  601. n = os_realloc_array(wpa_s->last_scan_res, siz,
  602. sizeof(struct wpa_bss *));
  603. if (n == NULL)
  604. return;
  605. wpa_s->last_scan_res = n;
  606. wpa_s->last_scan_res_size = siz;
  607. }
  608. if (wpa_s->last_scan_res)
  609. wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
  610. }
  611. static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
  612. const struct scan_info *info)
  613. {
  614. int found;
  615. size_t i;
  616. if (info == NULL)
  617. return 1;
  618. if (info->num_freqs) {
  619. found = 0;
  620. for (i = 0; i < info->num_freqs; i++) {
  621. if (bss->freq == info->freqs[i]) {
  622. found = 1;
  623. break;
  624. }
  625. }
  626. if (!found)
  627. return 0;
  628. }
  629. if (info->num_ssids) {
  630. found = 0;
  631. for (i = 0; i < info->num_ssids; i++) {
  632. const struct wpa_driver_scan_ssid *s = &info->ssids[i];
  633. if ((s->ssid == NULL || s->ssid_len == 0) ||
  634. (s->ssid_len == bss->ssid_len &&
  635. os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
  636. 0)) {
  637. found = 1;
  638. break;
  639. }
  640. }
  641. if (!found)
  642. return 0;
  643. }
  644. return 1;
  645. }
  646. /**
  647. * wpa_bss_update_end - End a BSS table update from scan results
  648. * @wpa_s: Pointer to wpa_supplicant data
  649. * @info: Information about scan parameters
  650. * @new_scan: Whether this update round was based on a new scan
  651. *
  652. * This function is called at the end of each BSS table update round for new
  653. * scan results. The start of the update was indicated with a call to
  654. * wpa_bss_update_start().
  655. */
  656. void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
  657. int new_scan)
  658. {
  659. struct wpa_bss *bss, *n;
  660. os_get_reltime(&wpa_s->last_scan);
  661. if (!new_scan)
  662. return; /* do not expire entries without new scan */
  663. dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
  664. if (wpa_bss_in_use(wpa_s, bss))
  665. continue;
  666. if (!wpa_bss_included_in_scan(bss, info))
  667. continue; /* expire only BSSes that were scanned */
  668. if (bss->last_update_idx < wpa_s->bss_update_idx)
  669. bss->scan_miss_count++;
  670. if (bss->scan_miss_count >=
  671. wpa_s->conf->bss_expiration_scan_count) {
  672. wpa_bss_remove(wpa_s, bss, "no match in scan");
  673. }
  674. }
  675. wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
  676. wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
  677. }
  678. /**
  679. * wpa_bss_flush_by_age - Flush old BSS entries
  680. * @wpa_s: Pointer to wpa_supplicant data
  681. * @age: Maximum entry age in seconds
  682. *
  683. * Remove BSS entries that have not been updated during the last @age seconds.
  684. */
  685. void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
  686. {
  687. struct wpa_bss *bss, *n;
  688. struct os_reltime t;
  689. if (dl_list_empty(&wpa_s->bss))
  690. return;
  691. os_get_reltime(&t);
  692. t.sec -= age;
  693. dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
  694. if (wpa_bss_in_use(wpa_s, bss))
  695. continue;
  696. if (os_reltime_before(&bss->last_update, &t)) {
  697. wpa_bss_remove(wpa_s, bss, __func__);
  698. } else
  699. break;
  700. }
  701. }
  702. static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
  703. {
  704. struct wpa_supplicant *wpa_s = eloop_ctx;
  705. wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
  706. eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
  707. wpa_bss_timeout, wpa_s, NULL);
  708. }
  709. /**
  710. * wpa_bss_init - Initialize BSS table
  711. * @wpa_s: Pointer to wpa_supplicant data
  712. * Returns: 0 on success, -1 on failure
  713. *
  714. * This prepares BSS table lists and timer for periodic updates. The BSS table
  715. * is deinitialized with wpa_bss_deinit() once not needed anymore.
  716. */
  717. int wpa_bss_init(struct wpa_supplicant *wpa_s)
  718. {
  719. dl_list_init(&wpa_s->bss);
  720. dl_list_init(&wpa_s->bss_id);
  721. eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
  722. wpa_bss_timeout, wpa_s, NULL);
  723. return 0;
  724. }
  725. /**
  726. * wpa_bss_flush - Flush all unused BSS entries
  727. * @wpa_s: Pointer to wpa_supplicant data
  728. */
  729. void wpa_bss_flush(struct wpa_supplicant *wpa_s)
  730. {
  731. struct wpa_bss *bss, *n;
  732. wpa_s->clear_driver_scan_cache = 1;
  733. if (wpa_s->bss.next == NULL)
  734. return; /* BSS table not yet initialized */
  735. dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
  736. if (wpa_bss_in_use(wpa_s, bss))
  737. continue;
  738. wpa_bss_remove(wpa_s, bss, __func__);
  739. }
  740. }
  741. /**
  742. * wpa_bss_deinit - Deinitialize BSS table
  743. * @wpa_s: Pointer to wpa_supplicant data
  744. */
  745. void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
  746. {
  747. eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
  748. wpa_bss_flush(wpa_s);
  749. }
  750. /**
  751. * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
  752. * @wpa_s: Pointer to wpa_supplicant data
  753. * @bssid: BSSID
  754. * Returns: Pointer to the BSS entry or %NULL if not found
  755. */
  756. struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
  757. const u8 *bssid)
  758. {
  759. struct wpa_bss *bss;
  760. if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
  761. return NULL;
  762. dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
  763. if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
  764. return bss;
  765. }
  766. return NULL;
  767. }
  768. /**
  769. * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
  770. * @wpa_s: Pointer to wpa_supplicant data
  771. * @bssid: BSSID
  772. * Returns: Pointer to the BSS entry or %NULL if not found
  773. *
  774. * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
  775. * find the entry that has the most recent update. This can help in finding the
  776. * correct entry in cases where the SSID of the AP may have changed recently
  777. * (e.g., in WPS reconfiguration cases).
  778. */
  779. struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
  780. const u8 *bssid)
  781. {
  782. struct wpa_bss *bss, *found = NULL;
  783. if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
  784. return NULL;
  785. dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
  786. if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
  787. continue;
  788. if (found == NULL ||
  789. os_reltime_before(&found->last_update, &bss->last_update))
  790. found = bss;
  791. }
  792. return found;
  793. }
  794. #ifdef CONFIG_P2P
  795. /**
  796. * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
  797. * @wpa_s: Pointer to wpa_supplicant data
  798. * @dev_addr: P2P Device Address of the GO
  799. * Returns: Pointer to the BSS entry or %NULL if not found
  800. */
  801. struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
  802. const u8 *dev_addr)
  803. {
  804. struct wpa_bss *bss;
  805. dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
  806. u8 addr[ETH_ALEN];
  807. if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
  808. addr) == 0 &&
  809. os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
  810. return bss;
  811. }
  812. return NULL;
  813. }
  814. #endif /* CONFIG_P2P */
  815. /**
  816. * wpa_bss_get_id - Fetch a BSS table entry based on identifier
  817. * @wpa_s: Pointer to wpa_supplicant data
  818. * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
  819. * Returns: Pointer to the BSS entry or %NULL if not found
  820. */
  821. struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
  822. {
  823. struct wpa_bss *bss;
  824. dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
  825. if (bss->id == id)
  826. return bss;
  827. }
  828. return NULL;
  829. }
  830. /**
  831. * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
  832. * @wpa_s: Pointer to wpa_supplicant data
  833. * @idf: Smallest allowed identifier assigned for the entry
  834. * @idf: Largest allowed identifier assigned for the entry
  835. * Returns: Pointer to the BSS entry or %NULL if not found
  836. *
  837. * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
  838. * smallest id value to be fetched within the specified range without the
  839. * caller having to know the exact id.
  840. */
  841. struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
  842. unsigned int idf, unsigned int idl)
  843. {
  844. struct wpa_bss *bss;
  845. dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
  846. if (bss->id >= idf && bss->id <= idl)
  847. return bss;
  848. }
  849. return NULL;
  850. }
  851. /**
  852. * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
  853. * @bss: BSS table entry
  854. * @ie: Information element identitifier (WLAN_EID_*)
  855. * Returns: Pointer to the information element (id field) or %NULL if not found
  856. *
  857. * This function returns the first matching information element in the BSS
  858. * entry.
  859. */
  860. const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
  861. {
  862. const u8 *end, *pos;
  863. pos = (const u8 *) (bss + 1);
  864. end = pos + bss->ie_len;
  865. while (pos + 1 < end) {
  866. if (pos + 2 + pos[1] > end)
  867. break;
  868. if (pos[0] == ie)
  869. return pos;
  870. pos += 2 + pos[1];
  871. }
  872. return NULL;
  873. }
  874. /**
  875. * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
  876. * @bss: BSS table entry
  877. * @vendor_type: Vendor type (four octets starting the IE payload)
  878. * Returns: Pointer to the information element (id field) or %NULL if not found
  879. *
  880. * This function returns the first matching information element in the BSS
  881. * entry.
  882. */
  883. const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
  884. {
  885. const u8 *end, *pos;
  886. pos = (const u8 *) (bss + 1);
  887. end = pos + bss->ie_len;
  888. while (pos + 1 < end) {
  889. if (pos + 2 + pos[1] > end)
  890. break;
  891. if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
  892. vendor_type == WPA_GET_BE32(&pos[2]))
  893. return pos;
  894. pos += 2 + pos[1];
  895. }
  896. return NULL;
  897. }
  898. /**
  899. * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
  900. * @bss: BSS table entry
  901. * @vendor_type: Vendor type (four octets starting the IE payload)
  902. * Returns: Pointer to the information element (id field) or %NULL if not found
  903. *
  904. * This function returns the first matching information element in the BSS
  905. * entry.
  906. *
  907. * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
  908. * from Beacon frames instead of either Beacon or Probe Response frames.
  909. */
  910. const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
  911. u32 vendor_type)
  912. {
  913. const u8 *end, *pos;
  914. if (bss->beacon_ie_len == 0)
  915. return NULL;
  916. pos = (const u8 *) (bss + 1);
  917. pos += bss->ie_len;
  918. end = pos + bss->beacon_ie_len;
  919. while (pos + 1 < end) {
  920. if (pos + 2 + pos[1] > end)
  921. break;
  922. if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
  923. vendor_type == WPA_GET_BE32(&pos[2]))
  924. return pos;
  925. pos += 2 + pos[1];
  926. }
  927. return NULL;
  928. }
  929. /**
  930. * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
  931. * @bss: BSS table entry
  932. * @vendor_type: Vendor type (four octets starting the IE payload)
  933. * Returns: Pointer to the information element payload or %NULL if not found
  934. *
  935. * This function returns concatenated payload of possibly fragmented vendor
  936. * specific information elements in the BSS entry. The caller is responsible for
  937. * freeing the returned buffer.
  938. */
  939. struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
  940. u32 vendor_type)
  941. {
  942. struct wpabuf *buf;
  943. const u8 *end, *pos;
  944. buf = wpabuf_alloc(bss->ie_len);
  945. if (buf == NULL)
  946. return NULL;
  947. pos = (const u8 *) (bss + 1);
  948. end = pos + bss->ie_len;
  949. while (pos + 1 < end) {
  950. if (pos + 2 + pos[1] > end)
  951. break;
  952. if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
  953. vendor_type == WPA_GET_BE32(&pos[2]))
  954. wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
  955. pos += 2 + pos[1];
  956. }
  957. if (wpabuf_len(buf) == 0) {
  958. wpabuf_free(buf);
  959. buf = NULL;
  960. }
  961. return buf;
  962. }
  963. /**
  964. * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
  965. * @bss: BSS table entry
  966. * @vendor_type: Vendor type (four octets starting the IE payload)
  967. * Returns: Pointer to the information element payload or %NULL if not found
  968. *
  969. * This function returns concatenated payload of possibly fragmented vendor
  970. * specific information elements in the BSS entry. The caller is responsible for
  971. * freeing the returned buffer.
  972. *
  973. * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
  974. * from Beacon frames instead of either Beacon or Probe Response frames.
  975. */
  976. struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
  977. u32 vendor_type)
  978. {
  979. struct wpabuf *buf;
  980. const u8 *end, *pos;
  981. buf = wpabuf_alloc(bss->beacon_ie_len);
  982. if (buf == NULL)
  983. return NULL;
  984. pos = (const u8 *) (bss + 1);
  985. pos += bss->ie_len;
  986. end = pos + bss->beacon_ie_len;
  987. while (pos + 1 < end) {
  988. if (pos + 2 + pos[1] > end)
  989. break;
  990. if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
  991. vendor_type == WPA_GET_BE32(&pos[2]))
  992. wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
  993. pos += 2 + pos[1];
  994. }
  995. if (wpabuf_len(buf) == 0) {
  996. wpabuf_free(buf);
  997. buf = NULL;
  998. }
  999. return buf;
  1000. }
  1001. /**
  1002. * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
  1003. * @bss: BSS table entry
  1004. * Returns: Maximum legacy rate in units of 500 kbps
  1005. */
  1006. int wpa_bss_get_max_rate(const struct wpa_bss *bss)
  1007. {
  1008. int rate = 0;
  1009. const u8 *ie;
  1010. int i;
  1011. ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
  1012. for (i = 0; ie && i < ie[1]; i++) {
  1013. if ((ie[i + 2] & 0x7f) > rate)
  1014. rate = ie[i + 2] & 0x7f;
  1015. }
  1016. ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
  1017. for (i = 0; ie && i < ie[1]; i++) {
  1018. if ((ie[i + 2] & 0x7f) > rate)
  1019. rate = ie[i + 2] & 0x7f;
  1020. }
  1021. return rate;
  1022. }
  1023. /**
  1024. * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
  1025. * @bss: BSS table entry
  1026. * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
  1027. * Returns: number of legacy TX rates or -1 on failure
  1028. *
  1029. * The caller is responsible for freeing the returned buffer with os_free() in
  1030. * case of success.
  1031. */
  1032. int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
  1033. {
  1034. const u8 *ie, *ie2;
  1035. int i, j;
  1036. unsigned int len;
  1037. u8 *r;
  1038. ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
  1039. ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
  1040. len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
  1041. r = os_malloc(len);
  1042. if (!r)
  1043. return -1;
  1044. for (i = 0; ie && i < ie[1]; i++)
  1045. r[i] = ie[i + 2] & 0x7f;
  1046. for (j = 0; ie2 && j < ie2[1]; j++)
  1047. r[i + j] = ie2[j + 2] & 0x7f;
  1048. *rates = r;
  1049. return len;
  1050. }