• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/wpa_supplicant/src/drivers/
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
22const 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
41const 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
62struct 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
93int 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
115void 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. */
131static 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
178void 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}
183