13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * Common driver-related functions
3*a1157835SDaniel Fojt  * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino #include "utils/common.h"
113ff40c12SJohn Marino #include "driver.h"
123ff40c12SJohn Marino 
wpa_scan_results_free(struct wpa_scan_results * res)133ff40c12SJohn Marino void wpa_scan_results_free(struct wpa_scan_results *res)
143ff40c12SJohn Marino {
153ff40c12SJohn Marino 	size_t i;
163ff40c12SJohn Marino 
173ff40c12SJohn Marino 	if (res == NULL)
183ff40c12SJohn Marino 		return;
193ff40c12SJohn Marino 
203ff40c12SJohn Marino 	for (i = 0; i < res->num; i++)
213ff40c12SJohn Marino 		os_free(res->res[i]);
223ff40c12SJohn Marino 	os_free(res->res);
233ff40c12SJohn Marino 	os_free(res);
243ff40c12SJohn Marino }
253ff40c12SJohn Marino 
263ff40c12SJohn Marino 
event_to_string(enum wpa_event_type event)273ff40c12SJohn Marino const char * event_to_string(enum wpa_event_type event)
283ff40c12SJohn Marino {
293ff40c12SJohn Marino #define E2S(n) case EVENT_ ## n: return #n
303ff40c12SJohn Marino 	switch (event) {
313ff40c12SJohn Marino 	E2S(ASSOC);
323ff40c12SJohn Marino 	E2S(DISASSOC);
333ff40c12SJohn Marino 	E2S(MICHAEL_MIC_FAILURE);
343ff40c12SJohn Marino 	E2S(SCAN_RESULTS);
353ff40c12SJohn Marino 	E2S(ASSOCINFO);
363ff40c12SJohn Marino 	E2S(INTERFACE_STATUS);
373ff40c12SJohn Marino 	E2S(PMKID_CANDIDATE);
383ff40c12SJohn Marino 	E2S(TDLS);
393ff40c12SJohn Marino 	E2S(FT_RESPONSE);
403ff40c12SJohn Marino 	E2S(IBSS_RSN_START);
413ff40c12SJohn Marino 	E2S(AUTH);
423ff40c12SJohn Marino 	E2S(DEAUTH);
433ff40c12SJohn Marino 	E2S(ASSOC_REJECT);
443ff40c12SJohn Marino 	E2S(AUTH_TIMED_OUT);
453ff40c12SJohn Marino 	E2S(ASSOC_TIMED_OUT);
463ff40c12SJohn Marino 	E2S(WPS_BUTTON_PUSHED);
473ff40c12SJohn Marino 	E2S(TX_STATUS);
483ff40c12SJohn Marino 	E2S(RX_FROM_UNKNOWN);
493ff40c12SJohn Marino 	E2S(RX_MGMT);
503ff40c12SJohn Marino 	E2S(REMAIN_ON_CHANNEL);
513ff40c12SJohn Marino 	E2S(CANCEL_REMAIN_ON_CHANNEL);
523ff40c12SJohn Marino 	E2S(RX_PROBE_REQ);
533ff40c12SJohn Marino 	E2S(NEW_STA);
543ff40c12SJohn Marino 	E2S(EAPOL_RX);
553ff40c12SJohn Marino 	E2S(SIGNAL_CHANGE);
563ff40c12SJohn Marino 	E2S(INTERFACE_ENABLED);
573ff40c12SJohn Marino 	E2S(INTERFACE_DISABLED);
583ff40c12SJohn Marino 	E2S(CHANNEL_LIST_CHANGED);
593ff40c12SJohn Marino 	E2S(INTERFACE_UNAVAILABLE);
603ff40c12SJohn Marino 	E2S(BEST_CHANNEL);
613ff40c12SJohn Marino 	E2S(UNPROT_DEAUTH);
623ff40c12SJohn Marino 	E2S(UNPROT_DISASSOC);
633ff40c12SJohn Marino 	E2S(STATION_LOW_ACK);
643ff40c12SJohn Marino 	E2S(IBSS_PEER_LOST);
653ff40c12SJohn Marino 	E2S(DRIVER_GTK_REKEY);
663ff40c12SJohn Marino 	E2S(SCHED_SCAN_STOPPED);
673ff40c12SJohn Marino 	E2S(DRIVER_CLIENT_POLL_OK);
683ff40c12SJohn Marino 	E2S(EAPOL_TX_STATUS);
693ff40c12SJohn Marino 	E2S(CH_SWITCH);
70*a1157835SDaniel Fojt 	E2S(CH_SWITCH_STARTED);
713ff40c12SJohn Marino 	E2S(WNM);
723ff40c12SJohn Marino 	E2S(CONNECT_FAILED_REASON);
733ff40c12SJohn Marino 	E2S(DFS_RADAR_DETECTED);
743ff40c12SJohn Marino 	E2S(DFS_CAC_FINISHED);
753ff40c12SJohn Marino 	E2S(DFS_CAC_ABORTED);
763ff40c12SJohn Marino 	E2S(DFS_NOP_FINISHED);
773ff40c12SJohn Marino 	E2S(SURVEY);
783ff40c12SJohn Marino 	E2S(SCAN_STARTED);
793ff40c12SJohn Marino 	E2S(AVOID_FREQUENCIES);
80*a1157835SDaniel Fojt 	E2S(NEW_PEER_CANDIDATE);
81*a1157835SDaniel Fojt 	E2S(ACS_CHANNEL_SELECTED);
82*a1157835SDaniel Fojt 	E2S(DFS_CAC_STARTED);
83*a1157835SDaniel Fojt 	E2S(P2P_LO_STOP);
84*a1157835SDaniel Fojt 	E2S(BEACON_LOSS);
85*a1157835SDaniel Fojt 	E2S(DFS_PRE_CAC_EXPIRED);
86*a1157835SDaniel Fojt 	E2S(EXTERNAL_AUTH);
87*a1157835SDaniel Fojt 	E2S(PORT_AUTHORIZED);
88*a1157835SDaniel Fojt 	E2S(STATION_OPMODE_CHANGED);
89*a1157835SDaniel Fojt 	E2S(INTERFACE_MAC_CHANGED);
90*a1157835SDaniel Fojt 	E2S(WDS_STA_INTERFACE_STATUS);
91*a1157835SDaniel Fojt 	E2S(UPDATE_DH);
923ff40c12SJohn Marino 	}
933ff40c12SJohn Marino 
943ff40c12SJohn Marino 	return "UNKNOWN";
953ff40c12SJohn Marino #undef E2S
963ff40c12SJohn Marino }
97*a1157835SDaniel Fojt 
98*a1157835SDaniel Fojt 
channel_width_to_string(enum chan_width width)99*a1157835SDaniel Fojt const char * channel_width_to_string(enum chan_width width)
100*a1157835SDaniel Fojt {
101*a1157835SDaniel Fojt 	switch (width) {
102*a1157835SDaniel Fojt 	case CHAN_WIDTH_20_NOHT:
103*a1157835SDaniel Fojt 		return "20 MHz (no HT)";
104*a1157835SDaniel Fojt 	case CHAN_WIDTH_20:
105*a1157835SDaniel Fojt 		return "20 MHz";
106*a1157835SDaniel Fojt 	case CHAN_WIDTH_40:
107*a1157835SDaniel Fojt 		return "40 MHz";
108*a1157835SDaniel Fojt 	case CHAN_WIDTH_80:
109*a1157835SDaniel Fojt 		return "80 MHz";
110*a1157835SDaniel Fojt 	case CHAN_WIDTH_80P80:
111*a1157835SDaniel Fojt 		return "80+80 MHz";
112*a1157835SDaniel Fojt 	case CHAN_WIDTH_160:
113*a1157835SDaniel Fojt 		return "160 MHz";
114*a1157835SDaniel Fojt 	default:
115*a1157835SDaniel Fojt 		return "unknown";
116*a1157835SDaniel Fojt 	}
117*a1157835SDaniel Fojt }
118*a1157835SDaniel Fojt 
119*a1157835SDaniel Fojt 
channel_width_to_int(enum chan_width width)120*a1157835SDaniel Fojt int channel_width_to_int(enum chan_width width)
121*a1157835SDaniel Fojt {
122*a1157835SDaniel Fojt 	switch (width) {
123*a1157835SDaniel Fojt 	case CHAN_WIDTH_20_NOHT:
124*a1157835SDaniel Fojt 	case CHAN_WIDTH_20:
125*a1157835SDaniel Fojt 		return 20;
126*a1157835SDaniel Fojt 	case CHAN_WIDTH_40:
127*a1157835SDaniel Fojt 		return 40;
128*a1157835SDaniel Fojt 	case CHAN_WIDTH_80:
129*a1157835SDaniel Fojt 		return 80;
130*a1157835SDaniel Fojt 	case CHAN_WIDTH_80P80:
131*a1157835SDaniel Fojt 	case CHAN_WIDTH_160:
132*a1157835SDaniel Fojt 		return 160;
133*a1157835SDaniel Fojt 	default:
134*a1157835SDaniel Fojt 		return 0;
135*a1157835SDaniel Fojt 	}
136*a1157835SDaniel Fojt }
137*a1157835SDaniel Fojt 
138*a1157835SDaniel Fojt 
ht_supported(const struct hostapd_hw_modes * mode)139*a1157835SDaniel Fojt int ht_supported(const struct hostapd_hw_modes *mode)
140*a1157835SDaniel Fojt {
141*a1157835SDaniel Fojt 	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
142*a1157835SDaniel Fojt 		/*
143*a1157835SDaniel Fojt 		 * The driver did not indicate whether it supports HT. Assume
144*a1157835SDaniel Fojt 		 * it does to avoid connection issues.
145*a1157835SDaniel Fojt 		 */
146*a1157835SDaniel Fojt 		return 1;
147*a1157835SDaniel Fojt 	}
148*a1157835SDaniel Fojt 
149*a1157835SDaniel Fojt 	/*
150*a1157835SDaniel Fojt 	 * IEEE Std 802.11n-2009 20.1.1:
151*a1157835SDaniel Fojt 	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
152*a1157835SDaniel Fojt 	 */
153*a1157835SDaniel Fojt 	return mode->mcs_set[0] == 0xff;
154*a1157835SDaniel Fojt }
155*a1157835SDaniel Fojt 
156*a1157835SDaniel Fojt 
vht_supported(const struct hostapd_hw_modes * mode)157*a1157835SDaniel Fojt int vht_supported(const struct hostapd_hw_modes *mode)
158*a1157835SDaniel Fojt {
159*a1157835SDaniel Fojt 	if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
160*a1157835SDaniel Fojt 		/*
161*a1157835SDaniel Fojt 		 * The driver did not indicate whether it supports VHT. Assume
162*a1157835SDaniel Fojt 		 * it does to avoid connection issues.
163*a1157835SDaniel Fojt 		 */
164*a1157835SDaniel Fojt 		return 1;
165*a1157835SDaniel Fojt 	}
166*a1157835SDaniel Fojt 
167*a1157835SDaniel Fojt 	/*
168*a1157835SDaniel Fojt 	 * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
169*a1157835SDaniel Fojt 	 * TODO: Verify if this complies with the standard
170*a1157835SDaniel Fojt 	 */
171*a1157835SDaniel Fojt 	return (mode->vht_mcs_set[0] & 0x3) != 3;
172*a1157835SDaniel Fojt }
173*a1157835SDaniel Fojt 
174*a1157835SDaniel Fojt 
wpa_check_wowlan_trigger(const char * start,const char * trigger,int capa_trigger,u8 * param_trigger)175*a1157835SDaniel Fojt static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
176*a1157835SDaniel Fojt 				    int capa_trigger, u8 *param_trigger)
177*a1157835SDaniel Fojt {
178*a1157835SDaniel Fojt 	if (os_strcmp(start, trigger) != 0)
179*a1157835SDaniel Fojt 		return 0;
180*a1157835SDaniel Fojt 	if (!capa_trigger)
181*a1157835SDaniel Fojt 		return 0;
182*a1157835SDaniel Fojt 
183*a1157835SDaniel Fojt 	*param_trigger = 1;
184*a1157835SDaniel Fojt 	return 1;
185*a1157835SDaniel Fojt }
186*a1157835SDaniel Fojt 
187*a1157835SDaniel Fojt 
188*a1157835SDaniel Fojt struct wowlan_triggers *
wpa_get_wowlan_triggers(const char * wowlan_triggers,const struct wpa_driver_capa * capa)189*a1157835SDaniel Fojt wpa_get_wowlan_triggers(const char *wowlan_triggers,
190*a1157835SDaniel Fojt 			const struct wpa_driver_capa *capa)
191*a1157835SDaniel Fojt {
192*a1157835SDaniel Fojt 	struct wowlan_triggers *triggers;
193*a1157835SDaniel Fojt 	char *start, *end, *buf;
194*a1157835SDaniel Fojt 	int last;
195*a1157835SDaniel Fojt 
196*a1157835SDaniel Fojt 	if (!wowlan_triggers)
197*a1157835SDaniel Fojt 		return NULL;
198*a1157835SDaniel Fojt 
199*a1157835SDaniel Fojt 	buf = os_strdup(wowlan_triggers);
200*a1157835SDaniel Fojt 	if (buf == NULL)
201*a1157835SDaniel Fojt 		return NULL;
202*a1157835SDaniel Fojt 
203*a1157835SDaniel Fojt 	triggers = os_zalloc(sizeof(*triggers));
204*a1157835SDaniel Fojt 	if (triggers == NULL)
205*a1157835SDaniel Fojt 		goto out;
206*a1157835SDaniel Fojt 
207*a1157835SDaniel Fojt #define CHECK_TRIGGER(trigger) \
208*a1157835SDaniel Fojt 	wpa_check_wowlan_trigger(start, #trigger,			\
209*a1157835SDaniel Fojt 				  capa->wowlan_triggers.trigger,	\
210*a1157835SDaniel Fojt 				  &triggers->trigger)
211*a1157835SDaniel Fojt 
212*a1157835SDaniel Fojt 	start = buf;
213*a1157835SDaniel Fojt 	while (*start != '\0') {
214*a1157835SDaniel Fojt 		while (isblank((unsigned char) *start))
215*a1157835SDaniel Fojt 			start++;
216*a1157835SDaniel Fojt 		if (*start == '\0')
217*a1157835SDaniel Fojt 			break;
218*a1157835SDaniel Fojt 		end = start;
219*a1157835SDaniel Fojt 		while (!isblank((unsigned char) *end) && *end != '\0')
220*a1157835SDaniel Fojt 			end++;
221*a1157835SDaniel Fojt 		last = *end == '\0';
222*a1157835SDaniel Fojt 		*end = '\0';
223*a1157835SDaniel Fojt 
224*a1157835SDaniel Fojt 		if (!CHECK_TRIGGER(any) &&
225*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(disconnect) &&
226*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(magic_pkt) &&
227*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(gtk_rekey_failure) &&
228*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(eap_identity_req) &&
229*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(four_way_handshake) &&
230*a1157835SDaniel Fojt 		    !CHECK_TRIGGER(rfkill_release)) {
231*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
232*a1157835SDaniel Fojt 				   "Unknown/unsupported wowlan trigger '%s'",
233*a1157835SDaniel Fojt 				   start);
234*a1157835SDaniel Fojt 			os_free(triggers);
235*a1157835SDaniel Fojt 			triggers = NULL;
236*a1157835SDaniel Fojt 			goto out;
237*a1157835SDaniel Fojt 		}
238*a1157835SDaniel Fojt 
239*a1157835SDaniel Fojt 		if (last)
240*a1157835SDaniel Fojt 			break;
241*a1157835SDaniel Fojt 		start = end + 1;
242*a1157835SDaniel Fojt 	}
243*a1157835SDaniel Fojt #undef CHECK_TRIGGER
244*a1157835SDaniel Fojt 
245*a1157835SDaniel Fojt out:
246*a1157835SDaniel Fojt 	os_free(buf);
247*a1157835SDaniel Fojt 	return triggers;
248*a1157835SDaniel Fojt }
249*a1157835SDaniel Fojt 
250*a1157835SDaniel Fojt 
driver_flag_to_string(u64 flag)251*a1157835SDaniel Fojt const char * driver_flag_to_string(u64 flag)
252*a1157835SDaniel Fojt {
253*a1157835SDaniel Fojt #define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x
254*a1157835SDaniel Fojt 	switch (flag) {
255*a1157835SDaniel Fojt 	DF2S(DRIVER_IE);
256*a1157835SDaniel Fojt 	DF2S(SET_KEYS_AFTER_ASSOC);
257*a1157835SDaniel Fojt 	DF2S(DFS_OFFLOAD);
258*a1157835SDaniel Fojt 	DF2S(4WAY_HANDSHAKE_PSK);
259*a1157835SDaniel Fojt 	DF2S(4WAY_HANDSHAKE_8021X);
260*a1157835SDaniel Fojt 	DF2S(WIRED);
261*a1157835SDaniel Fojt 	DF2S(SME);
262*a1157835SDaniel Fojt 	DF2S(AP);
263*a1157835SDaniel Fojt 	DF2S(SET_KEYS_AFTER_ASSOC_DONE);
264*a1157835SDaniel Fojt 	DF2S(HT_2040_COEX);
265*a1157835SDaniel Fojt 	DF2S(P2P_CONCURRENT);
266*a1157835SDaniel Fojt 	DF2S(P2P_DEDICATED_INTERFACE);
267*a1157835SDaniel Fojt 	DF2S(P2P_CAPABLE);
268*a1157835SDaniel Fojt 	DF2S(AP_TEARDOWN_SUPPORT);
269*a1157835SDaniel Fojt 	DF2S(P2P_MGMT_AND_NON_P2P);
270*a1157835SDaniel Fojt 	DF2S(SANE_ERROR_CODES);
271*a1157835SDaniel Fojt 	DF2S(OFFCHANNEL_TX);
272*a1157835SDaniel Fojt 	DF2S(EAPOL_TX_STATUS);
273*a1157835SDaniel Fojt 	DF2S(DEAUTH_TX_STATUS);
274*a1157835SDaniel Fojt 	DF2S(BSS_SELECTION);
275*a1157835SDaniel Fojt 	DF2S(TDLS_SUPPORT);
276*a1157835SDaniel Fojt 	DF2S(TDLS_EXTERNAL_SETUP);
277*a1157835SDaniel Fojt 	DF2S(PROBE_RESP_OFFLOAD);
278*a1157835SDaniel Fojt 	DF2S(AP_UAPSD);
279*a1157835SDaniel Fojt 	DF2S(INACTIVITY_TIMER);
280*a1157835SDaniel Fojt 	DF2S(AP_MLME);
281*a1157835SDaniel Fojt 	DF2S(SAE);
282*a1157835SDaniel Fojt 	DF2S(OBSS_SCAN);
283*a1157835SDaniel Fojt 	DF2S(IBSS);
284*a1157835SDaniel Fojt 	DF2S(RADAR);
285*a1157835SDaniel Fojt 	DF2S(DEDICATED_P2P_DEVICE);
286*a1157835SDaniel Fojt 	DF2S(QOS_MAPPING);
287*a1157835SDaniel Fojt 	DF2S(AP_CSA);
288*a1157835SDaniel Fojt 	DF2S(MESH);
289*a1157835SDaniel Fojt 	DF2S(ACS_OFFLOAD);
290*a1157835SDaniel Fojt 	DF2S(KEY_MGMT_OFFLOAD);
291*a1157835SDaniel Fojt 	DF2S(TDLS_CHANNEL_SWITCH);
292*a1157835SDaniel Fojt 	DF2S(HT_IBSS);
293*a1157835SDaniel Fojt 	DF2S(VHT_IBSS);
294*a1157835SDaniel Fojt 	DF2S(SUPPORT_HW_MODE_ANY);
295*a1157835SDaniel Fojt 	DF2S(OFFCHANNEL_SIMULTANEOUS);
296*a1157835SDaniel Fojt 	DF2S(FULL_AP_CLIENT_STATE);
297*a1157835SDaniel Fojt 	DF2S(P2P_LISTEN_OFFLOAD);
298*a1157835SDaniel Fojt 	DF2S(SUPPORT_FILS);
299*a1157835SDaniel Fojt 	DF2S(BEACON_RATE_LEGACY);
300*a1157835SDaniel Fojt 	DF2S(BEACON_RATE_HT);
301*a1157835SDaniel Fojt 	DF2S(BEACON_RATE_VHT);
302*a1157835SDaniel Fojt 	DF2S(MGMT_TX_RANDOM_TA);
303*a1157835SDaniel Fojt 	DF2S(MGMT_TX_RANDOM_TA_CONNECTED);
304*a1157835SDaniel Fojt 	DF2S(SCHED_SCAN_RELATIVE_RSSI);
305*a1157835SDaniel Fojt 	DF2S(HE_CAPABILITIES);
306*a1157835SDaniel Fojt 	DF2S(FILS_SK_OFFLOAD);
307*a1157835SDaniel Fojt 	DF2S(OCE_STA);
308*a1157835SDaniel Fojt 	DF2S(OCE_AP);
309*a1157835SDaniel Fojt 	DF2S(OCE_STA_CFON);
310*a1157835SDaniel Fojt 	DF2S(MFP_OPTIONAL);
311*a1157835SDaniel Fojt 	}
312*a1157835SDaniel Fojt 	return "UNKNOWN";
313*a1157835SDaniel Fojt #undef DF2S
314*a1157835SDaniel Fojt }
315