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
hostapd_get_sta_tx_rx(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)29 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 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
37 return 0;
38
39 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 if (os_snprintf_error(buflen, ret))
44 return 0;
45 return ret;
46 }
47
48
hostapd_get_sta_conn_time(struct sta_info * sta,char * buf,size_t buflen)49 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 if (!sta->connected_time.sec)
56 return 0;
57
58 os_reltime_age(&sta->connected_time, &age);
59
60 ret = os_snprintf(buf, buflen, "connected_time=%u\n",
61 (unsigned int) age.sec);
62 if (os_snprintf_error(buflen, ret))
63 return 0;
64 return ret;
65 }
66
67
timeout_next_str(int val)68 static const char * timeout_next_str(int val)
69 {
70 switch (val) {
71 case STA_NULLFUNC:
72 return "NULLFUNC POLL";
73 case STA_DISASSOC:
74 return "DISASSOC";
75 case STA_DEAUTH:
76 return "DEAUTH";
77 case STA_REMOVE:
78 return "REMOVE";
79 case STA_DISASSOC_FROM_CLI:
80 return "DISASSOC_FROM_CLI";
81 }
82
83 return "?";
84 }
85
86
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)87 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 if (!sta)
94 return 0;
95
96 len = 0;
97 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
98 MAC2STR(sta->addr));
99 if (os_snprintf_error(buflen - len, ret))
100 return len;
101 len += ret;
102
103 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
104 if (ret < 0)
105 return len;
106 len += ret;
107
108 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
109 "listen_interval=%d\nsupported_rates=",
110 sta->aid, sta->capability, sta->listen_interval);
111 if (os_snprintf_error(buflen - len, ret))
112 return len;
113 len += ret;
114
115 for (i = 0; i < sta->supported_rates_len; i++) {
116 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
117 sta->supported_rates[i],
118 i + 1 < sta->supported_rates_len ? " " : "");
119 if (os_snprintf_error(buflen - len, ret))
120 return len;
121 len += ret;
122 }
123
124 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
125 timeout_next_str(sta->timeout_next));
126 if (os_snprintf_error(buflen - len, ret))
127 return len;
128 len += ret;
129
130 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
131 if (res >= 0)
132 len += res;
133 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
134 if (res >= 0)
135 len += res;
136 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
137 if (res >= 0)
138 len += res;
139 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
140 buflen - len);
141 if (res >= 0)
142 len += res;
143 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
144 if (res >= 0)
145 len += res;
146
147 len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
148 len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
149
150 #ifdef CONFIG_SAE
151 if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
152 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
153 sta->sae->group);
154 if (!os_snprintf_error(buflen - len, res))
155 len += res;
156 }
157 #endif /* CONFIG_SAE */
158
159 if (sta->vlan_id > 0) {
160 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
161 sta->vlan_id);
162 if (!os_snprintf_error(buflen - len, res))
163 len += res;
164 }
165
166 res = mbo_ap_get_info(sta, buf + len, buflen - len);
167 if (res >= 0)
168 len += res;
169
170 if (sta->supp_op_classes &&
171 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
172 len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
173 len += wpa_snprintf_hex(buf + len, buflen - len,
174 sta->supp_op_classes + 1,
175 sta->supp_op_classes[0]);
176 len += os_snprintf(buf + len, buflen - len, "\n");
177 }
178
179 return len;
180 }
181
182
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)183 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
184 char *buf, size_t buflen)
185 {
186 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
187 }
188
189
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)190 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 if (hwaddr_aton(txtaddr, addr)) {
199 ret = os_snprintf(buf, buflen, "FAIL\n");
200 if (os_snprintf_error(buflen, ret))
201 return 0;
202 return ret;
203 }
204
205 sta = ap_get_sta(hapd, addr);
206 if (sta == NULL)
207 return -1;
208
209 pos = os_strchr(txtaddr, ' ');
210 if (pos) {
211 pos++;
212
213 #ifdef HOSTAPD_DUMP_STATE
214 if (os_strcmp(pos, "eapol") == 0) {
215 if (sta->eapol_sm == NULL)
216 return -1;
217 return eapol_auth_dump_state(sta->eapol_sm, buf,
218 buflen);
219 }
220 #endif /* HOSTAPD_DUMP_STATE */
221
222 return -1;
223 }
224
225 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
226 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
227
228 return ret;
229 }
230
231
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)232 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 if (hwaddr_aton(txtaddr, addr) ||
240 (sta = ap_get_sta(hapd, addr)) == NULL) {
241 ret = os_snprintf(buf, buflen, "FAIL\n");
242 if (os_snprintf_error(buflen, ret))
243 return 0;
244 return ret;
245 }
246
247 if (!sta->next)
248 return 0;
249
250 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
251 }
252
253
254 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)255 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 if (!hapd->drv_priv || !hapd->driver->send_frame)
263 return -1;
264
265 mgmt = os_zalloc(sizeof(*mgmt) + 100);
266 if (mgmt == NULL)
267 return -1;
268
269 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
270 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 os_memcpy(mgmt->da, addr, ETH_ALEN);
276 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
277 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
278 if (stype == WLAN_FC_STYPE_DEAUTH) {
279 mgmt->u.deauth.reason_code =
280 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
281 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
282 } else {
283 mgmt->u.disassoc.reason_code =
284 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
285 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
286 }
287
288 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
289 *pos++ = 4 + 3 + 1;
290 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
291 pos += 4;
292
293 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
294 WPA_PUT_LE16(pos, 1);
295 pos += 2;
296 *pos++ = minor_reason_code;
297
298 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
299 pos - (u8 *) mgmt, 1);
300 os_free(mgmt);
301
302 return ret < 0 ? -1 : 0;
303 }
304 #endif /* CONFIG_P2P_MANAGER */
305
306
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)307 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 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
314
315 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
316 txtaddr);
317
318 if (hwaddr_aton(txtaddr, addr))
319 return -1;
320
321 pos = os_strstr(txtaddr, " reason=");
322 if (pos)
323 reason = atoi(pos + 8);
324
325 pos = os_strstr(txtaddr, " test=");
326 if (pos) {
327 struct ieee80211_mgmt mgmt;
328 int encrypt;
329 if (!hapd->drv_priv || !hapd->driver->send_frame)
330 return -1;
331 pos += 6;
332 encrypt = atoi(pos);
333 os_memset(&mgmt, 0, sizeof(mgmt));
334 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
335 WLAN_FC_STYPE_DEAUTH);
336 os_memcpy(mgmt.da, addr, ETH_ALEN);
337 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
338 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
339 mgmt.u.deauth.reason_code = host_to_le16(reason);
340 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
341 IEEE80211_HDRLEN +
342 sizeof(mgmt.u.deauth),
343 encrypt) < 0)
344 return -1;
345 return 0;
346 }
347
348 #ifdef CONFIG_P2P_MANAGER
349 pos = os_strstr(txtaddr, " p2p=");
350 if (pos) {
351 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
352 atoi(pos + 5), addr);
353 }
354 #endif /* CONFIG_P2P_MANAGER */
355
356 if (os_strstr(txtaddr, " tx=0"))
357 hostapd_drv_sta_remove(hapd, addr);
358 else
359 hostapd_drv_sta_deauth(hapd, addr, reason);
360 sta = ap_get_sta(hapd, addr);
361 if (sta)
362 ap_sta_deauthenticate(hapd, sta, reason);
363 else if (addr[0] == 0xff)
364 hostapd_free_stas(hapd);
365
366 return 0;
367 }
368
369
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)370 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 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
377
378 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
379 txtaddr);
380
381 if (hwaddr_aton(txtaddr, addr))
382 return -1;
383
384 pos = os_strstr(txtaddr, " reason=");
385 if (pos)
386 reason = atoi(pos + 8);
387
388 pos = os_strstr(txtaddr, " test=");
389 if (pos) {
390 struct ieee80211_mgmt mgmt;
391 int encrypt;
392 if (!hapd->drv_priv || !hapd->driver->send_frame)
393 return -1;
394 pos += 6;
395 encrypt = atoi(pos);
396 os_memset(&mgmt, 0, sizeof(mgmt));
397 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
398 WLAN_FC_STYPE_DISASSOC);
399 os_memcpy(mgmt.da, addr, ETH_ALEN);
400 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
401 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
402 mgmt.u.disassoc.reason_code = host_to_le16(reason);
403 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
404 IEEE80211_HDRLEN +
405 sizeof(mgmt.u.deauth),
406 encrypt) < 0)
407 return -1;
408 return 0;
409 }
410
411 #ifdef CONFIG_P2P_MANAGER
412 pos = os_strstr(txtaddr, " p2p=");
413 if (pos) {
414 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
415 atoi(pos + 5), addr);
416 }
417 #endif /* CONFIG_P2P_MANAGER */
418
419 if (os_strstr(txtaddr, " tx=0"))
420 hostapd_drv_sta_remove(hapd, addr);
421 else
422 hostapd_drv_sta_disassoc(hapd, addr, reason);
423 sta = ap_get_sta(hapd, addr);
424 if (sta)
425 ap_sta_disassociate(hapd, sta, reason);
426 else if (addr[0] == 0xff)
427 hostapd_free_stas(hapd);
428
429 return 0;
430 }
431
432
433 #ifdef CONFIG_TAXONOMY
hostapd_ctrl_iface_signature(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)434 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 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
442
443 if (hwaddr_aton(txtaddr, addr))
444 return -1;
445
446 sta = ap_get_sta(hapd, addr);
447 if (!sta)
448 return -1;
449
450 return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
451 }
452 #endif /* CONFIG_TAXONOMY */
453
454
hostapd_ctrl_iface_poll_sta(struct hostapd_data * hapd,const char * txtaddr)455 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 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
462
463 if (hwaddr_aton(txtaddr, addr))
464 return -1;
465
466 sta = ap_get_sta(hapd, addr);
467 if (!sta)
468 return -1;
469
470 hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
471 sta->flags & WLAN_STA_WMM);
472 return 0;
473 }
474
475
hostapd_ctrl_iface_status(struct hostapd_data * hapd,char * buf,size_t buflen)476 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
477 size_t buflen)
478 {
479 struct hostapd_iface *iface = hapd->iface;
480 int len = 0, ret;
481 size_t i;
482
483 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 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 iface->ht_op_mode);
510 if (os_snprintf_error(buflen - len, ret))
511 return len;
512 len += ret;
513
514 if (!iface->cac_started || !iface->dfs_cac_ms) {
515 ret = os_snprintf(buf + len, buflen - len,
516 "cac_time_seconds=%d\n"
517 "cac_time_left_seconds=N/A\n",
518 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 os_reltime_age(&iface->dfs_cac_start, &now);
525 left_time = iface->dfs_cac_ms / 1000 - now.sec;
526 ret = os_snprintf(buf + len, buflen - len,
527 "cac_time_seconds=%u\n"
528 "cac_time_left_seconds=%u\n",
529 iface->dfs_cac_ms / 1000,
530 left_time);
531 }
532 if (os_snprintf_error(buflen - len, ret))
533 return len;
534 len += ret;
535
536 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 iface->conf->channel,
542 iface->conf->ieee80211n && !hapd->conf->disable_11n ?
543 iface->conf->secondary_channel : 0,
544 iface->conf->ieee80211n && !hapd->conf->disable_11n,
545 iface->conf->ieee80211ac &&
546 !hapd->conf->disable_11ac);
547 if (os_snprintf_error(buflen - len, ret))
548 return len;
549 len += ret;
550 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
551 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 iface->conf->vht_oper_chwidth,
556 iface->conf->vht_oper_centr_freq_seg0_idx,
557 iface->conf->vht_oper_centr_freq_seg1_idx);
558 if (os_snprintf_error(buflen - len, ret))
559 return len;
560 len += ret;
561 }
562
563 for (i = 0; i < iface->num_bss; i++) {
564 struct hostapd_data *bss = iface->bss[i];
565 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 (int) i, bss->conf->iface,
571 (int) i, MAC2STR(bss->own_addr),
572 (int) i,
573 wpa_ssid_txt(bss->conf->ssid.ssid,
574 bss->conf->ssid.ssid_len),
575 (int) i, bss->num_sta);
576 if (os_snprintf_error(buflen - len, ret))
577 return len;
578 len += ret;
579 }
580
581 return len;
582 }
583
584
hostapd_parse_csa_settings(const char * pos,struct csa_settings * settings)585 int hostapd_parse_csa_settings(const char *pos,
586 struct csa_settings *settings)
587 {
588 char *end;
589
590 os_memset(settings, 0, sizeof(*settings));
591 settings->cs_count = strtol(pos, &end, 10);
592 if (pos == end) {
593 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
594 return -1;
595 }
596
597 settings->freq_params.freq = atoi(end);
598 if (settings->freq_params.freq == 0) {
599 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
600 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 SET_CSA_SETTING(center_freq1);
613 SET_CSA_SETTING(center_freq2);
614 SET_CSA_SETTING(bandwidth);
615 SET_CSA_SETTING(sec_channel_offset);
616 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
617 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
618 settings->block_tx = !!os_strstr(pos, " blocktx");
619 #undef SET_CSA_SETTING
620
621 return 0;
622 }
623
624
hostapd_ctrl_iface_stop_ap(struct hostapd_data * hapd)625 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
626 {
627 return hostapd_drv_stop_ap(hapd);
628 }
629
630
hostapd_ctrl_iface_pmksa_list(struct hostapd_data * hapd,char * buf,size_t len)631 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
632 size_t len)
633 {
634 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
635 }
636
637
hostapd_ctrl_iface_pmksa_flush(struct hostapd_data * hapd)638 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
639 {
640 wpa_auth_pmksa_flush(hapd->wpa_auth);
641 }
642
643
644 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
645 #ifdef CONFIG_MESH
646
hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t len)647 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
648 const u8 *addr, char *buf, size_t len)
649 {
650 return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
651 }
652
653
hostapd_ctrl_iface_pmksa_create_entry(const u8 * aa,char * cmd)654 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
655 {
656 u8 spa[ETH_ALEN];
657 u8 pmkid[PMKID_LEN];
658 u8 pmk[PMK_LEN_MAX];
659 char *pos;
660 int expiration;
661
662 /*
663 * Entry format:
664 * <BSSID> <PMKID> <PMK> <expiration in seconds>
665 */
666
667 if (hwaddr_aton(cmd, spa))
668 return NULL;
669
670 pos = os_strchr(cmd, ' ');
671 if (!pos)
672 return NULL;
673 pos++;
674
675 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
676 return NULL;
677
678 pos = os_strchr(pos, ' ');
679 if (!pos)
680 return NULL;
681 pos++;
682
683 if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
684 return NULL;
685
686 pos = os_strchr(pos, ' ');
687 if (!pos)
688 return NULL;
689 pos++;
690
691 if (sscanf(pos, "%d", &expiration) != 1)
692 return NULL;
693
694 return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
695 }
696
697 #endif /* CONFIG_MESH */
698 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
699