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