2 * WPA Supplicant - Helper functions for scan result processing
3 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "drivers/driver.h"
19 #include "common/ieee802_11_defs.h"
22 const u8
* wpa_scan_get_ie(const struct wpa_scan_res
*res
, u8 ie
)
26 pos
= (const u8
*) (res
+ 1);
27 end
= pos
+ res
->ie_len
;
29 while (pos
+ 1 < end
) {
30 if (pos
+ 2 + pos
[1] > end
)
41 const u8
* wpa_scan_get_vendor_ie(const struct wpa_scan_res
*res
,
46 pos
= (const u8
*) (res
+ 1);
47 end
= pos
+ res
->ie_len
;
49 while (pos
+ 1 < end
) {
50 if (pos
+ 2 + pos
[1] > end
)
52 if (pos
[0] == WLAN_EID_VENDOR_SPECIFIC
&& pos
[1] >= 4 &&
53 vendor_type
== WPA_GET_BE32(&pos
[2]))
62 struct wpabuf
* wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res
*res
,
68 buf
= wpabuf_alloc(res
->ie_len
);
72 pos
= (const u8
*) (res
+ 1);
73 end
= pos
+ res
->ie_len
;
75 while (pos
+ 1 < end
) {
76 if (pos
+ 2 + pos
[1] > end
)
78 if (pos
[0] == WLAN_EID_VENDOR_SPECIFIC
&& pos
[1] >= 4 &&
79 vendor_type
== WPA_GET_BE32(&pos
[2]))
80 wpabuf_put_data(buf
, pos
+ 2 + 4, pos
[1] - 4);
84 if (wpabuf_len(buf
) == 0) {
93 int wpa_scan_get_max_rate(const struct wpa_scan_res
*res
)
99 ie
= wpa_scan_get_ie(res
, WLAN_EID_SUPP_RATES
);
100 for (i
= 0; ie
&& i
< ie
[1]; i
++) {
101 if ((ie
[i
+ 2] & 0x7f) > rate
)
102 rate
= ie
[i
+ 2] & 0x7f;
105 ie
= wpa_scan_get_ie(res
, WLAN_EID_EXT_SUPP_RATES
);
106 for (i
= 0; ie
&& i
< ie
[1]; i
++) {
107 if ((ie
[i
+ 2] & 0x7f) > rate
)
108 rate
= ie
[i
+ 2] & 0x7f;
115 void wpa_scan_results_free(struct wpa_scan_results
*res
)
122 for (i
= 0; i
< res
->num
; i
++)
123 os_free(res
->res
[i
]);
129 /* Compare function for sorting scan results. Return >0 if @b is considered
131 static int wpa_scan_result_compar(const void *a
, const void *b
)
133 struct wpa_scan_res
**_wa
= (void *) a
;
134 struct wpa_scan_res
**_wb
= (void *) b
;
135 struct wpa_scan_res
*wa
= *_wa
;
136 struct wpa_scan_res
*wb
= *_wb
;
137 int wpa_a
, wpa_b
, maxrate_a
, maxrate_b
;
139 /* WPA/WPA2 support preferred */
140 wpa_a
= wpa_scan_get_vendor_ie(wa
, WPA_IE_VENDOR_TYPE
) != NULL
||
141 wpa_scan_get_ie(wa
, WLAN_EID_RSN
) != NULL
;
142 wpa_b
= wpa_scan_get_vendor_ie(wb
, WPA_IE_VENDOR_TYPE
) != NULL
||
143 wpa_scan_get_ie(wb
, WLAN_EID_RSN
) != NULL
;
150 /* privacy support preferred */
151 if ((wa
->caps
& IEEE80211_CAP_PRIVACY
) == 0 &&
152 (wb
->caps
& IEEE80211_CAP_PRIVACY
))
154 if ((wa
->caps
& IEEE80211_CAP_PRIVACY
) &&
155 (wb
->caps
& IEEE80211_CAP_PRIVACY
) == 0)
158 /* best/max rate preferred if signal level close enough XXX */
159 if ((wa
->level
&& wb
->level
&& abs(wb
->level
- wa
->level
) < 5) ||
160 (wa
->qual
&& wb
->qual
&& abs(wb
->qual
- wa
->qual
) < 10)) {
161 maxrate_a
= wpa_scan_get_max_rate(wa
);
162 maxrate_b
= wpa_scan_get_max_rate(wb
);
163 if (maxrate_a
!= maxrate_b
)
164 return maxrate_b
- maxrate_a
;
167 /* use freq for channel preference */
169 /* all things being equal, use signal level; if signal levels are
170 * identical, use quality values since some drivers may only report
171 * that value and leave the signal level zero */
172 if (wb
->level
== wa
->level
)
173 return wb
->qual
- wa
->qual
;
174 return wb
->level
- wa
->level
;
178 void wpa_scan_sort_results(struct wpa_scan_results
*res
)
180 qsort(res
->res
, res
->num
, sizeof(struct wpa_scan_res
*),
181 wpa_scan_result_compar
);