hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / drivers / scan_helpers.c
1 /*
2  * WPA Supplicant - Helper functions for scan result processing
3  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "drivers/driver.h"
19 #include "ieee802_11_defs.h"
20
21
22 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
23 {
24         const u8 *end, *pos;
25
26         pos = (const u8 *) (res + 1);
27         end = pos + res->ie_len;
28
29         while (pos + 1 < end) {
30                 if (pos + 2 + pos[1] > end)
31                         break;
32                 if (pos[0] == ie)
33                         return pos;
34                 pos += 2 + pos[1];
35         }
36
37         return NULL;
38 }
39
40
41 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
42                                   u32 vendor_type)
43 {
44         const u8 *end, *pos;
45
46         pos = (const u8 *) (res + 1);
47         end = pos + res->ie_len;
48
49         while (pos + 1 < end) {
50                 if (pos + 2 + pos[1] > end)
51                         break;
52                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
53                     vendor_type == WPA_GET_BE32(&pos[2]))
54                         return pos;
55                 pos += 2 + pos[1];
56         }
57
58         return NULL;
59 }
60
61
62 struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
63                                              u32 vendor_type)
64 {
65         struct wpabuf *buf;
66         const u8 *end, *pos;
67
68         buf = wpabuf_alloc(res->ie_len);
69         if (buf == NULL)
70                 return NULL;
71
72         pos = (const u8 *) (res + 1);
73         end = pos + res->ie_len;
74
75         while (pos + 1 < end) {
76                 if (pos + 2 + pos[1] > end)
77                         break;
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);
81                 pos += 2 + pos[1];
82         }
83
84         if (wpabuf_len(buf) == 0) {
85                 wpabuf_free(buf);
86                 buf = NULL;
87         }
88
89         return buf;
90 }
91
92
93 int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
94 {
95         int rate = 0;
96         const u8 *ie;
97         int i;
98
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;
103         }
104
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;
109         }
110
111         return rate;
112 }
113
114
115 void wpa_scan_results_free(struct wpa_scan_results *res)
116 {
117         size_t i;
118
119         if (res == NULL)
120                 return;
121
122         for (i = 0; i < res->num; i++)
123                 os_free(res->res[i]);
124         os_free(res->res);
125         os_free(res);
126 }
127
128
129 /* Compare function for sorting scan results. Return >0 if @b is considered
130  * better. */
131 static int wpa_scan_result_compar(const void *a, const void *b)
132 {
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;
138
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;
144
145         if (wpa_b && !wpa_a)
146                 return 1;
147         if (!wpa_b && wpa_a)
148                 return -1;
149
150         /* privacy support preferred */
151         if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
152             (wb->caps & IEEE80211_CAP_PRIVACY))
153                 return 1;
154         if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
155             (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
156                 return -1;
157
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;
165         }
166
167         /* use freq for channel preference */
168
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;
175 }
176
177
178 void wpa_scan_sort_results(struct wpa_scan_results *res)
179 {
180         qsort(res->res, res->num, sizeof(struct wpa_scan_res *),
181               wpa_scan_result_compar);
182 }