1252190Srpaulo/*
2252190Srpaulo * Common driver-related functions
3252190Srpaulo * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
4252190Srpaulo *
5252190Srpaulo * This software may be distributed under the terms of the BSD license.
6252190Srpaulo * See README for more details.
7252190Srpaulo */
8252190Srpaulo
9252190Srpaulo#include "includes.h"
10252190Srpaulo#include "utils/common.h"
11252190Srpaulo#include "driver.h"
12252190Srpaulo
13252190Srpaulovoid wpa_scan_results_free(struct wpa_scan_results *res)
14252190Srpaulo{
15252190Srpaulo	size_t i;
16252190Srpaulo
17252190Srpaulo	if (res == NULL)
18252190Srpaulo		return;
19252190Srpaulo
20252190Srpaulo	for (i = 0; i < res->num; i++)
21252190Srpaulo		os_free(res->res[i]);
22252190Srpaulo	os_free(res->res);
23252190Srpaulo	os_free(res);
24252190Srpaulo}
25252190Srpaulo
26252190Srpaulo
27252190Srpauloconst char * event_to_string(enum wpa_event_type event)
28252190Srpaulo{
29252190Srpaulo#define E2S(n) case EVENT_ ## n: return #n
30252190Srpaulo	switch (event) {
31252190Srpaulo	E2S(ASSOC);
32252190Srpaulo	E2S(DISASSOC);
33252190Srpaulo	E2S(MICHAEL_MIC_FAILURE);
34252190Srpaulo	E2S(SCAN_RESULTS);
35252190Srpaulo	E2S(ASSOCINFO);
36252190Srpaulo	E2S(INTERFACE_STATUS);
37252190Srpaulo	E2S(PMKID_CANDIDATE);
38252190Srpaulo	E2S(STKSTART);
39252190Srpaulo	E2S(TDLS);
40252190Srpaulo	E2S(FT_RESPONSE);
41252190Srpaulo	E2S(IBSS_RSN_START);
42252190Srpaulo	E2S(AUTH);
43252190Srpaulo	E2S(DEAUTH);
44252190Srpaulo	E2S(ASSOC_REJECT);
45252190Srpaulo	E2S(AUTH_TIMED_OUT);
46252190Srpaulo	E2S(ASSOC_TIMED_OUT);
47252190Srpaulo	E2S(WPS_BUTTON_PUSHED);
48252190Srpaulo	E2S(TX_STATUS);
49252190Srpaulo	E2S(RX_FROM_UNKNOWN);
50252190Srpaulo	E2S(RX_MGMT);
51252190Srpaulo	E2S(REMAIN_ON_CHANNEL);
52252190Srpaulo	E2S(CANCEL_REMAIN_ON_CHANNEL);
53252190Srpaulo	E2S(RX_PROBE_REQ);
54252190Srpaulo	E2S(NEW_STA);
55252190Srpaulo	E2S(EAPOL_RX);
56252190Srpaulo	E2S(SIGNAL_CHANGE);
57252190Srpaulo	E2S(INTERFACE_ENABLED);
58252190Srpaulo	E2S(INTERFACE_DISABLED);
59252190Srpaulo	E2S(CHANNEL_LIST_CHANGED);
60252190Srpaulo	E2S(INTERFACE_UNAVAILABLE);
61252190Srpaulo	E2S(BEST_CHANNEL);
62252190Srpaulo	E2S(UNPROT_DEAUTH);
63252190Srpaulo	E2S(UNPROT_DISASSOC);
64252190Srpaulo	E2S(STATION_LOW_ACK);
65252190Srpaulo	E2S(IBSS_PEER_LOST);
66252190Srpaulo	E2S(DRIVER_GTK_REKEY);
67252190Srpaulo	E2S(SCHED_SCAN_STOPPED);
68252190Srpaulo	E2S(DRIVER_CLIENT_POLL_OK);
69252190Srpaulo	E2S(EAPOL_TX_STATUS);
70252190Srpaulo	E2S(CH_SWITCH);
71252190Srpaulo	E2S(WNM);
72281806Srpaulo	E2S(CONNECT_FAILED_REASON);
73281806Srpaulo	E2S(DFS_RADAR_DETECTED);
74281806Srpaulo	E2S(DFS_CAC_FINISHED);
75281806Srpaulo	E2S(DFS_CAC_ABORTED);
76281806Srpaulo	E2S(DFS_NOP_FINISHED);
77281806Srpaulo	E2S(SURVEY);
78281806Srpaulo	E2S(SCAN_STARTED);
79281806Srpaulo	E2S(AVOID_FREQUENCIES);
80281806Srpaulo	E2S(NEW_PEER_CANDIDATE);
81281806Srpaulo	E2S(ACS_CHANNEL_SELECTED);
82281806Srpaulo	E2S(DFS_CAC_STARTED);
83252190Srpaulo	}
84252190Srpaulo
85252190Srpaulo	return "UNKNOWN";
86252190Srpaulo#undef E2S
87252190Srpaulo}
88281806Srpaulo
89281806Srpaulo
90281806Srpauloconst char * channel_width_to_string(enum chan_width width)
91281806Srpaulo{
92281806Srpaulo	switch (width) {
93281806Srpaulo	case CHAN_WIDTH_20_NOHT:
94281806Srpaulo		return "20 MHz (no HT)";
95281806Srpaulo	case CHAN_WIDTH_20:
96281806Srpaulo		return "20 MHz";
97281806Srpaulo	case CHAN_WIDTH_40:
98281806Srpaulo		return "40 MHz";
99281806Srpaulo	case CHAN_WIDTH_80:
100281806Srpaulo		return "80 MHz";
101281806Srpaulo	case CHAN_WIDTH_80P80:
102281806Srpaulo		return "80+80 MHz";
103281806Srpaulo	case CHAN_WIDTH_160:
104281806Srpaulo		return "160 MHz";
105281806Srpaulo	default:
106281806Srpaulo		return "unknown";
107281806Srpaulo	}
108281806Srpaulo}
109281806Srpaulo
110281806Srpaulo
111281806Srpauloint ht_supported(const struct hostapd_hw_modes *mode)
112281806Srpaulo{
113281806Srpaulo	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
114281806Srpaulo		/*
115281806Srpaulo		 * The driver did not indicate whether it supports HT. Assume
116281806Srpaulo		 * it does to avoid connection issues.
117281806Srpaulo		 */
118281806Srpaulo		return 1;
119281806Srpaulo	}
120281806Srpaulo
121281806Srpaulo	/*
122281806Srpaulo	 * IEEE Std 802.11n-2009 20.1.1:
123281806Srpaulo	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
124281806Srpaulo	 */
125281806Srpaulo	return mode->mcs_set[0] == 0xff;
126281806Srpaulo}
127281806Srpaulo
128281806Srpaulo
129281806Srpauloint vht_supported(const struct hostapd_hw_modes *mode)
130281806Srpaulo{
131281806Srpaulo	if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
132281806Srpaulo		/*
133281806Srpaulo		 * The driver did not indicate whether it supports VHT. Assume
134281806Srpaulo		 * it does to avoid connection issues.
135281806Srpaulo		 */
136281806Srpaulo		return 1;
137281806Srpaulo	}
138281806Srpaulo
139281806Srpaulo	/*
140281806Srpaulo	 * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
141281806Srpaulo	 * TODO: Verify if this complies with the standard
142281806Srpaulo	 */
143281806Srpaulo	return (mode->vht_mcs_set[0] & 0x3) != 3;
144281806Srpaulo}
145281806Srpaulo
146281806Srpaulo
147281806Srpaulostatic int wpa_check_wowlan_trigger(const char *start, const char *trigger,
148281806Srpaulo				    int capa_trigger, u8 *param_trigger)
149281806Srpaulo{
150281806Srpaulo	if (os_strcmp(start, trigger) != 0)
151281806Srpaulo		return 0;
152281806Srpaulo	if (!capa_trigger)
153281806Srpaulo		return 0;
154281806Srpaulo
155281806Srpaulo	*param_trigger = 1;
156281806Srpaulo	return 1;
157281806Srpaulo}
158281806Srpaulo
159281806Srpaulo
160281806Srpaulostruct wowlan_triggers *
161281806Srpaulowpa_get_wowlan_triggers(const char *wowlan_triggers,
162281806Srpaulo			const struct wpa_driver_capa *capa)
163281806Srpaulo{
164281806Srpaulo	struct wowlan_triggers *triggers;
165281806Srpaulo	char *start, *end, *buf;
166281806Srpaulo	int last;
167281806Srpaulo
168281806Srpaulo	if (!wowlan_triggers)
169281806Srpaulo		return NULL;
170281806Srpaulo
171281806Srpaulo	buf = os_strdup(wowlan_triggers);
172281806Srpaulo	if (buf == NULL)
173281806Srpaulo		return NULL;
174281806Srpaulo
175281806Srpaulo	triggers = os_zalloc(sizeof(*triggers));
176281806Srpaulo	if (triggers == NULL)
177281806Srpaulo		goto out;
178281806Srpaulo
179281806Srpaulo#define CHECK_TRIGGER(trigger) \
180281806Srpaulo	wpa_check_wowlan_trigger(start, #trigger,			\
181281806Srpaulo				  capa->wowlan_triggers.trigger,	\
182281806Srpaulo				  &triggers->trigger)
183281806Srpaulo
184281806Srpaulo	start = buf;
185281806Srpaulo	while (*start != '\0') {
186281806Srpaulo		while (isblank(*start))
187281806Srpaulo			start++;
188281806Srpaulo		if (*start == '\0')
189281806Srpaulo			break;
190281806Srpaulo		end = start;
191281806Srpaulo		while (!isblank(*end) && *end != '\0')
192281806Srpaulo			end++;
193281806Srpaulo		last = *end == '\0';
194281806Srpaulo		*end = '\0';
195281806Srpaulo
196281806Srpaulo		if (!CHECK_TRIGGER(any) &&
197281806Srpaulo		    !CHECK_TRIGGER(disconnect) &&
198281806Srpaulo		    !CHECK_TRIGGER(magic_pkt) &&
199281806Srpaulo		    !CHECK_TRIGGER(gtk_rekey_failure) &&
200281806Srpaulo		    !CHECK_TRIGGER(eap_identity_req) &&
201281806Srpaulo		    !CHECK_TRIGGER(four_way_handshake) &&
202281806Srpaulo		    !CHECK_TRIGGER(rfkill_release)) {
203281806Srpaulo			wpa_printf(MSG_DEBUG,
204281806Srpaulo				   "Unknown/unsupported wowlan trigger '%s'",
205281806Srpaulo				   start);
206281806Srpaulo			os_free(triggers);
207281806Srpaulo			triggers = NULL;
208281806Srpaulo			goto out;
209281806Srpaulo		}
210281806Srpaulo
211281806Srpaulo		if (last)
212281806Srpaulo			break;
213281806Srpaulo		start = end + 1;
214281806Srpaulo	}
215281806Srpaulo#undef CHECK_TRIGGER
216281806Srpaulo
217281806Srpauloout:
218281806Srpaulo	os_free(buf);
219281806Srpaulo	return triggers;
220281806Srpaulo}
221