]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/ap/ctrl_iface_ap.c
Merge lld trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / ap / ctrl_iface_ap.c
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 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
30                                            size_t curr_len, const u8 *mcs_set)
31 {
32         int ret;
33         size_t len = curr_len;
34
35         ret = os_snprintf(buf + len, buflen - len,
36                           "ht_mcs_bitmask=");
37         if (os_snprintf_error(buflen - len, ret))
38                 return len;
39         len += ret;
40
41         /* 77 first bits (+ 3 reserved bits) */
42         len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
43
44         ret = os_snprintf(buf + len, buflen - len, "\n");
45         if (os_snprintf_error(buflen - len, ret))
46                 return curr_len;
47         len += ret;
48
49         return len;
50 }
51
52
53 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
54                                  struct sta_info *sta,
55                                  char *buf, size_t buflen)
56 {
57         struct hostap_sta_driver_data data;
58         int ret;
59         int len = 0;
60
61         if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
62                 return 0;
63
64         ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
65                           "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
66                           "signal=%d\n",
67                           data.rx_packets, data.tx_packets,
68                           data.rx_bytes, data.tx_bytes, data.inactive_msec,
69                           data.signal);
70         if (os_snprintf_error(buflen, ret))
71                 return 0;
72         len += ret;
73
74         ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
75                           data.current_rx_rate);
76         if (os_snprintf_error(buflen - len, ret))
77                 return len;
78         len += ret;
79         if (data.flags & STA_DRV_DATA_RX_MCS) {
80                 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
81                                   data.rx_mcs);
82                 if (!os_snprintf_error(buflen - len, ret))
83                         len += ret;
84         }
85         if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
86                 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
87                                   data.rx_vhtmcs);
88                 if (!os_snprintf_error(buflen - len, ret))
89                         len += ret;
90         }
91         if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
92                 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
93                                   data.rx_vht_nss);
94                 if (!os_snprintf_error(buflen - len, ret))
95                         len += ret;
96         }
97         if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
98                 ret = os_snprintf(buf + len, buflen - len, " shortGI");
99                 if (!os_snprintf_error(buflen - len, ret))
100                         len += ret;
101         }
102         ret = os_snprintf(buf + len, buflen - len, "\n");
103         if (!os_snprintf_error(buflen - len, ret))
104                 len += ret;
105
106         ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
107                           data.current_tx_rate);
108         if (os_snprintf_error(buflen - len, ret))
109                 return len;
110         len += ret;
111         if (data.flags & STA_DRV_DATA_TX_MCS) {
112                 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
113                                   data.tx_mcs);
114                 if (!os_snprintf_error(buflen - len, ret))
115                         len += ret;
116         }
117         if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
118                 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
119                                   data.tx_vhtmcs);
120                 if (!os_snprintf_error(buflen - len, ret))
121                         len += ret;
122         }
123         if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
124                 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
125                                   data.tx_vht_nss);
126                 if (!os_snprintf_error(buflen - len, ret))
127                         len += ret;
128         }
129         if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
130                 ret = os_snprintf(buf + len, buflen - len, " shortGI");
131                 if (!os_snprintf_error(buflen - len, ret))
132                         len += ret;
133         }
134         ret = os_snprintf(buf + len, buflen - len, "\n");
135         if (!os_snprintf_error(buflen - len, ret))
136                 len += ret;
137
138         if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
139                 ret = os_snprintf(buf + len, buflen - len,
140                                   "rx_vht_mcs_map=%04x\n"
141                                   "tx_vht_mcs_map=%04x\n",
142                                   le_to_host16(sta->vht_capabilities->
143                                                vht_supported_mcs_set.rx_map),
144                                   le_to_host16(sta->vht_capabilities->
145                                                vht_supported_mcs_set.tx_map));
146                 if (!os_snprintf_error(buflen - len, ret))
147                         len += ret;
148         }
149
150         if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
151                 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
152                                                    sta->ht_capabilities->
153                                                    supported_mcs_set);
154         }
155
156         if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
157                 ret = os_snprintf(buf + len, buflen - len,
158                                   "last_ack_signal=%d\n", data.last_ack_rssi);
159                 if (!os_snprintf_error(buflen - len, ret))
160                         len += ret;
161         }
162
163         return len;
164 }
165
166
167 static int hostapd_get_sta_conn_time(struct sta_info *sta,
168                                      char *buf, size_t buflen)
169 {
170         struct os_reltime age;
171         int ret;
172
173         if (!sta->connected_time.sec)
174                 return 0;
175
176         os_reltime_age(&sta->connected_time, &age);
177
178         ret = os_snprintf(buf, buflen, "connected_time=%u\n",
179                           (unsigned int) age.sec);
180         if (os_snprintf_error(buflen, ret))
181                 return 0;
182         return ret;
183 }
184
185
186 static const char * timeout_next_str(int val)
187 {
188         switch (val) {
189         case STA_NULLFUNC:
190                 return "NULLFUNC POLL";
191         case STA_DISASSOC:
192                 return "DISASSOC";
193         case STA_DEAUTH:
194                 return "DEAUTH";
195         case STA_REMOVE:
196                 return "REMOVE";
197         case STA_DISASSOC_FROM_CLI:
198                 return "DISASSOC_FROM_CLI";
199         }
200
201         return "?";
202 }
203
204
205 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
206                                       struct sta_info *sta,
207                                       char *buf, size_t buflen)
208 {
209         int len, res, ret, i;
210
211         if (!sta)
212                 return 0;
213
214         len = 0;
215         ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
216                           MAC2STR(sta->addr));
217         if (os_snprintf_error(buflen - len, ret))
218                 return len;
219         len += ret;
220
221         ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
222         if (ret < 0)
223                 return len;
224         len += ret;
225
226         ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
227                           "listen_interval=%d\nsupported_rates=",
228                           sta->aid, sta->capability, sta->listen_interval);
229         if (os_snprintf_error(buflen - len, ret))
230                 return len;
231         len += ret;
232
233         for (i = 0; i < sta->supported_rates_len; i++) {
234                 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
235                                   sta->supported_rates[i],
236                                   i + 1 < sta->supported_rates_len ? " " : "");
237                 if (os_snprintf_error(buflen - len, ret))
238                         return len;
239                 len += ret;
240         }
241
242         ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
243                           timeout_next_str(sta->timeout_next));
244         if (os_snprintf_error(buflen - len, ret))
245                 return len;
246         len += ret;
247
248         res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
249         if (res >= 0)
250                 len += res;
251         res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
252         if (res >= 0)
253                 len += res;
254         res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
255         if (res >= 0)
256                 len += res;
257         res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
258                                       buflen - len);
259         if (res >= 0)
260                 len += res;
261         res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
262         if (res >= 0)
263                 len += res;
264
265         len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
266         len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
267
268 #ifdef CONFIG_SAE
269         if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
270                 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
271                                   sta->sae->group);
272                 if (!os_snprintf_error(buflen - len, res))
273                         len += res;
274         }
275 #endif /* CONFIG_SAE */
276
277         if (sta->vlan_id > 0) {
278                 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
279                                   sta->vlan_id);
280                 if (!os_snprintf_error(buflen - len, res))
281                         len += res;
282         }
283
284         res = mbo_ap_get_info(sta, buf + len, buflen - len);
285         if (res >= 0)
286                 len += res;
287
288         if (sta->supp_op_classes &&
289             buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
290                 len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
291                 len += wpa_snprintf_hex(buf + len, buflen - len,
292                                         sta->supp_op_classes + 1,
293                                         sta->supp_op_classes[0]);
294                 len += os_snprintf(buf + len, buflen - len, "\n");
295         }
296
297         if (sta->power_capab) {
298                 ret = os_snprintf(buf + len, buflen - len,
299                                   "min_txpower=%d\n"
300                                   "max_txpower=%d\n",
301                                   sta->min_tx_power, sta->max_tx_power);
302                 if (!os_snprintf_error(buflen - len, ret))
303                         len += ret;
304         }
305
306 #ifdef CONFIG_IEEE80211AC
307         if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
308                 res = os_snprintf(buf + len, buflen - len,
309                                   "vht_caps_info=0x%08x\n",
310                                   le_to_host32(sta->vht_capabilities->
311                                                vht_capabilities_info));
312                 if (!os_snprintf_error(buflen - len, res))
313                         len += res;
314         }
315 #endif /* CONFIG_IEEE80211AC */
316
317 #ifdef CONFIG_IEEE80211N
318         if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
319                 res = os_snprintf(buf + len, buflen - len,
320                                   "ht_caps_info=0x%04x\n",
321                                   le_to_host16(sta->ht_capabilities->
322                                                ht_capabilities_info));
323                 if (!os_snprintf_error(buflen - len, res))
324                         len += res;
325         }
326 #endif /* CONFIG_IEEE80211N */
327
328         if (sta->ext_capability &&
329             buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
330                 len += os_snprintf(buf + len, buflen - len, "ext_capab=");
331                 len += wpa_snprintf_hex(buf + len, buflen - len,
332                                         sta->ext_capability + 1,
333                                         sta->ext_capability[0]);
334                 len += os_snprintf(buf + len, buflen - len, "\n");
335         }
336
337         if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
338                 ret = os_snprintf(buf + len, buflen - len,
339                                   "wds_sta_ifname=%s\n", sta->ifname_wds);
340                 if (!os_snprintf_error(buflen - len, ret))
341                         len += ret;
342         }
343
344         return len;
345 }
346
347
348 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
349                                  char *buf, size_t buflen)
350 {
351         return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
352 }
353
354
355 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
356                            char *buf, size_t buflen)
357 {
358         u8 addr[ETH_ALEN];
359         int ret;
360         const char *pos;
361         struct sta_info *sta;
362
363         if (hwaddr_aton(txtaddr, addr)) {
364                 ret = os_snprintf(buf, buflen, "FAIL\n");
365                 if (os_snprintf_error(buflen, ret))
366                         return 0;
367                 return ret;
368         }
369
370         sta = ap_get_sta(hapd, addr);
371         if (sta == NULL)
372                 return -1;
373
374         pos = os_strchr(txtaddr, ' ');
375         if (pos) {
376                 pos++;
377
378 #ifdef HOSTAPD_DUMP_STATE
379                 if (os_strcmp(pos, "eapol") == 0) {
380                         if (sta->eapol_sm == NULL)
381                                 return -1;
382                         return eapol_auth_dump_state(sta->eapol_sm, buf,
383                                                      buflen);
384                 }
385 #endif /* HOSTAPD_DUMP_STATE */
386
387                 return -1;
388         }
389
390         ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
391         ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
392
393         return ret;
394 }
395
396
397 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
398                                 char *buf, size_t buflen)
399 {
400         u8 addr[ETH_ALEN];
401         struct sta_info *sta;
402         int ret;
403
404         if (hwaddr_aton(txtaddr, addr) ||
405             (sta = ap_get_sta(hapd, addr)) == NULL) {
406                 ret = os_snprintf(buf, buflen, "FAIL\n");
407                 if (os_snprintf_error(buflen, ret))
408                         return 0;
409                 return ret;
410         }
411
412         if (!sta->next)
413                 return 0;
414
415         return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
416 }
417
418
419 #ifdef CONFIG_P2P_MANAGER
420 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
421                                   u8 minor_reason_code, const u8 *addr)
422 {
423         struct ieee80211_mgmt *mgmt;
424         int ret;
425         u8 *pos;
426
427         if (!hapd->drv_priv || !hapd->driver->send_frame)
428                 return -1;
429
430         mgmt = os_zalloc(sizeof(*mgmt) + 100);
431         if (mgmt == NULL)
432                 return -1;
433
434         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
435         wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
436                 " with minor reason code %u (stype=%u (%s))",
437                 MAC2STR(addr), minor_reason_code, stype,
438                 fc2str(le_to_host16(mgmt->frame_control)));
439
440         os_memcpy(mgmt->da, addr, ETH_ALEN);
441         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
442         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
443         if (stype == WLAN_FC_STYPE_DEAUTH) {
444                 mgmt->u.deauth.reason_code =
445                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
446                 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
447         } else {
448                 mgmt->u.disassoc.reason_code =
449                         host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
450                 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
451         }
452
453         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
454         *pos++ = 4 + 3 + 1;
455         WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
456         pos += 4;
457
458         *pos++ = P2P_ATTR_MINOR_REASON_CODE;
459         WPA_PUT_LE16(pos, 1);
460         pos += 2;
461         *pos++ = minor_reason_code;
462
463         ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
464                                        pos - (u8 *) mgmt, 1);
465         os_free(mgmt);
466
467         return ret < 0 ? -1 : 0;
468 }
469 #endif /* CONFIG_P2P_MANAGER */
470
471
472 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
473                                       const char *txtaddr)
474 {
475         u8 addr[ETH_ALEN];
476         struct sta_info *sta;
477         const char *pos;
478         u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
479
480         wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
481                 txtaddr);
482
483         if (hwaddr_aton(txtaddr, addr))
484                 return -1;
485
486         pos = os_strstr(txtaddr, " reason=");
487         if (pos)
488                 reason = atoi(pos + 8);
489
490         pos = os_strstr(txtaddr, " test=");
491         if (pos) {
492                 struct ieee80211_mgmt mgmt;
493                 int encrypt;
494                 if (!hapd->drv_priv || !hapd->driver->send_frame)
495                         return -1;
496                 pos += 6;
497                 encrypt = atoi(pos);
498                 os_memset(&mgmt, 0, sizeof(mgmt));
499                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
500                                                   WLAN_FC_STYPE_DEAUTH);
501                 os_memcpy(mgmt.da, addr, ETH_ALEN);
502                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
503                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
504                 mgmt.u.deauth.reason_code = host_to_le16(reason);
505                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
506                                              IEEE80211_HDRLEN +
507                                              sizeof(mgmt.u.deauth),
508                                              encrypt) < 0)
509                         return -1;
510                 return 0;
511         }
512
513 #ifdef CONFIG_P2P_MANAGER
514         pos = os_strstr(txtaddr, " p2p=");
515         if (pos) {
516                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
517                                               atoi(pos + 5), addr);
518         }
519 #endif /* CONFIG_P2P_MANAGER */
520
521         if (os_strstr(txtaddr, " tx=0"))
522                 hostapd_drv_sta_remove(hapd, addr);
523         else
524                 hostapd_drv_sta_deauth(hapd, addr, reason);
525         sta = ap_get_sta(hapd, addr);
526         if (sta)
527                 ap_sta_deauthenticate(hapd, sta, reason);
528         else if (addr[0] == 0xff)
529                 hostapd_free_stas(hapd);
530
531         return 0;
532 }
533
534
535 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
536                                     const char *txtaddr)
537 {
538         u8 addr[ETH_ALEN];
539         struct sta_info *sta;
540         const char *pos;
541         u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
542
543         wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
544                 txtaddr);
545
546         if (hwaddr_aton(txtaddr, addr))
547                 return -1;
548
549         pos = os_strstr(txtaddr, " reason=");
550         if (pos)
551                 reason = atoi(pos + 8);
552
553         pos = os_strstr(txtaddr, " test=");
554         if (pos) {
555                 struct ieee80211_mgmt mgmt;
556                 int encrypt;
557                 if (!hapd->drv_priv || !hapd->driver->send_frame)
558                         return -1;
559                 pos += 6;
560                 encrypt = atoi(pos);
561                 os_memset(&mgmt, 0, sizeof(mgmt));
562                 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
563                                                   WLAN_FC_STYPE_DISASSOC);
564                 os_memcpy(mgmt.da, addr, ETH_ALEN);
565                 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
566                 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
567                 mgmt.u.disassoc.reason_code = host_to_le16(reason);
568                 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
569                                              IEEE80211_HDRLEN +
570                                              sizeof(mgmt.u.deauth),
571                                              encrypt) < 0)
572                         return -1;
573                 return 0;
574         }
575
576 #ifdef CONFIG_P2P_MANAGER
577         pos = os_strstr(txtaddr, " p2p=");
578         if (pos) {
579                 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
580                                               atoi(pos + 5), addr);
581         }
582 #endif /* CONFIG_P2P_MANAGER */
583
584         if (os_strstr(txtaddr, " tx=0"))
585                 hostapd_drv_sta_remove(hapd, addr);
586         else
587                 hostapd_drv_sta_disassoc(hapd, addr, reason);
588         sta = ap_get_sta(hapd, addr);
589         if (sta)
590                 ap_sta_disassociate(hapd, sta, reason);
591         else if (addr[0] == 0xff)
592                 hostapd_free_stas(hapd);
593
594         return 0;
595 }
596
597
598 #ifdef CONFIG_TAXONOMY
599 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
600                                  const char *txtaddr,
601                                  char *buf, size_t buflen)
602 {
603         u8 addr[ETH_ALEN];
604         struct sta_info *sta;
605
606         wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
607
608         if (hwaddr_aton(txtaddr, addr))
609                 return -1;
610
611         sta = ap_get_sta(hapd, addr);
612         if (!sta)
613                 return -1;
614
615         return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
616 }
617 #endif /* CONFIG_TAXONOMY */
618
619
620 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
621                                 const char *txtaddr)
622 {
623         u8 addr[ETH_ALEN];
624         struct sta_info *sta;
625
626         wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
627
628         if (hwaddr_aton(txtaddr, addr))
629                 return -1;
630
631         sta = ap_get_sta(hapd, addr);
632         if (!sta)
633                 return -1;
634
635         hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
636                                 sta->flags & WLAN_STA_WMM);
637         return 0;
638 }
639
640
641 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
642                               size_t buflen)
643 {
644         struct hostapd_iface *iface = hapd->iface;
645         struct hostapd_hw_modes *mode = iface->current_mode;
646         int len = 0, ret, j;
647         size_t i;
648
649         ret = os_snprintf(buf + len, buflen - len,
650                           "state=%s\n"
651                           "phy=%s\n"
652                           "freq=%d\n"
653                           "num_sta_non_erp=%d\n"
654                           "num_sta_no_short_slot_time=%d\n"
655                           "num_sta_no_short_preamble=%d\n"
656                           "olbc=%d\n"
657                           "num_sta_ht_no_gf=%d\n"
658                           "num_sta_no_ht=%d\n"
659                           "num_sta_ht_20_mhz=%d\n"
660                           "num_sta_ht40_intolerant=%d\n"
661                           "olbc_ht=%d\n"
662                           "ht_op_mode=0x%x\n",
663                           hostapd_state_text(iface->state),
664                           iface->phy,
665                           iface->freq,
666                           iface->num_sta_non_erp,
667                           iface->num_sta_no_short_slot_time,
668                           iface->num_sta_no_short_preamble,
669                           iface->olbc,
670                           iface->num_sta_ht_no_gf,
671                           iface->num_sta_no_ht,
672                           iface->num_sta_ht_20mhz,
673                           iface->num_sta_ht40_intolerant,
674                           iface->olbc_ht,
675                           iface->ht_op_mode);
676         if (os_snprintf_error(buflen - len, ret))
677                 return len;
678         len += ret;
679
680         if (!iface->cac_started || !iface->dfs_cac_ms) {
681                 ret = os_snprintf(buf + len, buflen - len,
682                                   "cac_time_seconds=%d\n"
683                                   "cac_time_left_seconds=N/A\n",
684                                   iface->dfs_cac_ms / 1000);
685         } else {
686                 /* CAC started and CAC time set - calculate remaining time */
687                 struct os_reltime now;
688                 unsigned int left_time;
689
690                 os_reltime_age(&iface->dfs_cac_start, &now);
691                 left_time = iface->dfs_cac_ms / 1000 - now.sec;
692                 ret = os_snprintf(buf + len, buflen - len,
693                                   "cac_time_seconds=%u\n"
694                                   "cac_time_left_seconds=%u\n",
695                                   iface->dfs_cac_ms / 1000,
696                                   left_time);
697         }
698         if (os_snprintf_error(buflen - len, ret))
699                 return len;
700         len += ret;
701
702         ret = os_snprintf(buf + len, buflen - len,
703                           "channel=%u\n"
704                           "secondary_channel=%d\n"
705                           "ieee80211n=%d\n"
706                           "ieee80211ac=%d\n"
707                           "beacon_int=%u\n"
708                           "dtim_period=%d\n",
709                           iface->conf->channel,
710                           iface->conf->ieee80211n && !hapd->conf->disable_11n ?
711                           iface->conf->secondary_channel : 0,
712                           iface->conf->ieee80211n && !hapd->conf->disable_11n,
713                           iface->conf->ieee80211ac &&
714                           !hapd->conf->disable_11ac,
715                           iface->conf->beacon_int,
716                           hapd->conf->dtim_period);
717         if (os_snprintf_error(buflen - len, ret))
718                 return len;
719         len += ret;
720         if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
721                 ret = os_snprintf(buf + len, buflen - len,
722                                   "vht_oper_chwidth=%d\n"
723                                   "vht_oper_centr_freq_seg0_idx=%d\n"
724                                   "vht_oper_centr_freq_seg1_idx=%d\n"
725                                   "vht_caps_info=%08x\n",
726                                   iface->conf->vht_oper_chwidth,
727                                   iface->conf->vht_oper_centr_freq_seg0_idx,
728                                   iface->conf->vht_oper_centr_freq_seg1_idx,
729                                   iface->conf->vht_capab);
730                 if (os_snprintf_error(buflen - len, ret))
731                         return len;
732                 len += ret;
733         }
734
735         if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
736                 u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
737                 u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
738
739                 ret = os_snprintf(buf + len, buflen - len,
740                                   "rx_vht_mcs_map=%04x\n"
741                                   "tx_vht_mcs_map=%04x\n",
742                                   rxmap, txmap);
743                 if (os_snprintf_error(buflen - len, ret))
744                         return len;
745                 len += ret;
746         }
747
748         if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
749                 ret = os_snprintf(buf + len, buflen - len,
750                                   "ht_caps_info=%04x\n",
751                                   hapd->iconf->ht_capab);
752                 if (os_snprintf_error(buflen - len, ret))
753                         return len;
754                 len += ret;
755         }
756
757         if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
758                 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
759                                                    mode->mcs_set);
760         }
761
762         if (iface->current_rates && iface->num_rates) {
763                 ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
764                 if (os_snprintf_error(buflen - len, ret))
765                         return len;
766                 len += ret;
767
768                 for (j = 0; j < iface->num_rates; j++) {
769                         ret = os_snprintf(buf + len, buflen - len, "%s%02x",
770                                           j > 0 ? " " : "",
771                                           iface->current_rates[j].rate / 5);
772                         if (os_snprintf_error(buflen - len, ret))
773                                 return len;
774                         len += ret;
775                 }
776                 ret = os_snprintf(buf + len, buflen - len, "\n");
777                 if (os_snprintf_error(buflen - len, ret))
778                         return len;
779                 len += ret;
780         }
781
782         for (j = 0; mode && j < mode->num_channels; j++) {
783                 if (mode->channels[j].freq == iface->freq) {
784                         ret = os_snprintf(buf + len, buflen - len,
785                                           "max_txpower=%u\n",
786                                           mode->channels[j].max_tx_power);
787                         if (os_snprintf_error(buflen - len, ret))
788                                 return len;
789                         len += ret;
790                         break;
791                 }
792         }
793
794         for (i = 0; i < iface->num_bss; i++) {
795                 struct hostapd_data *bss = iface->bss[i];
796                 ret = os_snprintf(buf + len, buflen - len,
797                                   "bss[%d]=%s\n"
798                                   "bssid[%d]=" MACSTR "\n"
799                                   "ssid[%d]=%s\n"
800                                   "num_sta[%d]=%d\n",
801                                   (int) i, bss->conf->iface,
802                                   (int) i, MAC2STR(bss->own_addr),
803                                   (int) i,
804                                   wpa_ssid_txt(bss->conf->ssid.ssid,
805                                                bss->conf->ssid.ssid_len),
806                                   (int) i, bss->num_sta);
807                 if (os_snprintf_error(buflen - len, ret))
808                         return len;
809                 len += ret;
810         }
811
812         if (hapd->conf->chan_util_avg_period) {
813                 ret = os_snprintf(buf + len, buflen - len,
814                                   "chan_util_avg=%u\n",
815                                   iface->chan_util_average);
816                 if (os_snprintf_error(buflen - len, ret))
817                         return len;
818                 len += ret;
819         }
820
821         return len;
822 }
823
824
825 int hostapd_parse_csa_settings(const char *pos,
826                                struct csa_settings *settings)
827 {
828         char *end;
829
830         os_memset(settings, 0, sizeof(*settings));
831         settings->cs_count = strtol(pos, &end, 10);
832         if (pos == end) {
833                 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
834                 return -1;
835         }
836
837         settings->freq_params.freq = atoi(end);
838         if (settings->freq_params.freq == 0) {
839                 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
840                 return -1;
841         }
842
843 #define SET_CSA_SETTING(str) \
844         do { \
845                 const char *pos2 = os_strstr(pos, " " #str "="); \
846                 if (pos2) { \
847                         pos2 += sizeof(" " #str "=") - 1; \
848                         settings->freq_params.str = atoi(pos2); \
849                 } \
850         } while (0)
851
852         SET_CSA_SETTING(center_freq1);
853         SET_CSA_SETTING(center_freq2);
854         SET_CSA_SETTING(bandwidth);
855         SET_CSA_SETTING(sec_channel_offset);
856         settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
857         settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
858         settings->block_tx = !!os_strstr(pos, " blocktx");
859 #undef SET_CSA_SETTING
860
861         return 0;
862 }
863
864
865 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
866 {
867         return hostapd_drv_stop_ap(hapd);
868 }
869
870
871 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
872                                   size_t len)
873 {
874         return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
875 }
876
877
878 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
879 {
880         wpa_auth_pmksa_flush(hapd->wpa_auth);
881 }
882
883
884 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
885 {
886         u8 spa[ETH_ALEN];
887         u8 pmkid[PMKID_LEN];
888         u8 pmk[PMK_LEN_MAX];
889         size_t pmk_len;
890         char *pos, *pos2;
891         int akmp = 0, expiration = 0;
892
893         /*
894          * Entry format:
895          * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
896          */
897
898         if (hwaddr_aton(cmd, spa))
899                 return -1;
900
901         pos = os_strchr(cmd, ' ');
902         if (!pos)
903                 return -1;
904         pos++;
905
906         if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
907                 return -1;
908
909         pos = os_strchr(pos, ' ');
910         if (!pos)
911                 return -1;
912         pos++;
913
914         pos2 = os_strchr(pos, ' ');
915         if (!pos2)
916                 return -1;
917         pmk_len = (pos2 - pos) / 2;
918         if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
919             hexstr2bin(pos, pmk, pmk_len) < 0)
920                 return -1;
921
922         pos = pos2 + 1;
923
924         if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
925                 return -1;
926
927         return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
928                                    pmkid, expiration, akmp);
929 }
930
931
932 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
933 #ifdef CONFIG_MESH
934
935 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
936                                        const u8 *addr, char *buf, size_t len)
937 {
938         return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
939 }
940
941
942 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
943 {
944         u8 spa[ETH_ALEN];
945         u8 pmkid[PMKID_LEN];
946         u8 pmk[PMK_LEN_MAX];
947         char *pos;
948         int expiration;
949
950         /*
951          * Entry format:
952          * <BSSID> <PMKID> <PMK> <expiration in seconds>
953          */
954
955         if (hwaddr_aton(cmd, spa))
956                 return NULL;
957
958         pos = os_strchr(cmd, ' ');
959         if (!pos)
960                 return NULL;
961         pos++;
962
963         if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
964                 return NULL;
965
966         pos = os_strchr(pos, ' ');
967         if (!pos)
968                 return NULL;
969         pos++;
970
971         if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
972                 return NULL;
973
974         pos = os_strchr(pos, ' ');
975         if (!pos)
976                 return NULL;
977         pos++;
978
979         if (sscanf(pos, "%d", &expiration) != 1)
980                 return NULL;
981
982         return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
983 }
984
985 #endif /* CONFIG_MESH */
986 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */