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