Line data Source code
1 : /*
2 : * Control interface for shared AP commands
3 : * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "utils/includes.h"
10 :
11 : #include "utils/common.h"
12 : #include "common/ieee802_11_defs.h"
13 : #include "common/sae.h"
14 : #include "eapol_auth/eapol_auth_sm.h"
15 : #include "fst/fst_ctrl_iface.h"
16 : #include "hostapd.h"
17 : #include "ieee802_1x.h"
18 : #include "wpa_auth.h"
19 : #include "ieee802_11.h"
20 : #include "sta_info.h"
21 : #include "wps_hostapd.h"
22 : #include "p2p_hostapd.h"
23 : #include "ctrl_iface_ap.h"
24 : #include "ap_drv_ops.h"
25 : #include "mbo_ap.h"
26 : #include "taxonomy.h"
27 :
28 :
29 221 : static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
30 : struct sta_info *sta,
31 : char *buf, size_t buflen)
32 : {
33 : struct hostap_sta_driver_data data;
34 : int ret;
35 :
36 221 : if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
37 1 : return 0;
38 :
39 220 : ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
40 : "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
41 : data.rx_packets, data.tx_packets,
42 : data.rx_bytes, data.tx_bytes, data.inactive_msec);
43 220 : if (os_snprintf_error(buflen, ret))
44 0 : return 0;
45 220 : return ret;
46 : }
47 :
48 :
49 221 : static int hostapd_get_sta_conn_time(struct sta_info *sta,
50 : char *buf, size_t buflen)
51 : {
52 : struct os_reltime age;
53 : int ret;
54 :
55 221 : if (!sta->connected_time.sec)
56 0 : return 0;
57 :
58 221 : os_reltime_age(&sta->connected_time, &age);
59 :
60 221 : ret = os_snprintf(buf, buflen, "connected_time=%u\n",
61 221 : (unsigned int) age.sec);
62 221 : if (os_snprintf_error(buflen, ret))
63 0 : return 0;
64 221 : return ret;
65 : }
66 :
67 :
68 221 : static const char * timeout_next_str(int val)
69 : {
70 221 : switch (val) {
71 : case STA_NULLFUNC:
72 220 : return "NULLFUNC POLL";
73 : case STA_DISASSOC:
74 1 : return "DISASSOC";
75 : case STA_DEAUTH:
76 0 : return "DEAUTH";
77 : case STA_REMOVE:
78 0 : return "REMOVE";
79 : case STA_DISASSOC_FROM_CLI:
80 0 : return "DISASSOC_FROM_CLI";
81 : }
82 :
83 0 : return "?";
84 : }
85 :
86 :
87 222 : static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
88 : struct sta_info *sta,
89 : char *buf, size_t buflen)
90 : {
91 : int len, res, ret, i;
92 :
93 222 : if (!sta)
94 1 : return 0;
95 :
96 221 : len = 0;
97 1326 : ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
98 1326 : MAC2STR(sta->addr));
99 221 : if (os_snprintf_error(buflen - len, ret))
100 0 : return len;
101 221 : len += ret;
102 :
103 221 : ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
104 221 : if (ret < 0)
105 0 : return len;
106 221 : len += ret;
107 :
108 663 : ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
109 : "listen_interval=%d\nsupported_rates=",
110 663 : sta->aid, sta->capability, sta->listen_interval);
111 221 : if (os_snprintf_error(buflen - len, ret))
112 0 : return len;
113 221 : len += ret;
114 :
115 2605 : for (i = 0; i < sta->supported_rates_len; i++) {
116 4768 : ret = os_snprintf(buf + len, buflen - len, "%02x%s",
117 2384 : sta->supported_rates[i],
118 2384 : i + 1 < sta->supported_rates_len ? " " : "");
119 2384 : if (os_snprintf_error(buflen - len, ret))
120 0 : return len;
121 2384 : len += ret;
122 : }
123 :
124 221 : ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
125 221 : timeout_next_str(sta->timeout_next));
126 221 : if (os_snprintf_error(buflen - len, ret))
127 0 : return len;
128 221 : len += ret;
129 :
130 221 : res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
131 221 : if (res >= 0)
132 221 : len += res;
133 221 : res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
134 221 : if (res >= 0)
135 221 : len += res;
136 221 : res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
137 221 : if (res >= 0)
138 221 : len += res;
139 221 : res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
140 : buflen - len);
141 221 : if (res >= 0)
142 221 : len += res;
143 221 : res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
144 221 : if (res >= 0)
145 221 : len += res;
146 :
147 221 : len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
148 221 : len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
149 :
150 : #ifdef CONFIG_SAE
151 221 : if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
152 0 : res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
153 0 : sta->sae->group);
154 0 : if (!os_snprintf_error(buflen - len, res))
155 0 : len += res;
156 : }
157 : #endif /* CONFIG_SAE */
158 :
159 221 : if (sta->vlan_id > 0) {
160 4 : res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
161 : sta->vlan_id);
162 4 : if (!os_snprintf_error(buflen - len, res))
163 4 : len += res;
164 : }
165 :
166 221 : res = mbo_ap_get_info(sta, buf + len, buflen - len);
167 221 : if (res >= 0)
168 221 : len += res;
169 :
170 241 : if (sta->supp_op_classes &&
171 20 : buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
172 20 : len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
173 40 : len += wpa_snprintf_hex(buf + len, buflen - len,
174 20 : sta->supp_op_classes + 1,
175 20 : sta->supp_op_classes[0]);
176 20 : len += os_snprintf(buf + len, buflen - len, "\n");
177 : }
178 :
179 221 : return len;
180 : }
181 :
182 :
183 116 : int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
184 : char *buf, size_t buflen)
185 : {
186 116 : return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
187 : }
188 :
189 :
190 128 : int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
191 : char *buf, size_t buflen)
192 : {
193 : u8 addr[ETH_ALEN];
194 : int ret;
195 : const char *pos;
196 : struct sta_info *sta;
197 :
198 128 : if (hwaddr_aton(txtaddr, addr)) {
199 1 : ret = os_snprintf(buf, buflen, "FAIL\n");
200 1 : if (os_snprintf_error(buflen, ret))
201 0 : return 0;
202 1 : return ret;
203 : }
204 :
205 127 : sta = ap_get_sta(hapd, addr);
206 127 : if (sta == NULL)
207 5 : return -1;
208 :
209 122 : pos = os_strchr(txtaddr, ' ');
210 122 : if (pos) {
211 18 : pos++;
212 :
213 : #ifdef HOSTAPD_DUMP_STATE
214 18 : if (os_strcmp(pos, "eapol") == 0) {
215 18 : if (sta->eapol_sm == NULL)
216 1 : return -1;
217 17 : return eapol_auth_dump_state(sta->eapol_sm, buf,
218 : buflen);
219 : }
220 : #endif /* HOSTAPD_DUMP_STATE */
221 :
222 0 : return -1;
223 : }
224 :
225 104 : ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
226 104 : ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
227 :
228 104 : return ret;
229 : }
230 :
231 :
232 6 : int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
233 : char *buf, size_t buflen)
234 : {
235 : u8 addr[ETH_ALEN];
236 : struct sta_info *sta;
237 : int ret;
238 :
239 6 : if (hwaddr_aton(txtaddr, addr) ||
240 : (sta = ap_get_sta(hapd, addr)) == NULL) {
241 1 : ret = os_snprintf(buf, buflen, "FAIL\n");
242 1 : if (os_snprintf_error(buflen, ret))
243 0 : return 0;
244 1 : return ret;
245 : }
246 :
247 5 : if (!sta->next)
248 3 : return 0;
249 :
250 2 : return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
251 : }
252 :
253 :
254 : #ifdef CONFIG_P2P_MANAGER
255 4 : static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
256 : u8 minor_reason_code, const u8 *addr)
257 : {
258 : struct ieee80211_mgmt *mgmt;
259 : int ret;
260 : u8 *pos;
261 :
262 4 : if (!hapd->drv_priv || !hapd->driver->send_frame)
263 2 : return -1;
264 :
265 2 : mgmt = os_zalloc(sizeof(*mgmt) + 100);
266 2 : if (mgmt == NULL)
267 0 : return -1;
268 :
269 2 : mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
270 2 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
271 : " with minor reason code %u (stype=%u (%s))",
272 : MAC2STR(addr), minor_reason_code, stype,
273 : fc2str(le_to_host16(mgmt->frame_control)));
274 :
275 2 : os_memcpy(mgmt->da, addr, ETH_ALEN);
276 2 : os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
277 2 : os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
278 2 : if (stype == WLAN_FC_STYPE_DEAUTH) {
279 1 : mgmt->u.deauth.reason_code =
280 : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
281 1 : pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
282 : } else {
283 1 : mgmt->u.disassoc.reason_code =
284 : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
285 1 : pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
286 : }
287 :
288 2 : *pos++ = WLAN_EID_VENDOR_SPECIFIC;
289 2 : *pos++ = 4 + 3 + 1;
290 2 : WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
291 2 : pos += 4;
292 :
293 2 : *pos++ = P2P_ATTR_MINOR_REASON_CODE;
294 2 : WPA_PUT_LE16(pos, 1);
295 2 : pos += 2;
296 2 : *pos++ = minor_reason_code;
297 :
298 4 : ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
299 2 : pos - (u8 *) mgmt, 1);
300 2 : os_free(mgmt);
301 :
302 2 : return ret < 0 ? -1 : 0;
303 : }
304 : #endif /* CONFIG_P2P_MANAGER */
305 :
306 :
307 43 : int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
308 : const char *txtaddr)
309 : {
310 : u8 addr[ETH_ALEN];
311 : struct sta_info *sta;
312 : const char *pos;
313 43 : u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
314 :
315 43 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
316 : txtaddr);
317 :
318 43 : if (hwaddr_aton(txtaddr, addr))
319 2 : return -1;
320 :
321 41 : pos = os_strstr(txtaddr, " reason=");
322 41 : if (pos)
323 22 : reason = atoi(pos + 8);
324 :
325 41 : pos = os_strstr(txtaddr, " test=");
326 41 : if (pos) {
327 : struct ieee80211_mgmt mgmt;
328 : int encrypt;
329 23 : if (!hapd->drv_priv || !hapd->driver->send_frame)
330 1 : return -1;
331 22 : pos += 6;
332 22 : encrypt = atoi(pos);
333 22 : os_memset(&mgmt, 0, sizeof(mgmt));
334 22 : mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
335 : WLAN_FC_STYPE_DEAUTH);
336 22 : os_memcpy(mgmt.da, addr, ETH_ALEN);
337 22 : os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
338 22 : os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
339 22 : mgmt.u.deauth.reason_code = host_to_le16(reason);
340 22 : if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
341 : IEEE80211_HDRLEN +
342 : sizeof(mgmt.u.deauth),
343 : encrypt) < 0)
344 0 : return -1;
345 22 : return 0;
346 : }
347 :
348 : #ifdef CONFIG_P2P_MANAGER
349 17 : pos = os_strstr(txtaddr, " p2p=");
350 17 : if (pos) {
351 2 : return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
352 2 : atoi(pos + 5), addr);
353 : }
354 : #endif /* CONFIG_P2P_MANAGER */
355 :
356 16 : if (os_strstr(txtaddr, " tx=0"))
357 2 : hostapd_drv_sta_remove(hapd, addr);
358 : else
359 14 : hostapd_drv_sta_deauth(hapd, addr, reason);
360 16 : sta = ap_get_sta(hapd, addr);
361 16 : if (sta)
362 11 : ap_sta_deauthenticate(hapd, sta, reason);
363 5 : else if (addr[0] == 0xff)
364 5 : hostapd_free_stas(hapd);
365 :
366 16 : return 0;
367 : }
368 :
369 :
370 30 : int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
371 : const char *txtaddr)
372 : {
373 : u8 addr[ETH_ALEN];
374 : struct sta_info *sta;
375 : const char *pos;
376 30 : u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
377 :
378 30 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
379 : txtaddr);
380 :
381 30 : if (hwaddr_aton(txtaddr, addr))
382 2 : return -1;
383 :
384 28 : pos = os_strstr(txtaddr, " reason=");
385 28 : if (pos)
386 17 : reason = atoi(pos + 8);
387 :
388 28 : pos = os_strstr(txtaddr, " test=");
389 28 : if (pos) {
390 : struct ieee80211_mgmt mgmt;
391 : int encrypt;
392 20 : if (!hapd->drv_priv || !hapd->driver->send_frame)
393 1 : return -1;
394 19 : pos += 6;
395 19 : encrypt = atoi(pos);
396 19 : os_memset(&mgmt, 0, sizeof(mgmt));
397 19 : mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
398 : WLAN_FC_STYPE_DISASSOC);
399 19 : os_memcpy(mgmt.da, addr, ETH_ALEN);
400 19 : os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
401 19 : os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
402 19 : mgmt.u.disassoc.reason_code = host_to_le16(reason);
403 19 : if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
404 : IEEE80211_HDRLEN +
405 : sizeof(mgmt.u.deauth),
406 : encrypt) < 0)
407 0 : return -1;
408 19 : return 0;
409 : }
410 :
411 : #ifdef CONFIG_P2P_MANAGER
412 6 : pos = os_strstr(txtaddr, " p2p=");
413 6 : if (pos) {
414 2 : return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
415 2 : atoi(pos + 5), addr);
416 : }
417 : #endif /* CONFIG_P2P_MANAGER */
418 :
419 6 : if (os_strstr(txtaddr, " tx=0"))
420 2 : hostapd_drv_sta_remove(hapd, addr);
421 : else
422 4 : hostapd_drv_sta_disassoc(hapd, addr, reason);
423 6 : sta = ap_get_sta(hapd, addr);
424 6 : if (sta)
425 5 : ap_sta_disassociate(hapd, sta, reason);
426 1 : else if (addr[0] == 0xff)
427 1 : hostapd_free_stas(hapd);
428 :
429 6 : return 0;
430 : }
431 :
432 :
433 : #ifdef CONFIG_TAXONOMY
434 9 : int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
435 : const char *txtaddr,
436 : char *buf, size_t buflen)
437 : {
438 : u8 addr[ETH_ALEN];
439 : struct sta_info *sta;
440 :
441 9 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
442 :
443 9 : if (hwaddr_aton(txtaddr, addr))
444 1 : return -1;
445 :
446 8 : sta = ap_get_sta(hapd, addr);
447 8 : if (!sta)
448 3 : return -1;
449 :
450 5 : return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
451 : }
452 : #endif /* CONFIG_TAXONOMY */
453 :
454 :
455 1 : int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
456 : const char *txtaddr)
457 : {
458 : u8 addr[ETH_ALEN];
459 : struct sta_info *sta;
460 :
461 1 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
462 :
463 1 : if (hwaddr_aton(txtaddr, addr))
464 0 : return -1;
465 :
466 1 : sta = ap_get_sta(hapd, addr);
467 1 : if (!sta)
468 0 : return -1;
469 :
470 1 : hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
471 1 : sta->flags & WLAN_STA_WMM);
472 1 : return 0;
473 : }
474 :
475 :
476 717 : int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
477 : size_t buflen)
478 : {
479 717 : struct hostapd_iface *iface = hapd->iface;
480 717 : int len = 0, ret;
481 : size_t i;
482 :
483 1434 : ret = os_snprintf(buf + len, buflen - len,
484 : "state=%s\n"
485 : "phy=%s\n"
486 : "freq=%d\n"
487 : "num_sta_non_erp=%d\n"
488 : "num_sta_no_short_slot_time=%d\n"
489 : "num_sta_no_short_preamble=%d\n"
490 : "olbc=%d\n"
491 : "num_sta_ht_no_gf=%d\n"
492 : "num_sta_no_ht=%d\n"
493 : "num_sta_ht_20_mhz=%d\n"
494 : "num_sta_ht40_intolerant=%d\n"
495 : "olbc_ht=%d\n"
496 : "ht_op_mode=0x%x\n",
497 : hostapd_state_text(iface->state),
498 717 : iface->phy,
499 : iface->freq,
500 : iface->num_sta_non_erp,
501 : iface->num_sta_no_short_slot_time,
502 : iface->num_sta_no_short_preamble,
503 : iface->olbc,
504 : iface->num_sta_ht_no_gf,
505 : iface->num_sta_no_ht,
506 : iface->num_sta_ht_20mhz,
507 : iface->num_sta_ht40_intolerant,
508 : iface->olbc_ht,
509 717 : iface->ht_op_mode);
510 717 : if (os_snprintf_error(buflen - len, ret))
511 0 : return len;
512 717 : len += ret;
513 :
514 717 : if (!iface->cac_started || !iface->dfs_cac_ms) {
515 706 : ret = os_snprintf(buf + len, buflen - len,
516 : "cac_time_seconds=%d\n"
517 : "cac_time_left_seconds=N/A\n",
518 706 : iface->dfs_cac_ms / 1000);
519 : } else {
520 : /* CAC started and CAC time set - calculate remaining time */
521 : struct os_reltime now;
522 : unsigned int left_time;
523 :
524 11 : os_reltime_age(&iface->dfs_cac_start, &now);
525 11 : left_time = iface->dfs_cac_ms / 1000 - now.sec;
526 11 : ret = os_snprintf(buf + len, buflen - len,
527 : "cac_time_seconds=%u\n"
528 : "cac_time_left_seconds=%u\n",
529 11 : iface->dfs_cac_ms / 1000,
530 : left_time);
531 : }
532 717 : if (os_snprintf_error(buflen - len, ret))
533 0 : return len;
534 717 : len += ret;
535 :
536 4311 : ret = os_snprintf(buf + len, buflen - len,
537 : "channel=%u\n"
538 : "secondary_channel=%d\n"
539 : "ieee80211n=%d\n"
540 : "ieee80211ac=%d\n",
541 717 : iface->conf->channel,
542 1431 : iface->conf->ieee80211n && !hapd->conf->disable_11n ?
543 696 : iface->conf->secondary_channel : 0,
544 1431 : iface->conf->ieee80211n && !hapd->conf->disable_11n,
545 717 : iface->conf->ieee80211ac &&
546 33 : !hapd->conf->disable_11ac);
547 717 : if (os_snprintf_error(buflen - len, ret))
548 0 : return len;
549 717 : len += ret;
550 717 : if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
551 93 : ret = os_snprintf(buf + len, buflen - len,
552 : "vht_oper_chwidth=%d\n"
553 : "vht_oper_centr_freq_seg0_idx=%d\n"
554 : "vht_oper_centr_freq_seg1_idx=%d\n",
555 31 : iface->conf->vht_oper_chwidth,
556 31 : iface->conf->vht_oper_centr_freq_seg0_idx,
557 31 : iface->conf->vht_oper_centr_freq_seg1_idx);
558 31 : if (os_snprintf_error(buflen - len, ret))
559 0 : return len;
560 31 : len += ret;
561 : }
562 :
563 1446 : for (i = 0; i < iface->num_bss; i++) {
564 729 : struct hostapd_data *bss = iface->bss[i];
565 7290 : ret = os_snprintf(buf + len, buflen - len,
566 : "bss[%d]=%s\n"
567 : "bssid[%d]=" MACSTR "\n"
568 : "ssid[%d]=%s\n"
569 : "num_sta[%d]=%d\n",
570 729 : (int) i, bss->conf->iface,
571 4374 : (int) i, MAC2STR(bss->own_addr),
572 : (int) i,
573 729 : wpa_ssid_txt(bss->conf->ssid.ssid,
574 729 : bss->conf->ssid.ssid_len),
575 : (int) i, bss->num_sta);
576 729 : if (os_snprintf_error(buflen - len, ret))
577 0 : return len;
578 729 : len += ret;
579 : }
580 :
581 717 : return len;
582 : }
583 :
584 :
585 35 : int hostapd_parse_csa_settings(const char *pos,
586 : struct csa_settings *settings)
587 : {
588 : char *end;
589 :
590 35 : os_memset(settings, 0, sizeof(*settings));
591 35 : settings->cs_count = strtol(pos, &end, 10);
592 35 : if (pos == end) {
593 2 : wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
594 2 : return -1;
595 : }
596 :
597 33 : settings->freq_params.freq = atoi(end);
598 33 : if (settings->freq_params.freq == 0) {
599 1 : wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
600 1 : return -1;
601 : }
602 :
603 : #define SET_CSA_SETTING(str) \
604 : do { \
605 : const char *pos2 = os_strstr(pos, " " #str "="); \
606 : if (pos2) { \
607 : pos2 += sizeof(" " #str "=") - 1; \
608 : settings->freq_params.str = atoi(pos2); \
609 : } \
610 : } while (0)
611 :
612 32 : SET_CSA_SETTING(center_freq1);
613 32 : SET_CSA_SETTING(center_freq2);
614 32 : SET_CSA_SETTING(bandwidth);
615 32 : SET_CSA_SETTING(sec_channel_offset);
616 32 : settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
617 32 : settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
618 32 : settings->block_tx = !!os_strstr(pos, " blocktx");
619 : #undef SET_CSA_SETTING
620 :
621 32 : return 0;
622 : }
623 :
624 :
625 3 : int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
626 : {
627 3 : return hostapd_drv_stop_ap(hapd);
628 : }
629 :
630 :
631 18 : int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
632 : size_t len)
633 : {
634 18 : return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
635 : }
636 :
637 :
638 4 : void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
639 : {
640 4 : wpa_auth_pmksa_flush(hapd->wpa_auth);
641 4 : }
|