]>
Commit | Line | Data |
---|---|---|
bf65bc63 JM |
1 | /* |
2 | * hostapd - Driver operations | |
ef580012 | 3 | * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> |
bf65bc63 | 4 | * |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
bf65bc63 JM |
7 | */ |
8 | ||
8b06c1ed | 9 | #include "utils/includes.h" |
bf65bc63 | 10 | |
8b06c1ed | 11 | #include "utils/common.h" |
ef580012 | 12 | #include "common/ieee802_11_defs.h" |
ada157f3 | 13 | #include "common/hw_features_common.h" |
0e2e565a | 14 | #include "wps/wps.h" |
9675ce35 | 15 | #include "p2p/p2p.h" |
8b06c1ed JM |
16 | #include "hostapd.h" |
17 | #include "ieee802_11.h" | |
18 | #include "sta_info.h" | |
19 | #include "ap_config.h" | |
dce044cc | 20 | #include "p2p_hostapd.h" |
19a8ad99 | 21 | #include "hs20.h" |
a4f21109 | 22 | #include "ap_drv_ops.h" |
bf65bc63 JM |
23 | |
24 | ||
4378fc14 | 25 | u32 hostapd_sta_flags_to_drv(u32 flags) |
4c2ddda4 JM |
26 | { |
27 | int res = 0; | |
28 | if (flags & WLAN_STA_AUTHORIZED) | |
29 | res |= WPA_STA_AUTHORIZED; | |
30 | if (flags & WLAN_STA_WMM) | |
31 | res |= WPA_STA_WMM; | |
32 | if (flags & WLAN_STA_SHORT_PREAMBLE) | |
33 | res |= WPA_STA_SHORT_PREAMBLE; | |
34 | if (flags & WLAN_STA_MFP) | |
35 | res |= WPA_STA_MFP; | |
bb598c3b AB |
36 | if (flags & WLAN_STA_AUTH) |
37 | res |= WPA_STA_AUTHENTICATED; | |
38 | if (flags & WLAN_STA_ASSOC) | |
39 | res |= WPA_STA_ASSOCIATED; | |
4c2ddda4 JM |
40 | return res; |
41 | } | |
42 | ||
43 | ||
990b7b6f JM |
44 | static int add_buf(struct wpabuf **dst, const struct wpabuf *src) |
45 | { | |
46 | if (!src) | |
47 | return 0; | |
48 | if (wpabuf_resize(dst, wpabuf_len(src)) != 0) | |
49 | return -1; | |
50 | wpabuf_put_buf(*dst, src); | |
51 | return 0; | |
52 | } | |
53 | ||
54 | ||
55 | static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len) | |
56 | { | |
57 | if (!data || !len) | |
58 | return 0; | |
59 | if (wpabuf_resize(dst, len) != 0) | |
60 | return -1; | |
61 | wpabuf_put_data(*dst, data, len); | |
62 | return 0; | |
63 | } | |
64 | ||
65 | ||
fb91db56 | 66 | int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, |
c2ff13c5 JM |
67 | struct wpabuf **beacon_ret, |
68 | struct wpabuf **proberesp_ret, | |
69 | struct wpabuf **assocresp_ret) | |
bf65bc63 | 70 | { |
c2ff13c5 | 71 | struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL; |
4b2a77ab | 72 | u8 buf[200], *pos; |
c2ff13c5 JM |
73 | |
74 | *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; | |
75 | ||
39b97072 JM |
76 | pos = buf; |
77 | pos = hostapd_eid_time_adv(hapd, pos); | |
990b7b6f JM |
78 | if (add_buf_data(&beacon, buf, pos - buf) < 0) |
79 | goto fail; | |
39b97072 | 80 | pos = hostapd_eid_time_zone(hapd, pos); |
990b7b6f JM |
81 | if (add_buf_data(&proberesp, buf, pos - buf) < 0) |
82 | goto fail; | |
39b97072 | 83 | |
a194b06c JM |
84 | pos = buf; |
85 | pos = hostapd_eid_ext_capab(hapd, pos); | |
990b7b6f JM |
86 | if (add_buf_data(&assocresp, buf, pos - buf) < 0) |
87 | goto fail; | |
a194b06c | 88 | pos = hostapd_eid_interworking(hapd, pos); |
c7c178e1 | 89 | pos = hostapd_eid_adv_proto(hapd, pos); |
4b2a77ab | 90 | pos = hostapd_eid_roaming_consortium(hapd, pos); |
990b7b6f JM |
91 | if (add_buf_data(&beacon, buf, pos - buf) < 0 || |
92 | add_buf_data(&proberesp, buf, pos - buf) < 0) | |
93 | goto fail; | |
a194b06c | 94 | |
347827ff | 95 | #ifdef CONFIG_FST |
990b7b6f JM |
96 | if (add_buf(&beacon, hapd->iface->fst_ies) < 0 || |
97 | add_buf(&proberesp, hapd->iface->fst_ies) < 0 || | |
98 | add_buf(&assocresp, hapd->iface->fst_ies) < 0) | |
99 | goto fail; | |
347827ff AN |
100 | #endif /* CONFIG_FST */ |
101 | ||
990b7b6f JM |
102 | if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 || |
103 | add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0) | |
104 | goto fail; | |
b3db190f | 105 | |
c2af2afb | 106 | #ifdef CONFIG_P2P |
990b7b6f JM |
107 | if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 || |
108 | add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0) | |
109 | goto fail; | |
c2af2afb JM |
110 | #endif /* CONFIG_P2P */ |
111 | ||
dce044cc JM |
112 | #ifdef CONFIG_P2P_MANAGER |
113 | if (hapd->conf->p2p & P2P_MANAGE) { | |
c2ff13c5 | 114 | if (wpabuf_resize(&beacon, 100) == 0) { |
dce044cc | 115 | u8 *start, *p; |
c2ff13c5 | 116 | start = wpabuf_put(beacon, 0); |
dce044cc | 117 | p = hostapd_eid_p2p_manage(hapd, start); |
c2ff13c5 | 118 | wpabuf_put(beacon, p - start); |
dce044cc JM |
119 | } |
120 | ||
c2ff13c5 | 121 | if (wpabuf_resize(&proberesp, 100) == 0) { |
dce044cc | 122 | u8 *start, *p; |
c2ff13c5 | 123 | start = wpabuf_put(proberesp, 0); |
dce044cc | 124 | p = hostapd_eid_p2p_manage(hapd, start); |
c2ff13c5 | 125 | wpabuf_put(proberesp, p - start); |
dce044cc JM |
126 | } |
127 | } | |
128 | #endif /* CONFIG_P2P_MANAGER */ | |
129 | ||
c201f93a | 130 | #ifdef CONFIG_WPS |
c2ff13c5 JM |
131 | if (hapd->conf->wps_state) { |
132 | struct wpabuf *a = wps_build_assoc_resp_ie(); | |
990b7b6f | 133 | add_buf(&assocresp, a); |
c2ff13c5 JM |
134 | wpabuf_free(a); |
135 | } | |
c201f93a | 136 | #endif /* CONFIG_WPS */ |
0e2e565a | 137 | |
dce044cc JM |
138 | #ifdef CONFIG_P2P_MANAGER |
139 | if (hapd->conf->p2p & P2P_MANAGE) { | |
c2ff13c5 | 140 | if (wpabuf_resize(&assocresp, 100) == 0) { |
dce044cc | 141 | u8 *start, *p; |
c2ff13c5 | 142 | start = wpabuf_put(assocresp, 0); |
dce044cc | 143 | p = hostapd_eid_p2p_manage(hapd, start); |
c2ff13c5 | 144 | wpabuf_put(assocresp, p - start); |
dce044cc JM |
145 | } |
146 | } | |
147 | #endif /* CONFIG_P2P_MANAGER */ | |
148 | ||
9675ce35 JM |
149 | #ifdef CONFIG_WIFI_DISPLAY |
150 | if (hapd->p2p_group) { | |
151 | struct wpabuf *a; | |
152 | a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS); | |
990b7b6f | 153 | add_buf(&assocresp, a); |
9675ce35 JM |
154 | wpabuf_free(a); |
155 | } | |
156 | #endif /* CONFIG_WIFI_DISPLAY */ | |
157 | ||
19a8ad99 | 158 | #ifdef CONFIG_HS20 |
990b7b6f JM |
159 | pos = hostapd_eid_hs20_indication(hapd, buf); |
160 | if (add_buf_data(&beacon, buf, pos - buf) < 0 || | |
161 | add_buf_data(&proberesp, buf, pos - buf) < 0) | |
162 | goto fail; | |
a14896e8 JM |
163 | |
164 | pos = hostapd_eid_osen(hapd, buf); | |
990b7b6f JM |
165 | if (add_buf_data(&beacon, buf, pos - buf) < 0 || |
166 | add_buf_data(&proberesp, buf, pos - buf) < 0) | |
167 | goto fail; | |
19a8ad99 JK |
168 | #endif /* CONFIG_HS20 */ |
169 | ||
fb9a1c3e AS |
170 | #ifdef CONFIG_MBO |
171 | if (hapd->conf->mbo_enabled) { | |
172 | pos = hostapd_eid_mbo(hapd, buf, sizeof(buf)); | |
990b7b6f JM |
173 | if (add_buf_data(&beacon, buf, pos - buf) < 0 || |
174 | add_buf_data(&proberesp, buf, pos - buf) < 0 || | |
175 | add_buf_data(&assocresp, buf, pos - buf) < 0) | |
176 | goto fail; | |
fb9a1c3e AS |
177 | } |
178 | #endif /* CONFIG_MBO */ | |
179 | ||
990b7b6f JM |
180 | add_buf(&beacon, hapd->conf->vendor_elements); |
181 | add_buf(&proberesp, hapd->conf->vendor_elements); | |
a9112270 | 182 | add_buf(&assocresp, hapd->conf->assocresp_elements); |
b084df8b | 183 | |
c2ff13c5 JM |
184 | *beacon_ret = beacon; |
185 | *proberesp_ret = proberesp; | |
186 | *assocresp_ret = assocresp; | |
187 | ||
fb91db56 | 188 | return 0; |
c2ff13c5 JM |
189 | |
190 | fail: | |
191 | wpabuf_free(beacon); | |
192 | wpabuf_free(proberesp); | |
193 | wpabuf_free(assocresp); | |
194 | return -1; | |
fb91db56 JM |
195 | } |
196 | ||
b3db190f | 197 | |
c2ff13c5 JM |
198 | void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, |
199 | struct wpabuf *beacon, | |
fb91db56 JM |
200 | struct wpabuf *proberesp, |
201 | struct wpabuf *assocresp) | |
202 | { | |
c2ff13c5 JM |
203 | wpabuf_free(beacon); |
204 | wpabuf_free(proberesp); | |
0e2e565a | 205 | wpabuf_free(assocresp); |
fb91db56 JM |
206 | } |
207 | ||
208 | ||
1de07100 AKP |
209 | int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd) |
210 | { | |
211 | if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) | |
212 | return 0; | |
213 | ||
214 | return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL); | |
215 | } | |
216 | ||
217 | ||
fb91db56 JM |
218 | int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) |
219 | { | |
220 | struct wpabuf *beacon, *proberesp, *assocresp; | |
221 | int ret; | |
222 | ||
223 | if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) | |
224 | return 0; | |
225 | ||
226 | if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < | |
227 | 0) | |
228 | return -1; | |
229 | ||
230 | ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp, | |
231 | assocresp); | |
232 | ||
233 | hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); | |
c2af2afb | 234 | |
b3db190f | 235 | return ret; |
bf65bc63 JM |
236 | } |
237 | ||
238 | ||
0e8a96a9 JM |
239 | int hostapd_set_authorized(struct hostapd_data *hapd, |
240 | struct sta_info *sta, int authorized) | |
45cefa0b JM |
241 | { |
242 | if (authorized) { | |
243 | return hostapd_sta_set_flags(hapd, sta->addr, | |
244 | hostapd_sta_flags_to_drv( | |
245 | sta->flags), | |
246 | WPA_STA_AUTHORIZED, ~0); | |
247 | } | |
248 | ||
249 | return hostapd_sta_set_flags(hapd, sta->addr, | |
250 | hostapd_sta_flags_to_drv(sta->flags), | |
251 | 0, ~WPA_STA_AUTHORIZED); | |
252 | } | |
253 | ||
254 | ||
0e8a96a9 | 255 | int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta) |
4c2ddda4 JM |
256 | { |
257 | int set_flags, total_flags, flags_and, flags_or; | |
258 | total_flags = hostapd_sta_flags_to_drv(sta->flags); | |
259 | set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP; | |
ef580012 JM |
260 | if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || |
261 | sta->auth_alg == WLAN_AUTH_FT) && | |
4c2ddda4 JM |
262 | sta->flags & WLAN_STA_AUTHORIZED) |
263 | set_flags |= WPA_STA_AUTHORIZED; | |
264 | flags_or = total_flags & set_flags; | |
265 | flags_and = total_flags | ~set_flags; | |
266 | return hostapd_sta_set_flags(hapd, sta->addr, total_flags, | |
267 | flags_or, flags_and); | |
268 | } | |
269 | ||
270 | ||
0e8a96a9 JM |
271 | int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, |
272 | int enabled) | |
010401fe JM |
273 | { |
274 | struct wpa_bss_params params; | |
275 | os_memset(¶ms, 0, sizeof(params)); | |
276 | params.ifname = ifname; | |
277 | params.enabled = enabled; | |
278 | if (enabled) { | |
279 | params.wpa = hapd->conf->wpa; | |
280 | params.ieee802_1x = hapd->conf->ieee802_1x; | |
281 | params.wpa_group = hapd->conf->wpa_group; | |
e19c1d2c JM |
282 | if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) == |
283 | (WPA_PROTO_WPA | WPA_PROTO_RSN)) | |
284 | params.wpa_pairwise = hapd->conf->wpa_pairwise | | |
285 | hapd->conf->rsn_pairwise; | |
286 | else if (hapd->conf->wpa & WPA_PROTO_RSN) | |
287 | params.wpa_pairwise = hapd->conf->rsn_pairwise; | |
288 | else if (hapd->conf->wpa & WPA_PROTO_WPA) | |
289 | params.wpa_pairwise = hapd->conf->wpa_pairwise; | |
010401fe JM |
290 | params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; |
291 | params.rsn_preauth = hapd->conf->rsn_preauth; | |
a1ca0292 MP |
292 | #ifdef CONFIG_IEEE80211W |
293 | params.ieee80211w = hapd->conf->ieee80211w; | |
294 | #endif /* CONFIG_IEEE80211W */ | |
010401fe JM |
295 | } |
296 | return hostapd_set_ieee8021x(hapd, ¶ms); | |
297 | } | |
298 | ||
299 | ||
0e8a96a9 | 300 | int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) |
36592d31 | 301 | { |
f3585c8a JM |
302 | char force_ifname[IFNAMSIZ]; |
303 | u8 if_addr[ETH_ALEN]; | |
e926bcff | 304 | return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr, |
2aec4f3c | 305 | NULL, NULL, force_ifname, if_addr, NULL, 0); |
36592d31 JM |
306 | } |
307 | ||
0e8a96a9 JM |
308 | |
309 | int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname) | |
36592d31 JM |
310 | { |
311 | return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname); | |
312 | } | |
313 | ||
314 | ||
69dd2967 SM |
315 | int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds, |
316 | const u8 *addr, int aid, int val) | |
bdee6fce | 317 | { |
d38ae2ea FF |
318 | const char *bridge = NULL; |
319 | ||
bdee6fce | 320 | if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL) |
69dd2967 | 321 | return -1; |
d38ae2ea FF |
322 | if (hapd->conf->wds_bridge[0]) |
323 | bridge = hapd->conf->wds_bridge; | |
324 | else if (hapd->conf->bridge[0]) | |
325 | bridge = hapd->conf->bridge; | |
0e8a96a9 | 326 | return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, |
69dd2967 | 327 | bridge, ifname_wds); |
bdee6fce JM |
328 | } |
329 | ||
330 | ||
a52eba0f SP |
331 | int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, |
332 | u16 auth_alg) | |
333 | { | |
334 | if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL) | |
335 | return 0; | |
336 | return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg); | |
337 | } | |
338 | ||
339 | ||
340 | int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr, | |
341 | u16 seq, u16 status, const u8 *ie, size_t len) | |
342 | { | |
343 | if (hapd->driver == NULL || hapd->driver->sta_auth == NULL) | |
344 | return 0; | |
345 | return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr, | |
346 | seq, status, ie, len); | |
347 | } | |
348 | ||
349 | ||
350 | int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, | |
351 | int reassoc, u16 status, const u8 *ie, size_t len) | |
352 | { | |
353 | if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL) | |
354 | return 0; | |
355 | return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr, | |
356 | reassoc, status, ie, len); | |
357 | } | |
358 | ||
359 | ||
0e8a96a9 JM |
360 | int hostapd_sta_add(struct hostapd_data *hapd, |
361 | const u8 *addr, u16 aid, u16 capability, | |
362 | const u8 *supp_rates, size_t supp_rates_len, | |
363 | u16 listen_interval, | |
d83ab1fe | 364 | const struct ieee80211_ht_capabilities *ht_capab, |
a9a1d0f0 | 365 | const struct ieee80211_vht_capabilities *vht_capab, |
ae33239c AB |
366 | u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, |
367 | int set) | |
2ce86d9d JM |
368 | { |
369 | struct hostapd_sta_add_params params; | |
370 | ||
371 | if (hapd->driver == NULL) | |
372 | return 0; | |
373 | if (hapd->driver->sta_add == NULL) | |
374 | return 0; | |
375 | ||
376 | os_memset(¶ms, 0, sizeof(params)); | |
377 | params.addr = addr; | |
378 | params.aid = aid; | |
379 | params.capability = capability; | |
380 | params.supp_rates = supp_rates; | |
381 | params.supp_rates_len = supp_rates_len; | |
382 | params.listen_interval = listen_interval; | |
383 | params.ht_capabilities = ht_capab; | |
a9a1d0f0 | 384 | params.vht_capabilities = vht_capab; |
8a458116 MK |
385 | params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); |
386 | params.vht_opmode = vht_opmode; | |
d83ab1fe | 387 | params.flags = hostapd_sta_flags_to_drv(flags); |
5d061637 | 388 | params.qosinfo = qosinfo; |
ae33239c | 389 | params.support_p2p_ps = supp_p2p_ps; |
bb598c3b | 390 | params.set = set; |
62847751 | 391 | return hapd->driver->sta_add(hapd->drv_priv, ¶ms); |
2ce86d9d JM |
392 | } |
393 | ||
394 | ||
a52eba0f SP |
395 | int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, |
396 | u8 *tspec_ie, size_t tspec_ielen) | |
397 | { | |
398 | if (hapd->driver == NULL || hapd->driver->add_tspec == NULL) | |
399 | return 0; | |
400 | return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie, | |
401 | tspec_ielen); | |
402 | } | |
403 | ||
404 | ||
8b06c1ed JM |
405 | int hostapd_set_privacy(struct hostapd_data *hapd, int enabled) |
406 | { | |
407 | if (hapd->driver == NULL || hapd->driver->set_privacy == NULL) | |
408 | return 0; | |
d5dd016a | 409 | return hapd->driver->set_privacy(hapd->drv_priv, enabled); |
8b06c1ed JM |
410 | } |
411 | ||
412 | ||
413 | int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, | |
414 | size_t elem_len) | |
415 | { | |
416 | if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL) | |
417 | return 0; | |
aa484516 | 418 | return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len); |
8b06c1ed JM |
419 | } |
420 | ||
421 | ||
422 | int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len) | |
423 | { | |
424 | if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL) | |
425 | return 0; | |
8709de1a | 426 | return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len); |
8b06c1ed JM |
427 | } |
428 | ||
429 | ||
430 | int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len) | |
431 | { | |
432 | if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL) | |
433 | return 0; | |
8709de1a | 434 | return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len); |
8b06c1ed JM |
435 | } |
436 | ||
437 | ||
438 | int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, | |
a2e40bb6 | 439 | const char *ifname, const u8 *addr, void *bss_ctx, |
e17a2477 | 440 | void **drv_priv, char *force_ifname, u8 *if_addr, |
2aec4f3c | 441 | const char *bridge, int use_existing) |
8b06c1ed JM |
442 | { |
443 | if (hapd->driver == NULL || hapd->driver->if_add == NULL) | |
444 | return -1; | |
7ab68865 | 445 | return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr, |
e17a2477 | 446 | bss_ctx, drv_priv, force_ifname, if_addr, |
d8a3b66d | 447 | bridge, use_existing, 1); |
8b06c1ed JM |
448 | } |
449 | ||
450 | ||
451 | int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, | |
452 | const char *ifname) | |
453 | { | |
71cdf6b6 JM |
454 | if (hapd->driver == NULL || hapd->drv_priv == NULL || |
455 | hapd->driver->if_remove == NULL) | |
8b06c1ed JM |
456 | return -1; |
457 | return hapd->driver->if_remove(hapd->drv_priv, type, ifname); | |
458 | } | |
6e6e8c31 JM |
459 | |
460 | ||
461 | int hostapd_set_ieee8021x(struct hostapd_data *hapd, | |
462 | struct wpa_bss_params *params) | |
463 | { | |
464 | if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL) | |
465 | return 0; | |
466 | return hapd->driver->set_ieee8021x(hapd->drv_priv, params); | |
467 | } | |
468 | ||
469 | ||
470 | int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, | |
471 | const u8 *addr, int idx, u8 *seq) | |
472 | { | |
473 | if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL) | |
474 | return 0; | |
475 | return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx, | |
476 | seq); | |
477 | } | |
478 | ||
479 | ||
480 | int hostapd_flush(struct hostapd_data *hapd) | |
481 | { | |
482 | if (hapd->driver == NULL || hapd->driver->flush == NULL) | |
483 | return 0; | |
484 | return hapd->driver->flush(hapd->drv_priv); | |
485 | } | |
486 | ||
487 | ||
4e8f31e2 JM |
488 | int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, |
489 | int freq, int channel, int ht_enabled, int vht_enabled, | |
72c753d7 JD |
490 | int sec_channel_offset, int vht_oper_chwidth, |
491 | int center_segment0, int center_segment1) | |
492 | { | |
493 | struct hostapd_freq_params data; | |
494 | ||
495 | if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, | |
496 | vht_enabled, sec_channel_offset, | |
497 | vht_oper_chwidth, | |
7f0303d5 | 498 | center_segment0, center_segment1, |
e9b783d5 JM |
499 | hapd->iface->current_mode ? |
500 | hapd->iface->current_mode->vht_capab : 0)) | |
72c753d7 JD |
501 | return -1; |
502 | ||
fa476336 JB |
503 | if (hapd->driver == NULL) |
504 | return 0; | |
505 | if (hapd->driver->set_freq == NULL) | |
506 | return 0; | |
6e6e8c31 JM |
507 | return hapd->driver->set_freq(hapd->drv_priv, &data); |
508 | } | |
509 | ||
510 | int hostapd_set_rts(struct hostapd_data *hapd, int rts) | |
511 | { | |
512 | if (hapd->driver == NULL || hapd->driver->set_rts == NULL) | |
513 | return 0; | |
514 | return hapd->driver->set_rts(hapd->drv_priv, rts); | |
515 | } | |
516 | ||
517 | ||
518 | int hostapd_set_frag(struct hostapd_data *hapd, int frag) | |
519 | { | |
520 | if (hapd->driver == NULL || hapd->driver->set_frag == NULL) | |
521 | return 0; | |
522 | return hapd->driver->set_frag(hapd->drv_priv, frag); | |
523 | } | |
524 | ||
525 | ||
526 | int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, | |
527 | int total_flags, int flags_or, int flags_and) | |
528 | { | |
529 | if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL) | |
530 | return 0; | |
3234cba4 | 531 | return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags, |
6e6e8c31 JM |
532 | flags_or, flags_and); |
533 | } | |
534 | ||
535 | ||
6e6e8c31 JM |
536 | int hostapd_set_country(struct hostapd_data *hapd, const char *country) |
537 | { | |
538 | if (hapd->driver == NULL || | |
539 | hapd->driver->set_country == NULL) | |
540 | return 0; | |
541 | return hapd->driver->set_country(hapd->drv_priv, country); | |
542 | } | |
543 | ||
544 | ||
6e6e8c31 JM |
545 | int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, |
546 | int cw_min, int cw_max, int burst_time) | |
547 | { | |
548 | if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL) | |
549 | return 0; | |
550 | return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs, | |
551 | cw_min, cw_max, burst_time); | |
552 | } | |
553 | ||
554 | ||
6e6e8c31 JM |
555 | struct hostapd_hw_modes * |
556 | hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, | |
557 | u16 *flags) | |
558 | { | |
559 | if (hapd->driver == NULL || | |
560 | hapd->driver->get_hw_feature_data == NULL) | |
561 | return NULL; | |
562 | return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes, | |
563 | flags); | |
564 | } | |
565 | ||
566 | ||
567 | int hostapd_driver_commit(struct hostapd_data *hapd) | |
568 | { | |
569 | if (hapd->driver == NULL || hapd->driver->commit == NULL) | |
570 | return 0; | |
571 | return hapd->driver->commit(hapd->drv_priv); | |
572 | } | |
573 | ||
574 | ||
6e6e8c31 JM |
575 | int hostapd_drv_none(struct hostapd_data *hapd) |
576 | { | |
577 | return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; | |
578 | } | |
579 | ||
580 | ||
581 | int hostapd_driver_scan(struct hostapd_data *hapd, | |
582 | struct wpa_driver_scan_params *params) | |
583 | { | |
584 | if (hapd->driver && hapd->driver->scan2) | |
585 | return hapd->driver->scan2(hapd->drv_priv, params); | |
586 | return -1; | |
587 | } | |
588 | ||
589 | ||
590 | struct wpa_scan_results * hostapd_driver_get_scan_results( | |
591 | struct hostapd_data *hapd) | |
592 | { | |
593 | if (hapd->driver && hapd->driver->get_scan_results2) | |
594 | return hapd->driver->get_scan_results2(hapd->drv_priv); | |
595 | return NULL; | |
596 | } | |
aefb53bd JM |
597 | |
598 | ||
599 | int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, | |
600 | int duration) | |
601 | { | |
602 | if (hapd->driver && hapd->driver->set_noa) | |
603 | return hapd->driver->set_noa(hapd->drv_priv, count, start, | |
604 | duration); | |
605 | return -1; | |
606 | } | |
7392f11e JM |
607 | |
608 | ||
609 | int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, | |
610 | enum wpa_alg alg, const u8 *addr, | |
611 | int key_idx, int set_tx, | |
612 | const u8 *seq, size_t seq_len, | |
613 | const u8 *key, size_t key_len) | |
614 | { | |
615 | if (hapd->driver == NULL || hapd->driver->set_key == NULL) | |
616 | return 0; | |
617 | return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr, | |
618 | key_idx, set_tx, seq, seq_len, key, | |
619 | key_len); | |
620 | } | |
621 | ||
622 | ||
623 | int hostapd_drv_send_mlme(struct hostapd_data *hapd, | |
8cfa3527 | 624 | const void *msg, size_t len, int noack) |
7392f11e JM |
625 | { |
626 | if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) | |
627 | return 0; | |
2d3943ce AO |
628 | return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, |
629 | NULL, 0); | |
630 | } | |
631 | ||
632 | ||
633 | int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd, | |
634 | const void *msg, size_t len, int noack, | |
635 | const u16 *csa_offs, size_t csa_offs_len) | |
636 | { | |
637 | if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) | |
638 | return 0; | |
639 | return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, | |
640 | csa_offs, csa_offs_len); | |
7392f11e JM |
641 | } |
642 | ||
643 | ||
644 | int hostapd_drv_sta_deauth(struct hostapd_data *hapd, | |
645 | const u8 *addr, int reason) | |
646 | { | |
647 | if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL) | |
648 | return 0; | |
649 | return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr, | |
650 | reason); | |
651 | } | |
652 | ||
653 | ||
654 | int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, | |
655 | const u8 *addr, int reason) | |
656 | { | |
657 | if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL) | |
658 | return 0; | |
659 | return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr, | |
660 | reason); | |
661 | } | |
fb80e86e JK |
662 | |
663 | ||
a884be9d XC |
664 | int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper, |
665 | const u8 *peer, u8 *buf, u16 *buf_len) | |
666 | { | |
667 | if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL) | |
47768978 | 668 | return -1; |
a884be9d XC |
669 | return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf, |
670 | buf_len); | |
671 | } | |
672 | ||
673 | ||
fb80e86e JK |
674 | int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, |
675 | unsigned int wait, const u8 *dst, const u8 *data, | |
676 | size_t len) | |
677 | { | |
678 | if (hapd->driver == NULL || hapd->driver->send_action == NULL) | |
679 | return 0; | |
680 | return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, | |
681 | hapd->own_addr, hapd->own_addr, data, | |
682 | len, 0); | |
683 | } | |
e76da505 | 684 | |
dc036d9e | 685 | |
4e8f31e2 JM |
686 | int hostapd_start_dfs_cac(struct hostapd_iface *iface, |
687 | enum hostapd_hw_mode mode, int freq, | |
58b73e3d JD |
688 | int channel, int ht_enabled, int vht_enabled, |
689 | int sec_channel_offset, int vht_oper_chwidth, | |
690 | int center_segment0, int center_segment1) | |
e76da505 | 691 | { |
dc036d9e | 692 | struct hostapd_data *hapd = iface->bss[0]; |
04e8003c | 693 | struct hostapd_freq_params data; |
2e946249 | 694 | int res; |
04e8003c | 695 | |
e76da505 JD |
696 | if (!hapd->driver || !hapd->driver->start_dfs_cac) |
697 | return 0; | |
698 | ||
dc036d9e | 699 | if (!iface->conf->ieee80211h) { |
e76da505 JD |
700 | wpa_printf(MSG_ERROR, "Can't start DFS CAC, DFS functionality " |
701 | "is not enabled"); | |
702 | return -1; | |
703 | } | |
704 | ||
58b73e3d JD |
705 | if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, |
706 | vht_enabled, sec_channel_offset, | |
707 | vht_oper_chwidth, center_segment0, | |
7f0303d5 | 708 | center_segment1, |
1f374834 JD |
709 | iface->current_mode->vht_capab)) { |
710 | wpa_printf(MSG_ERROR, "Can't set freq params"); | |
04e8003c | 711 | return -1; |
1f374834 | 712 | } |
04e8003c | 713 | |
2e946249 | 714 | res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data); |
bbbacbf2 | 715 | if (!res) { |
dc036d9e | 716 | iface->cac_started = 1; |
bbbacbf2 JD |
717 | os_get_reltime(&iface->dfs_cac_start); |
718 | } | |
2e946249 JD |
719 | |
720 | return res; | |
e76da505 | 721 | } |
c551700f KP |
722 | |
723 | ||
724 | int hostapd_drv_set_qos_map(struct hostapd_data *hapd, | |
725 | const u8 *qos_map_set, u8 qos_map_set_len) | |
726 | { | |
727 | if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL) | |
728 | return 0; | |
729 | return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set, | |
730 | qos_map_set_len); | |
731 | } | |
16689c7c PX |
732 | |
733 | ||
d0cdccd3 PX |
734 | static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, |
735 | struct hostapd_hw_modes *mode, | |
736 | int acs_ch_list_all, | |
737 | int **freq_list) | |
738 | { | |
739 | int i; | |
740 | ||
741 | for (i = 0; i < mode->num_channels; i++) { | |
742 | struct hostapd_channel_data *chan = &mode->channels[i]; | |
743 | ||
744 | if ((acs_ch_list_all || | |
745 | freq_range_list_includes(&hapd->iface->conf->acs_ch_list, | |
746 | chan->chan)) && | |
747 | !(chan->flag & HOSTAPD_CHAN_DISABLED)) | |
748 | int_array_add_unique(freq_list, chan->freq); | |
749 | } | |
750 | } | |
751 | ||
752 | ||
16689c7c PX |
753 | int hostapd_drv_do_acs(struct hostapd_data *hapd) |
754 | { | |
755 | struct drv_acs_params params; | |
857d9422 MM |
756 | int ret, i, acs_ch_list_all = 0; |
757 | u8 *channels = NULL; | |
758 | unsigned int num_channels = 0; | |
759 | struct hostapd_hw_modes *mode; | |
d0cdccd3 | 760 | int *freq_list = NULL; |
16689c7c PX |
761 | |
762 | if (hapd->driver == NULL || hapd->driver->do_acs == NULL) | |
763 | return 0; | |
857d9422 | 764 | |
16689c7c PX |
765 | os_memset(¶ms, 0, sizeof(params)); |
766 | params.hw_mode = hapd->iface->conf->hw_mode; | |
857d9422 MM |
767 | |
768 | /* | |
769 | * If no chanlist config parameter is provided, include all enabled | |
770 | * channels of the selected hw_mode. | |
771 | */ | |
772 | if (!hapd->iface->conf->acs_ch_list.num) | |
773 | acs_ch_list_all = 1; | |
774 | ||
775 | mode = hapd->iface->current_mode; | |
d0cdccd3 PX |
776 | if (mode) { |
777 | channels = os_malloc(mode->num_channels); | |
778 | if (channels == NULL) | |
779 | return -1; | |
780 | ||
781 | for (i = 0; i < mode->num_channels; i++) { | |
782 | struct hostapd_channel_data *chan = &mode->channels[i]; | |
783 | if (!acs_ch_list_all && | |
784 | !freq_range_list_includes( | |
785 | &hapd->iface->conf->acs_ch_list, | |
786 | chan->chan)) | |
787 | continue; | |
788 | if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) { | |
789 | channels[num_channels++] = chan->chan; | |
790 | int_array_add_unique(&freq_list, chan->freq); | |
791 | } | |
792 | } | |
793 | } else { | |
794 | for (i = 0; i < hapd->iface->num_hw_features; i++) { | |
795 | mode = &hapd->iface->hw_features[i]; | |
796 | hostapd_get_hw_mode_any_channels(hapd, mode, | |
797 | acs_ch_list_all, | |
798 | &freq_list); | |
799 | } | |
857d9422 MM |
800 | } |
801 | ||
802 | params.ch_list = channels; | |
803 | params.ch_list_len = num_channels; | |
d0cdccd3 | 804 | params.freq_list = freq_list; |
857d9422 | 805 | |
16689c7c | 806 | params.ht_enabled = !!(hapd->iface->conf->ieee80211n); |
5085ffb8 | 807 | params.ht40_enabled = !!(hapd->iface->conf->ht_capab & |
16689c7c | 808 | HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET); |
857d9422 MM |
809 | params.vht_enabled = !!(hapd->iface->conf->ieee80211ac); |
810 | params.ch_width = 20; | |
811 | if (hapd->iface->conf->ieee80211n && params.ht40_enabled) | |
812 | params.ch_width = 40; | |
813 | ||
814 | /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth | |
815 | */ | |
816 | if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) { | |
817 | if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ) | |
818 | params.ch_width = 80; | |
819 | else if (hapd->iface->conf->vht_oper_chwidth == | |
820 | VHT_CHANWIDTH_160MHZ || | |
821 | hapd->iface->conf->vht_oper_chwidth == | |
822 | VHT_CHANWIDTH_80P80MHZ) | |
823 | params.ch_width = 160; | |
824 | } | |
825 | ||
826 | ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms); | |
827 | os_free(channels); | |
828 | ||
829 | return ret; | |
16689c7c | 830 | } |