1214501Srpaulo/*
2214501Srpaulo * hostapd - Driver operations
3214501Srpaulo * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#include "utils/common.h"
12214501Srpaulo#include "common/ieee802_11_defs.h"
13281806Srpaulo#include "common/hw_features_common.h"
14252726Srpaulo#include "wps/wps.h"
15252726Srpaulo#include "p2p/p2p.h"
16214501Srpaulo#include "hostapd.h"
17214501Srpaulo#include "ieee802_11.h"
18214501Srpaulo#include "sta_info.h"
19214501Srpaulo#include "ap_config.h"
20252726Srpaulo#include "p2p_hostapd.h"
21252726Srpaulo#include "hs20.h"
22346981Scy#include "wpa_auth.h"
23214501Srpaulo#include "ap_drv_ops.h"
24214501Srpaulo
25214501Srpaulo
26252726Srpaulou32 hostapd_sta_flags_to_drv(u32 flags)
27214501Srpaulo{
28214501Srpaulo	int res = 0;
29214501Srpaulo	if (flags & WLAN_STA_AUTHORIZED)
30214501Srpaulo		res |= WPA_STA_AUTHORIZED;
31214501Srpaulo	if (flags & WLAN_STA_WMM)
32214501Srpaulo		res |= WPA_STA_WMM;
33214501Srpaulo	if (flags & WLAN_STA_SHORT_PREAMBLE)
34214501Srpaulo		res |= WPA_STA_SHORT_PREAMBLE;
35214501Srpaulo	if (flags & WLAN_STA_MFP)
36214501Srpaulo		res |= WPA_STA_MFP;
37337817Scy	if (flags & WLAN_STA_AUTH)
38337817Scy		res |= WPA_STA_AUTHENTICATED;
39337817Scy	if (flags & WLAN_STA_ASSOC)
40337817Scy		res |= WPA_STA_ASSOCIATED;
41214501Srpaulo	return res;
42214501Srpaulo}
43214501Srpaulo
44214501Srpaulo
45337817Scystatic int add_buf(struct wpabuf **dst, const struct wpabuf *src)
46337817Scy{
47337817Scy	if (!src)
48337817Scy		return 0;
49337817Scy	if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
50337817Scy		return -1;
51337817Scy	wpabuf_put_buf(*dst, src);
52337817Scy	return 0;
53337817Scy}
54337817Scy
55337817Scy
56337817Scystatic int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
57337817Scy{
58337817Scy	if (!data || !len)
59337817Scy		return 0;
60337817Scy	if (wpabuf_resize(dst, len) != 0)
61337817Scy		return -1;
62337817Scy	wpabuf_put_data(*dst, data, len);
63337817Scy	return 0;
64337817Scy}
65337817Scy
66337817Scy
67252726Srpauloint hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
68252726Srpaulo			       struct wpabuf **beacon_ret,
69252726Srpaulo			       struct wpabuf **proberesp_ret,
70252726Srpaulo			       struct wpabuf **assocresp_ret)
71214501Srpaulo{
72252726Srpaulo	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
73252726Srpaulo	u8 buf[200], *pos;
74214501Srpaulo
75252726Srpaulo	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
76214501Srpaulo
77252726Srpaulo	pos = buf;
78252726Srpaulo	pos = hostapd_eid_time_adv(hapd, pos);
79337817Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0)
80337817Scy		goto fail;
81252726Srpaulo	pos = hostapd_eid_time_zone(hapd, pos);
82337817Scy	if (add_buf_data(&proberesp, buf, pos - buf) < 0)
83337817Scy		goto fail;
84214501Srpaulo
85252726Srpaulo	pos = buf;
86252726Srpaulo	pos = hostapd_eid_ext_capab(hapd, pos);
87337817Scy	if (add_buf_data(&assocresp, buf, pos - buf) < 0)
88337817Scy		goto fail;
89252726Srpaulo	pos = hostapd_eid_interworking(hapd, pos);
90252726Srpaulo	pos = hostapd_eid_adv_proto(hapd, pos);
91252726Srpaulo	pos = hostapd_eid_roaming_consortium(hapd, pos);
92337817Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
93337817Scy	    add_buf_data(&proberesp, buf, pos - buf) < 0)
94337817Scy		goto fail;
95214501Srpaulo
96289549Srpaulo#ifdef CONFIG_FST
97337817Scy	if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
98337817Scy	    add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
99337817Scy	    add_buf(&assocresp, hapd->iface->fst_ies) < 0)
100337817Scy		goto fail;
101289549Srpaulo#endif /* CONFIG_FST */
102289549Srpaulo
103346981Scy#ifdef CONFIG_FILS
104346981Scy	pos = hostapd_eid_fils_indic(hapd, buf, 0);
105346981Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
106346981Scy	    add_buf_data(&proberesp, buf, pos - buf) < 0)
107346981Scy		goto fail;
108346981Scy#endif /* CONFIG_FILS */
109346981Scy
110337817Scy	if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
111337817Scy	    add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
112337817Scy		goto fail;
113252726Srpaulo
114252726Srpaulo#ifdef CONFIG_P2P
115337817Scy	if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
116337817Scy	    add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
117337817Scy		goto fail;
118252726Srpaulo#endif /* CONFIG_P2P */
119252726Srpaulo
120252726Srpaulo#ifdef CONFIG_P2P_MANAGER
121252726Srpaulo	if (hapd->conf->p2p & P2P_MANAGE) {
122252726Srpaulo		if (wpabuf_resize(&beacon, 100) == 0) {
123252726Srpaulo			u8 *start, *p;
124252726Srpaulo			start = wpabuf_put(beacon, 0);
125252726Srpaulo			p = hostapd_eid_p2p_manage(hapd, start);
126252726Srpaulo			wpabuf_put(beacon, p - start);
127252726Srpaulo		}
128252726Srpaulo
129252726Srpaulo		if (wpabuf_resize(&proberesp, 100) == 0) {
130252726Srpaulo			u8 *start, *p;
131252726Srpaulo			start = wpabuf_put(proberesp, 0);
132252726Srpaulo			p = hostapd_eid_p2p_manage(hapd, start);
133252726Srpaulo			wpabuf_put(proberesp, p - start);
134252726Srpaulo		}
135252726Srpaulo	}
136252726Srpaulo#endif /* CONFIG_P2P_MANAGER */
137252726Srpaulo
138281806Srpaulo#ifdef CONFIG_WPS
139252726Srpaulo	if (hapd->conf->wps_state) {
140252726Srpaulo		struct wpabuf *a = wps_build_assoc_resp_ie();
141337817Scy		add_buf(&assocresp, a);
142252726Srpaulo		wpabuf_free(a);
143252726Srpaulo	}
144281806Srpaulo#endif /* CONFIG_WPS */
145252726Srpaulo
146252726Srpaulo#ifdef CONFIG_P2P_MANAGER
147252726Srpaulo	if (hapd->conf->p2p & P2P_MANAGE) {
148252726Srpaulo		if (wpabuf_resize(&assocresp, 100) == 0) {
149252726Srpaulo			u8 *start, *p;
150252726Srpaulo			start = wpabuf_put(assocresp, 0);
151252726Srpaulo			p = hostapd_eid_p2p_manage(hapd, start);
152252726Srpaulo			wpabuf_put(assocresp, p - start);
153252726Srpaulo		}
154252726Srpaulo	}
155252726Srpaulo#endif /* CONFIG_P2P_MANAGER */
156252726Srpaulo
157252726Srpaulo#ifdef CONFIG_WIFI_DISPLAY
158252726Srpaulo	if (hapd->p2p_group) {
159252726Srpaulo		struct wpabuf *a;
160252726Srpaulo		a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
161337817Scy		add_buf(&assocresp, a);
162252726Srpaulo		wpabuf_free(a);
163252726Srpaulo	}
164252726Srpaulo#endif /* CONFIG_WIFI_DISPLAY */
165252726Srpaulo
166252726Srpaulo#ifdef CONFIG_HS20
167337817Scy	pos = hostapd_eid_hs20_indication(hapd, buf);
168337817Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
169337817Scy	    add_buf_data(&proberesp, buf, pos - buf) < 0)
170337817Scy		goto fail;
171252726Srpaulo
172281806Srpaulo	pos = hostapd_eid_osen(hapd, buf);
173337817Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
174337817Scy	    add_buf_data(&proberesp, buf, pos - buf) < 0)
175337817Scy		goto fail;
176337817Scy#endif /* CONFIG_HS20 */
177281806Srpaulo
178337817Scy#ifdef CONFIG_MBO
179346981Scy	if (hapd->conf->mbo_enabled ||
180346981Scy	    OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
181337817Scy		pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
182337817Scy		if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
183337817Scy		    add_buf_data(&proberesp, buf, pos - buf) < 0 ||
184337817Scy		    add_buf_data(&assocresp, buf, pos - buf) < 0)
185281806Srpaulo			goto fail;
186281806Srpaulo	}
187337817Scy#endif /* CONFIG_MBO */
188252726Srpaulo
189346981Scy#ifdef CONFIG_OWE
190346981Scy	pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
191346981Scy	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
192346981Scy	    add_buf_data(&proberesp, buf, pos - buf) < 0)
193346981Scy		goto fail;
194346981Scy#endif /* CONFIG_OWE */
195346981Scy
196337817Scy	add_buf(&beacon, hapd->conf->vendor_elements);
197337817Scy	add_buf(&proberesp, hapd->conf->vendor_elements);
198337817Scy	add_buf(&assocresp, hapd->conf->assocresp_elements);
199281806Srpaulo
200252726Srpaulo	*beacon_ret = beacon;
201252726Srpaulo	*proberesp_ret = proberesp;
202252726Srpaulo	*assocresp_ret = assocresp;
203252726Srpaulo
204252726Srpaulo	return 0;
205252726Srpaulo
206252726Srpaulofail:
207252726Srpaulo	wpabuf_free(beacon);
208252726Srpaulo	wpabuf_free(proberesp);
209252726Srpaulo	wpabuf_free(assocresp);
210252726Srpaulo	return -1;
211214501Srpaulo}
212214501Srpaulo
213214501Srpaulo
214252726Srpaulovoid hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
215252726Srpaulo			       struct wpabuf *beacon,
216252726Srpaulo			       struct wpabuf *proberesp,
217252726Srpaulo			       struct wpabuf *assocresp)
218214501Srpaulo{
219252726Srpaulo	wpabuf_free(beacon);
220252726Srpaulo	wpabuf_free(proberesp);
221252726Srpaulo	wpabuf_free(assocresp);
222214501Srpaulo}
223214501Srpaulo
224214501Srpaulo
225289549Srpauloint hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
226289549Srpaulo{
227289549Srpaulo	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
228289549Srpaulo		return 0;
229289549Srpaulo
230289549Srpaulo	return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
231289549Srpaulo}
232289549Srpaulo
233289549Srpaulo
234252726Srpauloint hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
235214501Srpaulo{
236252726Srpaulo	struct wpabuf *beacon, *proberesp, *assocresp;
237252726Srpaulo	int ret;
238252726Srpaulo
239252726Srpaulo	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
240214501Srpaulo		return 0;
241252726Srpaulo
242252726Srpaulo	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
243252726Srpaulo	    0)
244252726Srpaulo		return -1;
245252726Srpaulo
246252726Srpaulo	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
247252726Srpaulo					  assocresp);
248252726Srpaulo
249252726Srpaulo	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
250252726Srpaulo
251252726Srpaulo	return ret;
252214501Srpaulo}
253214501Srpaulo
254214501Srpaulo
255252726Srpauloint hostapd_set_authorized(struct hostapd_data *hapd,
256252726Srpaulo			   struct sta_info *sta, int authorized)
257214501Srpaulo{
258214501Srpaulo	if (authorized) {
259214501Srpaulo		return hostapd_sta_set_flags(hapd, sta->addr,
260214501Srpaulo					     hostapd_sta_flags_to_drv(
261214501Srpaulo						     sta->flags),
262214501Srpaulo					     WPA_STA_AUTHORIZED, ~0);
263214501Srpaulo	}
264214501Srpaulo
265214501Srpaulo	return hostapd_sta_set_flags(hapd, sta->addr,
266214501Srpaulo				     hostapd_sta_flags_to_drv(sta->flags),
267214501Srpaulo				     0, ~WPA_STA_AUTHORIZED);
268214501Srpaulo}
269214501Srpaulo
270214501Srpaulo
271252726Srpauloint hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
272214501Srpaulo{
273214501Srpaulo	int set_flags, total_flags, flags_and, flags_or;
274214501Srpaulo	total_flags = hostapd_sta_flags_to_drv(sta->flags);
275214501Srpaulo	set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
276214501Srpaulo	if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
277214501Srpaulo	     sta->auth_alg == WLAN_AUTH_FT) &&
278214501Srpaulo	    sta->flags & WLAN_STA_AUTHORIZED)
279214501Srpaulo		set_flags |= WPA_STA_AUTHORIZED;
280214501Srpaulo	flags_or = total_flags & set_flags;
281214501Srpaulo	flags_and = total_flags | ~set_flags;
282214501Srpaulo	return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
283214501Srpaulo				     flags_or, flags_and);
284214501Srpaulo}
285214501Srpaulo
286214501Srpaulo
287252726Srpauloint hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
288252726Srpaulo			      int enabled)
289214501Srpaulo{
290214501Srpaulo	struct wpa_bss_params params;
291214501Srpaulo	os_memset(&params, 0, sizeof(params));
292214501Srpaulo	params.ifname = ifname;
293214501Srpaulo	params.enabled = enabled;
294214501Srpaulo	if (enabled) {
295214501Srpaulo		params.wpa = hapd->conf->wpa;
296214501Srpaulo		params.ieee802_1x = hapd->conf->ieee802_1x;
297214501Srpaulo		params.wpa_group = hapd->conf->wpa_group;
298289549Srpaulo		if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
299289549Srpaulo		    (WPA_PROTO_WPA | WPA_PROTO_RSN))
300289549Srpaulo			params.wpa_pairwise = hapd->conf->wpa_pairwise |
301289549Srpaulo				hapd->conf->rsn_pairwise;
302289549Srpaulo		else if (hapd->conf->wpa & WPA_PROTO_RSN)
303289549Srpaulo			params.wpa_pairwise = hapd->conf->rsn_pairwise;
304289549Srpaulo		else if (hapd->conf->wpa & WPA_PROTO_WPA)
305289549Srpaulo			params.wpa_pairwise = hapd->conf->wpa_pairwise;
306214501Srpaulo		params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
307214501Srpaulo		params.rsn_preauth = hapd->conf->rsn_preauth;
308252726Srpaulo#ifdef CONFIG_IEEE80211W
309252726Srpaulo		params.ieee80211w = hapd->conf->ieee80211w;
310252726Srpaulo#endif /* CONFIG_IEEE80211W */
311214501Srpaulo	}
312214501Srpaulo	return hostapd_set_ieee8021x(hapd, &params);
313214501Srpaulo}
314214501Srpaulo
315214501Srpaulo
316252726Srpauloint hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
317214501Srpaulo{
318214501Srpaulo	char force_ifname[IFNAMSIZ];
319214501Srpaulo	u8 if_addr[ETH_ALEN];
320252726Srpaulo	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
321281806Srpaulo			      NULL, NULL, force_ifname, if_addr, NULL, 0);
322214501Srpaulo}
323214501Srpaulo
324252726Srpaulo
325252726Srpauloint hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
326214501Srpaulo{
327214501Srpaulo	return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
328214501Srpaulo}
329214501Srpaulo
330214501Srpaulo
331281806Srpauloint hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
332281806Srpaulo			const u8 *addr, int aid, int val)
333214501Srpaulo{
334252726Srpaulo	const char *bridge = NULL;
335252726Srpaulo
336214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
337281806Srpaulo		return -1;
338252726Srpaulo	if (hapd->conf->wds_bridge[0])
339252726Srpaulo		bridge = hapd->conf->wds_bridge;
340252726Srpaulo	else if (hapd->conf->bridge[0])
341252726Srpaulo		bridge = hapd->conf->bridge;
342252726Srpaulo	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
343281806Srpaulo					 bridge, ifname_wds);
344214501Srpaulo}
345214501Srpaulo
346214501Srpaulo
347252726Srpauloint hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
348252726Srpaulo			 u16 auth_alg)
349214501Srpaulo{
350252726Srpaulo	if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
351214501Srpaulo		return 0;
352252726Srpaulo	return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
353214501Srpaulo}
354214501Srpaulo
355214501Srpaulo
356252726Srpauloint hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
357252726Srpaulo		     u16 seq, u16 status, const u8 *ie, size_t len)
358214501Srpaulo{
359346981Scy	struct wpa_driver_sta_auth_params params;
360346981Scy#ifdef CONFIG_FILS
361346981Scy	struct sta_info *sta;
362346981Scy#endif /* CONFIG_FILS */
363346981Scy
364252726Srpaulo	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
365214501Srpaulo		return 0;
366346981Scy
367346981Scy	os_memset(&params, 0, sizeof(params));
368346981Scy
369346981Scy#ifdef CONFIG_FILS
370346981Scy	sta = ap_get_sta(hapd, addr);
371346981Scy	if (!sta) {
372346981Scy		wpa_printf(MSG_DEBUG, "Station " MACSTR
373346981Scy			   " not found for sta_auth processing",
374346981Scy			   MAC2STR(addr));
375346981Scy		return 0;
376346981Scy	}
377346981Scy
378346981Scy	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
379346981Scy	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
380346981Scy	    sta->auth_alg == WLAN_AUTH_FILS_PK) {
381346981Scy		params.fils_auth = 1;
382346981Scy		wpa_auth_get_fils_aead_params(sta->wpa_sm, params.fils_anonce,
383346981Scy					      params.fils_snonce,
384346981Scy					      params.fils_kek,
385346981Scy					      &params.fils_kek_len);
386346981Scy	}
387346981Scy#endif /* CONFIG_FILS */
388346981Scy
389346981Scy	params.own_addr = hapd->own_addr;
390346981Scy	params.addr = addr;
391346981Scy	params.seq = seq;
392346981Scy	params.status = status;
393346981Scy	params.ie = ie;
394346981Scy	params.len = len;
395346981Scy
396346981Scy	return hapd->driver->sta_auth(hapd->drv_priv, &params);
397214501Srpaulo}
398214501Srpaulo
399214501Srpaulo
400252726Srpauloint hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
401252726Srpaulo		      int reassoc, u16 status, const u8 *ie, size_t len)
402214501Srpaulo{
403252726Srpaulo	if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
404214501Srpaulo		return 0;
405252726Srpaulo	return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
406252726Srpaulo				       reassoc, status, ie, len);
407214501Srpaulo}
408214501Srpaulo
409214501Srpaulo
410252726Srpauloint hostapd_sta_add(struct hostapd_data *hapd,
411252726Srpaulo		    const u8 *addr, u16 aid, u16 capability,
412252726Srpaulo		    const u8 *supp_rates, size_t supp_rates_len,
413252726Srpaulo		    u16 listen_interval,
414252726Srpaulo		    const struct ieee80211_ht_capabilities *ht_capab,
415281806Srpaulo		    const struct ieee80211_vht_capabilities *vht_capab,
416351611Scy		    const struct ieee80211_he_capabilities *he_capab,
417351611Scy		    size_t he_capab_len,
418337817Scy		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
419337817Scy		    int set)
420214501Srpaulo{
421214501Srpaulo	struct hostapd_sta_add_params params;
422214501Srpaulo
423214501Srpaulo	if (hapd->driver == NULL)
424214501Srpaulo		return 0;
425214501Srpaulo	if (hapd->driver->sta_add == NULL)
426214501Srpaulo		return 0;
427214501Srpaulo
428214501Srpaulo	os_memset(&params, 0, sizeof(params));
429214501Srpaulo	params.addr = addr;
430214501Srpaulo	params.aid = aid;
431214501Srpaulo	params.capability = capability;
432214501Srpaulo	params.supp_rates = supp_rates;
433214501Srpaulo	params.supp_rates_len = supp_rates_len;
434214501Srpaulo	params.listen_interval = listen_interval;
435214501Srpaulo	params.ht_capabilities = ht_capab;
436281806Srpaulo	params.vht_capabilities = vht_capab;
437351611Scy	params.he_capab = he_capab;
438351611Scy	params.he_capab_len = he_capab_len;
439281806Srpaulo	params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
440281806Srpaulo	params.vht_opmode = vht_opmode;
441252726Srpaulo	params.flags = hostapd_sta_flags_to_drv(flags);
442252726Srpaulo	params.qosinfo = qosinfo;
443337817Scy	params.support_p2p_ps = supp_p2p_ps;
444337817Scy	params.set = set;
445214501Srpaulo	return hapd->driver->sta_add(hapd->drv_priv, &params);
446214501Srpaulo}
447214501Srpaulo
448214501Srpaulo
449252726Srpauloint hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
450252726Srpaulo		      u8 *tspec_ie, size_t tspec_ielen)
451214501Srpaulo{
452252726Srpaulo	if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
453214501Srpaulo		return 0;
454252726Srpaulo	return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
455252726Srpaulo				       tspec_ielen);
456214501Srpaulo}
457214501Srpaulo
458214501Srpaulo
459214501Srpauloint hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
460214501Srpaulo{
461214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
462214501Srpaulo		return 0;
463214501Srpaulo	return hapd->driver->set_privacy(hapd->drv_priv, enabled);
464214501Srpaulo}
465214501Srpaulo
466214501Srpaulo
467214501Srpauloint hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
468214501Srpaulo			     size_t elem_len)
469214501Srpaulo{
470214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
471214501Srpaulo		return 0;
472214501Srpaulo	return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len);
473214501Srpaulo}
474214501Srpaulo
475214501Srpaulo
476214501Srpauloint hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
477214501Srpaulo{
478214501Srpaulo	if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
479214501Srpaulo		return 0;
480214501Srpaulo	return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
481214501Srpaulo}
482214501Srpaulo
483214501Srpaulo
484214501Srpauloint hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
485214501Srpaulo{
486214501Srpaulo	if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
487214501Srpaulo		return 0;
488214501Srpaulo	return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
489214501Srpaulo}
490214501Srpaulo
491214501Srpaulo
492214501Srpauloint hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
493214501Srpaulo		   const char *ifname, const u8 *addr, void *bss_ctx,
494252726Srpaulo		   void **drv_priv, char *force_ifname, u8 *if_addr,
495281806Srpaulo		   const char *bridge, int use_existing)
496214501Srpaulo{
497214501Srpaulo	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
498214501Srpaulo		return -1;
499214501Srpaulo	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
500252726Srpaulo				    bss_ctx, drv_priv, force_ifname, if_addr,
501337817Scy				    bridge, use_existing, 1);
502214501Srpaulo}
503214501Srpaulo
504214501Srpaulo
505214501Srpauloint hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
506214501Srpaulo		      const char *ifname)
507214501Srpaulo{
508281806Srpaulo	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
509281806Srpaulo	    hapd->driver->if_remove == NULL)
510214501Srpaulo		return -1;
511214501Srpaulo	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
512214501Srpaulo}
513214501Srpaulo
514214501Srpaulo
515214501Srpauloint hostapd_set_ieee8021x(struct hostapd_data *hapd,
516214501Srpaulo			  struct wpa_bss_params *params)
517214501Srpaulo{
518214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
519214501Srpaulo		return 0;
520214501Srpaulo	return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
521214501Srpaulo}
522214501Srpaulo
523214501Srpaulo
524214501Srpauloint hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
525214501Srpaulo		       const u8 *addr, int idx, u8 *seq)
526214501Srpaulo{
527214501Srpaulo	if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
528214501Srpaulo		return 0;
529214501Srpaulo	return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
530214501Srpaulo					seq);
531214501Srpaulo}
532214501Srpaulo
533214501Srpaulo
534214501Srpauloint hostapd_flush(struct hostapd_data *hapd)
535214501Srpaulo{
536214501Srpaulo	if (hapd->driver == NULL || hapd->driver->flush == NULL)
537214501Srpaulo		return 0;
538214501Srpaulo	return hapd->driver->flush(hapd->drv_priv);
539214501Srpaulo}
540214501Srpaulo
541214501Srpaulo
542281806Srpauloint hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
543281806Srpaulo		     int freq, int channel, int ht_enabled, int vht_enabled,
544351611Scy		     int he_enabled,
545351611Scy		     int sec_channel_offset, int oper_chwidth,
546281806Srpaulo		     int center_segment0, int center_segment1)
547214501Srpaulo{
548214501Srpaulo	struct hostapd_freq_params data;
549351611Scy	struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
550281806Srpaulo
551281806Srpaulo	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
552351611Scy				    vht_enabled, he_enabled, sec_channel_offset,
553351611Scy				    oper_chwidth,
554281806Srpaulo				    center_segment0, center_segment1,
555351611Scy				    cmode ? cmode->vht_capab : 0,
556351611Scy				    cmode ?
557351611Scy				    &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
558281806Srpaulo		return -1;
559281806Srpaulo
560214501Srpaulo	if (hapd->driver == NULL)
561214501Srpaulo		return 0;
562214501Srpaulo	if (hapd->driver->set_freq == NULL)
563214501Srpaulo		return 0;
564214501Srpaulo	return hapd->driver->set_freq(hapd->drv_priv, &data);
565214501Srpaulo}
566214501Srpaulo
567214501Srpauloint hostapd_set_rts(struct hostapd_data *hapd, int rts)
568214501Srpaulo{
569214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
570214501Srpaulo		return 0;
571214501Srpaulo	return hapd->driver->set_rts(hapd->drv_priv, rts);
572214501Srpaulo}
573214501Srpaulo
574214501Srpaulo
575214501Srpauloint hostapd_set_frag(struct hostapd_data *hapd, int frag)
576214501Srpaulo{
577214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
578214501Srpaulo		return 0;
579214501Srpaulo	return hapd->driver->set_frag(hapd->drv_priv, frag);
580214501Srpaulo}
581214501Srpaulo
582214501Srpaulo
583214501Srpauloint hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
584214501Srpaulo			  int total_flags, int flags_or, int flags_and)
585214501Srpaulo{
586214501Srpaulo	if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
587214501Srpaulo		return 0;
588214501Srpaulo	return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
589214501Srpaulo					   flags_or, flags_and);
590214501Srpaulo}
591214501Srpaulo
592214501Srpaulo
593351611Scyint hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
594351611Scy				   unsigned int weight)
595351611Scy{
596351611Scy	if (!hapd->driver || !hapd->driver->sta_set_airtime_weight)
597351611Scy		return 0;
598351611Scy	return hapd->driver->sta_set_airtime_weight(hapd->drv_priv, addr,
599351611Scy						    weight);
600351611Scy}
601351611Scy
602351611Scy
603214501Srpauloint hostapd_set_country(struct hostapd_data *hapd, const char *country)
604214501Srpaulo{
605214501Srpaulo	if (hapd->driver == NULL ||
606214501Srpaulo	    hapd->driver->set_country == NULL)
607214501Srpaulo		return 0;
608214501Srpaulo	return hapd->driver->set_country(hapd->drv_priv, country);
609214501Srpaulo}
610214501Srpaulo
611214501Srpaulo
612214501Srpauloint hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
613214501Srpaulo				int cw_min, int cw_max, int burst_time)
614214501Srpaulo{
615214501Srpaulo	if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
616214501Srpaulo		return 0;
617214501Srpaulo	return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
618214501Srpaulo						 cw_min, cw_max, burst_time);
619214501Srpaulo}
620214501Srpaulo
621214501Srpaulo
622214501Srpaulostruct hostapd_hw_modes *
623214501Srpaulohostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
624346981Scy			    u16 *flags, u8 *dfs_domain)
625214501Srpaulo{
626214501Srpaulo	if (hapd->driver == NULL ||
627214501Srpaulo	    hapd->driver->get_hw_feature_data == NULL)
628214501Srpaulo		return NULL;
629214501Srpaulo	return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
630346981Scy						 flags, dfs_domain);
631214501Srpaulo}
632214501Srpaulo
633214501Srpaulo
634214501Srpauloint hostapd_driver_commit(struct hostapd_data *hapd)
635214501Srpaulo{
636214501Srpaulo	if (hapd->driver == NULL || hapd->driver->commit == NULL)
637214501Srpaulo		return 0;
638214501Srpaulo	return hapd->driver->commit(hapd->drv_priv);
639214501Srpaulo}
640214501Srpaulo
641214501Srpaulo
642214501Srpauloint hostapd_drv_none(struct hostapd_data *hapd)
643214501Srpaulo{
644214501Srpaulo	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
645214501Srpaulo}
646214501Srpaulo
647214501Srpaulo
648214501Srpauloint hostapd_driver_scan(struct hostapd_data *hapd,
649214501Srpaulo			struct wpa_driver_scan_params *params)
650214501Srpaulo{
651214501Srpaulo	if (hapd->driver && hapd->driver->scan2)
652214501Srpaulo		return hapd->driver->scan2(hapd->drv_priv, params);
653214501Srpaulo	return -1;
654214501Srpaulo}
655214501Srpaulo
656214501Srpaulo
657214501Srpaulostruct wpa_scan_results * hostapd_driver_get_scan_results(
658214501Srpaulo	struct hostapd_data *hapd)
659214501Srpaulo{
660214501Srpaulo	if (hapd->driver && hapd->driver->get_scan_results2)
661214501Srpaulo		return hapd->driver->get_scan_results2(hapd->drv_priv);
662214501Srpaulo	return NULL;
663214501Srpaulo}
664252726Srpaulo
665252726Srpaulo
666252726Srpauloint hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
667252726Srpaulo			   int duration)
668252726Srpaulo{
669252726Srpaulo	if (hapd->driver && hapd->driver->set_noa)
670252726Srpaulo		return hapd->driver->set_noa(hapd->drv_priv, count, start,
671252726Srpaulo					     duration);
672252726Srpaulo	return -1;
673252726Srpaulo}
674252726Srpaulo
675252726Srpaulo
676252726Srpauloint hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
677252726Srpaulo			enum wpa_alg alg, const u8 *addr,
678252726Srpaulo			int key_idx, int set_tx,
679252726Srpaulo			const u8 *seq, size_t seq_len,
680252726Srpaulo			const u8 *key, size_t key_len)
681252726Srpaulo{
682252726Srpaulo	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
683252726Srpaulo		return 0;
684252726Srpaulo	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
685252726Srpaulo				     key_idx, set_tx, seq, seq_len, key,
686252726Srpaulo				     key_len);
687252726Srpaulo}
688252726Srpaulo
689252726Srpaulo
690252726Srpauloint hostapd_drv_send_mlme(struct hostapd_data *hapd,
691252726Srpaulo			  const void *msg, size_t len, int noack)
692252726Srpaulo{
693337817Scy	if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
694337817Scy		return 0;
695337817Scy	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
696337817Scy				       NULL, 0);
697337817Scy}
698337817Scy
699337817Scy
700337817Scyint hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
701337817Scy			      const void *msg, size_t len, int noack,
702337817Scy			      const u16 *csa_offs, size_t csa_offs_len)
703337817Scy{
704252726Srpaulo	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
705252726Srpaulo		return 0;
706337817Scy	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
707337817Scy				       csa_offs, csa_offs_len);
708252726Srpaulo}
709252726Srpaulo
710252726Srpaulo
711252726Srpauloint hostapd_drv_sta_deauth(struct hostapd_data *hapd,
712252726Srpaulo			   const u8 *addr, int reason)
713252726Srpaulo{
714337817Scy	if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
715252726Srpaulo		return 0;
716252726Srpaulo	return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
717252726Srpaulo					reason);
718252726Srpaulo}
719252726Srpaulo
720252726Srpaulo
721252726Srpauloint hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
722252726Srpaulo			     const u8 *addr, int reason)
723252726Srpaulo{
724337817Scy	if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
725252726Srpaulo		return 0;
726252726Srpaulo	return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
727252726Srpaulo					  reason);
728252726Srpaulo}
729252726Srpaulo
730252726Srpaulo
731252726Srpauloint hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
732252726Srpaulo			 const u8 *peer, u8 *buf, u16 *buf_len)
733252726Srpaulo{
734252726Srpaulo	if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
735281806Srpaulo		return -1;
736252726Srpaulo	return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
737252726Srpaulo				      buf_len);
738252726Srpaulo}
739252726Srpaulo
740252726Srpaulo
741252726Srpauloint hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
742252726Srpaulo			    unsigned int wait, const u8 *dst, const u8 *data,
743252726Srpaulo			    size_t len)
744252726Srpaulo{
745337817Scy	const u8 *bssid;
746337817Scy	const u8 wildcard_bssid[ETH_ALEN] = {
747337817Scy		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
748337817Scy	};
749337817Scy
750337817Scy	if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
751337817Scy		return 0;
752337817Scy	bssid = hapd->own_addr;
753337817Scy	if (!is_multicast_ether_addr(dst) &&
754337817Scy	    len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
755337817Scy		struct sta_info *sta;
756337817Scy
757337817Scy		/*
758337817Scy		 * Public Action frames to a STA that is not a member of the BSS
759337817Scy		 * shall use wildcard BSSID value.
760337817Scy		 */
761337817Scy		sta = ap_get_sta(hapd, dst);
762337817Scy		if (!sta || !(sta->flags & WLAN_STA_ASSOC))
763337817Scy			bssid = wildcard_bssid;
764346981Scy	} else if (is_broadcast_ether_addr(dst) &&
765346981Scy		   len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
766346981Scy		/*
767346981Scy		 * The only current use case of Public Action frames with
768346981Scy		 * broadcast destination address is DPP PKEX. That case is
769346981Scy		 * directing all devices and not just the STAs within the BSS,
770346981Scy		 * so have to use the wildcard BSSID value.
771346981Scy		 */
772346981Scy		bssid = wildcard_bssid;
773337817Scy	}
774337817Scy	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
775337817Scy					 hapd->own_addr, bssid, data, len, 0);
776337817Scy}
777337817Scy
778337817Scy
779337817Scyint hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
780337817Scy				     unsigned int freq,
781337817Scy				     unsigned int wait, const u8 *dst,
782337817Scy				     const u8 *data, size_t len)
783337817Scy{
784252726Srpaulo	if (hapd->driver == NULL || hapd->driver->send_action == NULL)
785252726Srpaulo		return 0;
786252726Srpaulo	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
787252726Srpaulo					 hapd->own_addr, hapd->own_addr, data,
788252726Srpaulo					 len, 0);
789252726Srpaulo}
790281806Srpaulo
791281806Srpaulo
792281806Srpauloint hostapd_start_dfs_cac(struct hostapd_iface *iface,
793281806Srpaulo			  enum hostapd_hw_mode mode, int freq,
794281806Srpaulo			  int channel, int ht_enabled, int vht_enabled,
795351611Scy			  int he_enabled,
796351611Scy			  int sec_channel_offset, int oper_chwidth,
797281806Srpaulo			  int center_segment0, int center_segment1)
798281806Srpaulo{
799281806Srpaulo	struct hostapd_data *hapd = iface->bss[0];
800281806Srpaulo	struct hostapd_freq_params data;
801281806Srpaulo	int res;
802351611Scy	struct hostapd_hw_modes *cmode = iface->current_mode;
803281806Srpaulo
804351611Scy	if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
805281806Srpaulo		return 0;
806281806Srpaulo
807281806Srpaulo	if (!iface->conf->ieee80211h) {
808281806Srpaulo		wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality "
809281806Srpaulo			   "is not enabled");
810281806Srpaulo		return -1;
811281806Srpaulo	}
812281806Srpaulo
813281806Srpaulo	if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
814351611Scy				    vht_enabled, he_enabled, sec_channel_offset,
815351611Scy				    oper_chwidth, center_segment0,
816281806Srpaulo				    center_segment1,
817351611Scy				    cmode->vht_capab,
818351611Scy				    &cmode->he_capab[IEEE80211_MODE_AP])) {
819281806Srpaulo		wpa_printf(MSG_ERROR, "Can't set freq params");
820281806Srpaulo		return -1;
821281806Srpaulo	}
822281806Srpaulo
823281806Srpaulo	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
824281806Srpaulo	if (!res) {
825281806Srpaulo		iface->cac_started = 1;
826281806Srpaulo		os_get_reltime(&iface->dfs_cac_start);
827281806Srpaulo	}
828281806Srpaulo
829281806Srpaulo	return res;
830281806Srpaulo}
831281806Srpaulo
832281806Srpaulo
833281806Srpauloint hostapd_drv_set_qos_map(struct hostapd_data *hapd,
834281806Srpaulo			    const u8 *qos_map_set, u8 qos_map_set_len)
835281806Srpaulo{
836337817Scy	if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
837281806Srpaulo		return 0;
838281806Srpaulo	return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
839281806Srpaulo					 qos_map_set_len);
840281806Srpaulo}
841281806Srpaulo
842281806Srpaulo
843289549Srpaulostatic void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
844289549Srpaulo					     struct hostapd_hw_modes *mode,
845289549Srpaulo					     int acs_ch_list_all,
846289549Srpaulo					     int **freq_list)
847289549Srpaulo{
848289549Srpaulo	int i;
849289549Srpaulo
850289549Srpaulo	for (i = 0; i < mode->num_channels; i++) {
851289549Srpaulo		struct hostapd_channel_data *chan = &mode->channels[i];
852289549Srpaulo
853289549Srpaulo		if ((acs_ch_list_all ||
854289549Srpaulo		     freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
855289549Srpaulo					      chan->chan)) &&
856346981Scy		    !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
857346981Scy		    !(hapd->iface->conf->acs_exclude_dfs &&
858346981Scy		      (chan->flag & HOSTAPD_CHAN_RADAR)))
859289549Srpaulo			int_array_add_unique(freq_list, chan->freq);
860289549Srpaulo	}
861289549Srpaulo}
862289549Srpaulo
863289549Srpaulo
864337817Scyvoid hostapd_get_ext_capa(struct hostapd_iface *iface)
865337817Scy{
866337817Scy	struct hostapd_data *hapd = iface->bss[0];
867337817Scy
868337817Scy	if (!hapd->driver || !hapd->driver->get_ext_capab)
869337817Scy		return;
870337817Scy
871337817Scy	hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
872337817Scy				    &iface->extended_capa,
873337817Scy				    &iface->extended_capa_mask,
874337817Scy				    &iface->extended_capa_len);
875337817Scy}
876337817Scy
877337817Scy
878281806Srpauloint hostapd_drv_do_acs(struct hostapd_data *hapd)
879281806Srpaulo{
880281806Srpaulo	struct drv_acs_params params;
881289549Srpaulo	int ret, i, acs_ch_list_all = 0;
882289549Srpaulo	u8 *channels = NULL;
883289549Srpaulo	unsigned int num_channels = 0;
884289549Srpaulo	struct hostapd_hw_modes *mode;
885289549Srpaulo	int *freq_list = NULL;
886281806Srpaulo
887281806Srpaulo	if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
888281806Srpaulo		return 0;
889289549Srpaulo
890281806Srpaulo	os_memset(&params, 0, sizeof(params));
891281806Srpaulo	params.hw_mode = hapd->iface->conf->hw_mode;
892289549Srpaulo
893289549Srpaulo	/*
894289549Srpaulo	 * If no chanlist config parameter is provided, include all enabled
895289549Srpaulo	 * channels of the selected hw_mode.
896289549Srpaulo	 */
897289549Srpaulo	if (!hapd->iface->conf->acs_ch_list.num)
898289549Srpaulo		acs_ch_list_all = 1;
899289549Srpaulo
900289549Srpaulo	mode = hapd->iface->current_mode;
901289549Srpaulo	if (mode) {
902289549Srpaulo		channels = os_malloc(mode->num_channels);
903289549Srpaulo		if (channels == NULL)
904289549Srpaulo			return -1;
905289549Srpaulo
906289549Srpaulo		for (i = 0; i < mode->num_channels; i++) {
907289549Srpaulo			struct hostapd_channel_data *chan = &mode->channels[i];
908289549Srpaulo			if (!acs_ch_list_all &&
909289549Srpaulo			    !freq_range_list_includes(
910289549Srpaulo				    &hapd->iface->conf->acs_ch_list,
911289549Srpaulo				    chan->chan))
912289549Srpaulo				continue;
913346981Scy			if (hapd->iface->conf->acs_exclude_dfs &&
914346981Scy			    (chan->flag & HOSTAPD_CHAN_RADAR))
915346981Scy				continue;
916289549Srpaulo			if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
917289549Srpaulo				channels[num_channels++] = chan->chan;
918289549Srpaulo				int_array_add_unique(&freq_list, chan->freq);
919289549Srpaulo			}
920289549Srpaulo		}
921289549Srpaulo	} else {
922289549Srpaulo		for (i = 0; i < hapd->iface->num_hw_features; i++) {
923289549Srpaulo			mode = &hapd->iface->hw_features[i];
924289549Srpaulo			hostapd_get_hw_mode_any_channels(hapd, mode,
925289549Srpaulo							 acs_ch_list_all,
926289549Srpaulo							 &freq_list);
927289549Srpaulo		}
928289549Srpaulo	}
929289549Srpaulo
930289549Srpaulo	params.ch_list = channels;
931289549Srpaulo	params.ch_list_len = num_channels;
932289549Srpaulo	params.freq_list = freq_list;
933289549Srpaulo
934281806Srpaulo	params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
935281806Srpaulo	params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
936281806Srpaulo				 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
937289549Srpaulo	params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
938289549Srpaulo	params.ch_width = 20;
939289549Srpaulo	if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
940289549Srpaulo		params.ch_width = 40;
941289549Srpaulo
942351611Scy	/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
943289549Srpaulo	 */
944351611Scy	if ((hapd->iface->conf->ieee80211ax ||
945351611Scy	     hapd->iface->conf->ieee80211ac) &&
946351611Scy	    params.ht40_enabled) {
947351611Scy		u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
948351611Scy
949351611Scy		if (oper_chwidth == CHANWIDTH_80MHZ)
950289549Srpaulo			params.ch_width = 80;
951351611Scy		else if (oper_chwidth == CHANWIDTH_160MHZ ||
952351611Scy			 oper_chwidth == CHANWIDTH_80P80MHZ)
953289549Srpaulo			params.ch_width = 160;
954289549Srpaulo	}
955289549Srpaulo
956289549Srpaulo	ret = hapd->driver->do_acs(hapd->drv_priv, &params);
957289549Srpaulo	os_free(channels);
958289549Srpaulo
959289549Srpaulo	return ret;
960281806Srpaulo}
961351611Scy
962351611Scy
963351611Scyint hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
964351611Scy			     u16 reason_code, const u8 *ie, size_t ielen)
965351611Scy{
966351611Scy	if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
967351611Scy		return 0;
968351611Scy	return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
969351611Scy					  ie, ielen);
970351611Scy}
971