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 #include "wnm_ap.h"
28 
29 
hostapd_write_ht_mcs_bitmask(char * buf,size_t buflen,size_t curr_len,const u8 * mcs_set)30 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
31                                                      size_t curr_len, const u8 *mcs_set)
32 {
33           int ret;
34           size_t len = curr_len;
35 
36           ret = os_snprintf(buf + len, buflen - len,
37                                 "ht_mcs_bitmask=");
38           if (os_snprintf_error(buflen - len, ret))
39                     return len;
40           len += ret;
41 
42           /* 77 first bits (+ 3 reserved bits) */
43           len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
44 
45           ret = os_snprintf(buf + len, buflen - len, "\n");
46           if (os_snprintf_error(buflen - len, ret))
47                     return curr_len;
48           len += ret;
49 
50           return len;
51 }
52 
53 
hostapd_get_sta_conn_time(struct sta_info * sta,struct hostap_sta_driver_data * data,char * buf,size_t buflen)54 static int hostapd_get_sta_conn_time(struct sta_info *sta,
55                                              struct hostap_sta_driver_data *data,
56                                              char *buf, size_t buflen)
57 {
58           struct os_reltime age;
59           unsigned long secs;
60           int ret;
61 
62           if (sta->connected_time.sec) {
63                     /* Locally maintained time in AP mode */
64                     os_reltime_age(&sta->connected_time, &age);
65                     secs = (unsigned long) age.sec;
66           } else if (data->flags & STA_DRV_DATA_CONN_TIME) {
67                     /* Time from the driver in mesh mode */
68                     secs = data->connected_sec;
69           } else {
70                     return 0;
71           }
72 
73           ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
74           if (os_snprintf_error(buflen, ret))
75                     return 0;
76           return ret;
77 }
78 
79 
hostapd_get_sta_info(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)80 static int hostapd_get_sta_info(struct hostapd_data *hapd,
81                                         struct sta_info *sta,
82                                         char *buf, size_t buflen)
83 {
84           struct hostap_sta_driver_data data;
85           int ret;
86           int len = 0;
87 
88           if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
89                     return 0;
90 
91           ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
92                                 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
93                                 "signal=%d\n",
94                                 data.rx_packets, data.tx_packets,
95                                 data.rx_bytes, data.tx_bytes, data.inactive_msec,
96                                 data.signal);
97           if (os_snprintf_error(buflen, ret))
98                     return 0;
99           len += ret;
100 
101           ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
102                                 data.current_rx_rate / 100);
103           if (os_snprintf_error(buflen - len, ret))
104                     return len;
105           len += ret;
106           if (data.flags & STA_DRV_DATA_RX_MCS) {
107                     ret = os_snprintf(buf + len, buflen - len, " mcs %u",
108                                           data.rx_mcs);
109                     if (!os_snprintf_error(buflen - len, ret))
110                               len += ret;
111           }
112           if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
113                     ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
114                                           data.rx_vhtmcs);
115                     if (!os_snprintf_error(buflen - len, ret))
116                               len += ret;
117           }
118           if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
119                     ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
120                                           data.rx_vht_nss);
121                     if (!os_snprintf_error(buflen - len, ret))
122                               len += ret;
123           }
124           if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
125                     ret = os_snprintf(buf + len, buflen - len, " shortGI");
126                     if (!os_snprintf_error(buflen - len, ret))
127                               len += ret;
128           }
129           ret = os_snprintf(buf + len, buflen - len, "\n");
130           if (!os_snprintf_error(buflen - len, ret))
131                     len += ret;
132 
133           ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
134                                 data.current_tx_rate / 100);
135           if (os_snprintf_error(buflen - len, ret))
136                     return len;
137           len += ret;
138           if (data.flags & STA_DRV_DATA_TX_MCS) {
139                     ret = os_snprintf(buf + len, buflen - len, " mcs %u",
140                                           data.tx_mcs);
141                     if (!os_snprintf_error(buflen - len, ret))
142                               len += ret;
143           }
144           if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
145                     ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
146                                           data.tx_vhtmcs);
147                     if (!os_snprintf_error(buflen - len, ret))
148                               len += ret;
149           }
150           if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
151                     ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
152                                           data.tx_vht_nss);
153                     if (!os_snprintf_error(buflen - len, ret))
154                               len += ret;
155           }
156           if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
157                     ret = os_snprintf(buf + len, buflen - len, " shortGI");
158                     if (!os_snprintf_error(buflen - len, ret))
159                               len += ret;
160           }
161           ret = os_snprintf(buf + len, buflen - len, "\n");
162           if (!os_snprintf_error(buflen - len, ret))
163                     len += ret;
164 
165           if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
166                     ret = os_snprintf(buf + len, buflen - len,
167                                           "rx_vht_mcs_map=%04x\n"
168                                           "tx_vht_mcs_map=%04x\n",
169                                           le_to_host16(sta->vht_capabilities->
170                                                          vht_supported_mcs_set.rx_map),
171                                           le_to_host16(sta->vht_capabilities->
172                                                          vht_supported_mcs_set.tx_map));
173                     if (!os_snprintf_error(buflen - len, ret))
174                               len += ret;
175           }
176 
177           if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
178                     len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
179                                                                sta->ht_capabilities->
180                                                                supported_mcs_set);
181           }
182 
183           if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
184                     ret = os_snprintf(buf + len, buflen - len,
185                                           "last_ack_signal=%d\n", data.last_ack_rssi);
186                     if (!os_snprintf_error(buflen - len, ret))
187                               len += ret;
188           }
189 
190           len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
191 
192           return len;
193 }
194 
195 
timeout_next_str(int val)196 static const char * timeout_next_str(int val)
197 {
198           switch (val) {
199           case STA_NULLFUNC:
200                     return "NULLFUNC POLL";
201           case STA_DISASSOC:
202                     return "DISASSOC";
203           case STA_DEAUTH:
204                     return "DEAUTH";
205           case STA_REMOVE:
206                     return "REMOVE";
207           case STA_DISASSOC_FROM_CLI:
208                     return "DISASSOC_FROM_CLI";
209           default:
210                     return "?";
211           }
212 }
213 
214 
hw_mode_str(enum hostapd_hw_mode mode)215 static const char * hw_mode_str(enum hostapd_hw_mode mode)
216 {
217           switch (mode) {
218           case HOSTAPD_MODE_IEEE80211B:
219                     return "b";
220           case HOSTAPD_MODE_IEEE80211G:
221                     return "g";
222           case HOSTAPD_MODE_IEEE80211A:
223                     return "a";
224           case HOSTAPD_MODE_IEEE80211AD:
225                     return "ad";
226           case HOSTAPD_MODE_IEEE80211ANY:
227                     return "any";
228           case NUM_HOSTAPD_MODES:
229                     return "invalid";
230           }
231           return "unknown";
232 }
233 
234 
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)235 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
236                                               struct sta_info *sta,
237                                               char *buf, size_t buflen)
238 {
239           int len, res, ret, i;
240           const char *keyid;
241           const u8 *dpp_pkhash;
242 
243           if (!sta)
244                     return 0;
245 
246           len = 0;
247           ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
248                                 MAC2STR(sta->addr));
249           if (os_snprintf_error(buflen - len, ret))
250                     return len;
251           len += ret;
252 
253           ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
254           if (ret < 0)
255                     return len;
256           len += ret;
257 
258           ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
259                                 "listen_interval=%d\nsupported_rates=",
260                                 sta->aid, sta->capability, sta->listen_interval);
261           if (os_snprintf_error(buflen - len, ret))
262                     return len;
263           len += ret;
264 
265           for (i = 0; i < sta->supported_rates_len; i++) {
266                     ret = os_snprintf(buf + len, buflen - len, "%02x%s",
267                                           sta->supported_rates[i],
268                                           i + 1 < sta->supported_rates_len ? " " : "");
269                     if (os_snprintf_error(buflen - len, ret))
270                               return len;
271                     len += ret;
272           }
273 
274           ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
275                                 timeout_next_str(sta->timeout_next));
276           if (os_snprintf_error(buflen - len, ret))
277                     return len;
278           len += ret;
279 
280           if (sta->max_idle_period) {
281                     ret = os_snprintf(buf + len, buflen - len,
282                                           "max_idle_period=%d\n", sta->max_idle_period);
283                     if (os_snprintf_error(buflen - len, ret))
284                               return len;
285                     len += ret;
286           }
287 
288           res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
289           if (res >= 0)
290                     len += res;
291           res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
292           if (res >= 0)
293                     len += res;
294           res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
295           if (res >= 0)
296                     len += res;
297           res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
298                                               buflen - len);
299           if (res >= 0)
300                     len += res;
301           res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
302           if (res >= 0)
303                     len += res;
304 
305           len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
306 
307 #ifdef CONFIG_SAE
308           if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
309                     res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
310                                           sta->sae->group);
311                     if (!os_snprintf_error(buflen - len, res))
312                               len += res;
313           }
314 
315           if (sta->sae && sta->sae->tmp) {
316                     const u8 *pos;
317                     unsigned int j, count;
318                     struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
319 
320                     res = os_snprintf(buf + len, buflen - len,
321                                           "sae_rejected_groups=");
322                     if (!os_snprintf_error(buflen - len, res))
323                               len += res;
324 
325                     if (groups) {
326                               pos = wpabuf_head(groups);
327                               count = wpabuf_len(groups) / 2;
328                     } else {
329                               pos = NULL;
330                               count = 0;
331                     }
332                     for (j = 0; pos && j < count; j++) {
333                               res = os_snprintf(buf + len, buflen - len, "%s%d",
334                                                     j == 0 ? "" : " ", WPA_GET_LE16(pos));
335                               if (!os_snprintf_error(buflen - len, res))
336                                         len += res;
337                               pos += 2;
338                     }
339 
340                     res = os_snprintf(buf + len, buflen - len, "\n");
341                     if (!os_snprintf_error(buflen - len, res))
342                               len += res;
343           }
344 #endif /* CONFIG_SAE */
345 
346           if (sta->vlan_id > 0) {
347                     res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
348                                           sta->vlan_id);
349                     if (!os_snprintf_error(buflen - len, res))
350                               len += res;
351           }
352 
353           res = mbo_ap_get_info(sta, buf + len, buflen - len);
354           if (res >= 0)
355                     len += res;
356 
357           if (sta->supp_op_classes &&
358               buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
359                     res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
360                     if (!os_snprintf_error(buflen - len, res))
361                               len += res;
362                     len += wpa_snprintf_hex(buf + len, buflen - len,
363                                                   sta->supp_op_classes + 1,
364                                                   sta->supp_op_classes[0]);
365                     res = os_snprintf(buf + len, buflen - len, "\n");
366                     if (!os_snprintf_error(buflen - len, res))
367                               len += res;
368           }
369 
370           if (sta->power_capab) {
371                     ret = os_snprintf(buf + len, buflen - len,
372                                           "min_txpower=%d\n"
373                                           "max_txpower=%d\n",
374                                           sta->min_tx_power, sta->max_tx_power);
375                     if (!os_snprintf_error(buflen - len, ret))
376                               len += ret;
377           }
378 
379 #ifdef CONFIG_IEEE80211AX
380           if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
381                     res = os_snprintf(buf + len, buflen - len, "he_capab=");
382                     if (!os_snprintf_error(buflen - len, res))
383                               len += res;
384                     len += wpa_snprintf_hex(buf + len, buflen - len,
385                                                   (const u8 *) sta->he_capab,
386                                                   sta->he_capab_len);
387                     res = os_snprintf(buf + len, buflen - len, "\n");
388                     if (!os_snprintf_error(buflen - len, res))
389                               len += res;
390           }
391 #endif /* CONFIG_IEEE80211AX */
392 
393 #ifdef CONFIG_IEEE80211BE
394           if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
395                     res = os_snprintf(buf + len, buflen - len, "eht_capab=");
396                     if (!os_snprintf_error(buflen - len, res))
397                               len += res;
398                     len += wpa_snprintf_hex(buf + len, buflen - len,
399                                                   (const u8 *) sta->eht_capab,
400                                                   sta->eht_capab_len);
401                     res = os_snprintf(buf + len, buflen - len, "\n");
402                     if (!os_snprintf_error(buflen - len, res))
403                               len += res;
404           }
405 #endif /* CONFIG_IEEE80211BE */
406 
407 #ifdef CONFIG_IEEE80211AC
408           if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
409                     res = os_snprintf(buf + len, buflen - len,
410                                           "vht_caps_info=0x%08x\n",
411                                           le_to_host32(sta->vht_capabilities->
412                                                          vht_capabilities_info));
413                     if (!os_snprintf_error(buflen - len, res))
414                               len += res;
415 
416                     res = os_snprintf(buf + len, buflen - len, "vht_capab=");
417                     if (!os_snprintf_error(buflen - len, res))
418                               len += res;
419                     len += wpa_snprintf_hex(buf + len, buflen - len,
420                                                   (const u8 *) sta->vht_capabilities,
421                                                   sizeof(*sta->vht_capabilities));
422                     res = os_snprintf(buf + len, buflen - len, "\n");
423                     if (!os_snprintf_error(buflen - len, res))
424                               len += res;
425           }
426 #endif /* CONFIG_IEEE80211AC */
427 
428           if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
429                     res = os_snprintf(buf + len, buflen - len,
430                                           "ht_caps_info=0x%04x\n",
431                                           le_to_host16(sta->ht_capabilities->
432                                                          ht_capabilities_info));
433                     if (!os_snprintf_error(buflen - len, res))
434                               len += res;
435           }
436 
437           if (sta->ext_capability &&
438               buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
439                     res = os_snprintf(buf + len, buflen - len, "ext_capab=");
440                     if (!os_snprintf_error(buflen - len, res))
441                               len += res;
442                     len += wpa_snprintf_hex(buf + len, buflen - len,
443                                                   sta->ext_capability + 1,
444                                                   sta->ext_capability[0]);
445                     res = os_snprintf(buf + len, buflen - len, "\n");
446                     if (!os_snprintf_error(buflen - len, res))
447                               len += res;
448           }
449 
450           if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
451                     ret = os_snprintf(buf + len, buflen - len,
452                                           "wds_sta_ifname=%s\n", sta->ifname_wds);
453                     if (!os_snprintf_error(buflen - len, ret))
454                               len += ret;
455           }
456 
457           keyid = ap_sta_wpa_get_keyid(hapd, sta);
458           if (keyid) {
459                     ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
460                     if (!os_snprintf_error(buflen - len, ret))
461                               len += ret;
462           }
463 
464           dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
465           if (dpp_pkhash) {
466                     ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
467                     if (!os_snprintf_error(buflen - len, ret))
468                               len += ret;
469                     len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
470                                                   SHA256_MAC_LEN);
471                     ret = os_snprintf(buf + len, buflen - len, "\n");
472                     if (!os_snprintf_error(buflen - len, ret))
473                               len += ret;
474           }
475 
476 #ifdef CONFIG_IEEE80211BE
477           if (sta->mld_info.mld_sta) {
478                     for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
479                               if (!sta->mld_info.links[i].valid)
480                                         continue;
481                               ret = os_snprintf(
482                                         buf + len, buflen - len,
483                                         "peer_addr[%d]=" MACSTR "\n",
484                                         i, MAC2STR(sta->mld_info.links[i].peer_addr));
485                               if (!os_snprintf_error(buflen - len, ret))
486                                         len += ret;
487                     }
488           }
489 #endif /* CONFIG_IEEE80211BE */
490 
491           return len;
492 }
493 
494 
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)495 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
496                                          char *buf, size_t buflen)
497 {
498           return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
499 }
500 
501 
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)502 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
503                                  char *buf, size_t buflen)
504 {
505           u8 addr[ETH_ALEN];
506           int ret;
507           const char *pos;
508           struct sta_info *sta;
509 
510           if (hwaddr_aton(txtaddr, addr)) {
511                     ret = os_snprintf(buf, buflen, "FAIL\n");
512                     if (os_snprintf_error(buflen, ret))
513                               return 0;
514                     return ret;
515           }
516 
517           sta = ap_get_sta(hapd, addr);
518           if (sta == NULL)
519                     return -1;
520 
521           pos = os_strchr(txtaddr, ' ');
522           if (pos) {
523                     pos++;
524 
525 #ifdef HOSTAPD_DUMP_STATE
526                     if (os_strcmp(pos, "eapol") == 0) {
527                               if (sta->eapol_sm == NULL)
528                                         return -1;
529                               return eapol_auth_dump_state(sta->eapol_sm, buf,
530                                                                  buflen);
531                     }
532 #endif /* HOSTAPD_DUMP_STATE */
533 
534                     return -1;
535           }
536 
537           ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
538           ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
539 
540           return ret;
541 }
542 
543 
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)544 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
545                                         char *buf, size_t buflen)
546 {
547           u8 addr[ETH_ALEN];
548           struct sta_info *sta;
549           int ret;
550 
551           if (hwaddr_aton(txtaddr, addr) ||
552               (sta = ap_get_sta(hapd, addr)) == NULL) {
553                     ret = os_snprintf(buf, buflen, "FAIL\n");
554                     if (os_snprintf_error(buflen, ret))
555                               return 0;
556                     return ret;
557           }
558 
559           if (!sta->next)
560                     return 0;
561 
562           return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
563 }
564 
565 
566 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)567 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
568                                           u8 minor_reason_code, const u8 *addr)
569 {
570           struct ieee80211_mgmt *mgmt;
571           int ret;
572           u8 *pos;
573 
574           mgmt = os_zalloc(sizeof(*mgmt) + 100);
575           if (mgmt == NULL)
576                     return -1;
577 
578           mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
579           wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
580                     " with minor reason code %u (stype=%u (%s))",
581                     MAC2STR(addr), minor_reason_code, stype,
582                     fc2str(le_to_host16(mgmt->frame_control)));
583 
584           os_memcpy(mgmt->da, addr, ETH_ALEN);
585           os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
586           os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
587           if (stype == WLAN_FC_STYPE_DEAUTH) {
588                     mgmt->u.deauth.reason_code =
589                               host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
590                     pos = mgmt->u.deauth.variable;
591           } else {
592                     mgmt->u.disassoc.reason_code =
593                               host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
594                     pos = mgmt->u.disassoc.variable;
595           }
596 
597           *pos++ = WLAN_EID_VENDOR_SPECIFIC;
598           *pos++ = 4 + 3 + 1;
599           WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
600           pos += 4;
601 
602           *pos++ = P2P_ATTR_MINOR_REASON_CODE;
603           WPA_PUT_LE16(pos, 1);
604           pos += 2;
605           *pos++ = minor_reason_code;
606 
607           ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
608                                             0);
609           os_free(mgmt);
610 
611           return ret < 0 ? -1 : 0;
612 }
613 #endif /* CONFIG_P2P_MANAGER */
614 
615 
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)616 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
617                                               const char *txtaddr)
618 {
619           u8 addr[ETH_ALEN];
620           struct sta_info *sta;
621           const char *pos;
622           u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
623 
624           wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
625                     txtaddr);
626 
627           if (hwaddr_aton(txtaddr, addr))
628                     return -1;
629 
630           pos = os_strstr(txtaddr, " reason=");
631           if (pos)
632                     reason = atoi(pos + 8);
633 
634           pos = os_strstr(txtaddr, " test=");
635           if (pos) {
636                     struct ieee80211_mgmt mgmt;
637                     int encrypt;
638 
639                     pos += 6;
640                     encrypt = atoi(pos);
641                     os_memset(&mgmt, 0, sizeof(mgmt));
642                     mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
643                                                               WLAN_FC_STYPE_DEAUTH);
644                     os_memcpy(mgmt.da, addr, ETH_ALEN);
645                     os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
646                     os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
647                     mgmt.u.deauth.reason_code = host_to_le16(reason);
648                     if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
649                                                     IEEE80211_HDRLEN +
650                                                     sizeof(mgmt.u.deauth),
651                                                     0, NULL, 0, !encrypt) < 0)
652                               return -1;
653                     return 0;
654           }
655 
656 #ifdef CONFIG_P2P_MANAGER
657           pos = os_strstr(txtaddr, " p2p=");
658           if (pos) {
659                     return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
660                                                         atoi(pos + 5), addr);
661           }
662 #endif /* CONFIG_P2P_MANAGER */
663 
664           if (os_strstr(txtaddr, " tx=0"))
665                     hostapd_drv_sta_remove(hapd, addr);
666           else
667                     hostapd_drv_sta_deauth(hapd, addr, reason);
668           sta = ap_get_sta(hapd, addr);
669           if (sta)
670                     ap_sta_deauthenticate(hapd, sta, reason);
671           else if (addr[0] == 0xff)
672                     hostapd_free_stas(hapd);
673 
674           return 0;
675 }
676 
677 
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)678 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
679                                             const char *txtaddr)
680 {
681           u8 addr[ETH_ALEN];
682           struct sta_info *sta;
683           const char *pos;
684           u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
685 
686           wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
687                     txtaddr);
688 
689           if (hwaddr_aton(txtaddr, addr))
690                     return -1;
691 
692           pos = os_strstr(txtaddr, " reason=");
693           if (pos)
694                     reason = atoi(pos + 8);
695 
696           pos = os_strstr(txtaddr, " test=");
697           if (pos) {
698                     struct ieee80211_mgmt mgmt;
699                     int encrypt;
700 
701                     pos += 6;
702                     encrypt = atoi(pos);
703                     os_memset(&mgmt, 0, sizeof(mgmt));
704                     mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
705                                                               WLAN_FC_STYPE_DISASSOC);
706                     os_memcpy(mgmt.da, addr, ETH_ALEN);
707                     os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
708                     os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
709                     mgmt.u.disassoc.reason_code = host_to_le16(reason);
710                     if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
711                                                     IEEE80211_HDRLEN +
712                                                     sizeof(mgmt.u.deauth),
713                                                     0, NULL, 0, !encrypt) < 0)
714                               return -1;
715                     return 0;
716           }
717 
718 #ifdef CONFIG_P2P_MANAGER
719           pos = os_strstr(txtaddr, " p2p=");
720           if (pos) {
721                     return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
722                                                         atoi(pos + 5), addr);
723           }
724 #endif /* CONFIG_P2P_MANAGER */
725 
726           if (os_strstr(txtaddr, " tx=0"))
727                     hostapd_drv_sta_remove(hapd, addr);
728           else
729                     hostapd_drv_sta_disassoc(hapd, addr, reason);
730           sta = ap_get_sta(hapd, addr);
731           if (sta)
732                     ap_sta_disassociate(hapd, sta, reason);
733           else if (addr[0] == 0xff)
734                     hostapd_free_stas(hapd);
735 
736           return 0;
737 }
738 
739 
740 #ifdef CONFIG_TAXONOMY
hostapd_ctrl_iface_signature(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)741 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
742                                          const char *txtaddr,
743                                          char *buf, size_t buflen)
744 {
745           u8 addr[ETH_ALEN];
746           struct sta_info *sta;
747 
748           wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
749 
750           if (hwaddr_aton(txtaddr, addr))
751                     return -1;
752 
753           sta = ap_get_sta(hapd, addr);
754           if (!sta)
755                     return -1;
756 
757           return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
758 }
759 #endif /* CONFIG_TAXONOMY */
760 
761 
hostapd_ctrl_iface_poll_sta(struct hostapd_data * hapd,const char * txtaddr)762 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
763                                         const char *txtaddr)
764 {
765           u8 addr[ETH_ALEN];
766           struct sta_info *sta;
767 
768           wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
769 
770           if (hwaddr_aton(txtaddr, addr))
771                     return -1;
772 
773           sta = ap_get_sta(hapd, addr);
774           if (!sta)
775                     return -1;
776 
777           hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
778                                         sta->flags & WLAN_STA_WMM);
779           return 0;
780 }
781 
782 
hostapd_ctrl_iface_status(struct hostapd_data * hapd,char * buf,size_t buflen)783 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
784                                     size_t buflen)
785 {
786           struct hostapd_iface *iface = hapd->iface;
787           struct hostapd_hw_modes *mode = iface->current_mode;
788           struct hostapd_config *iconf = hapd->iconf;
789           int len = 0, ret, j;
790           size_t i;
791 
792           ret = os_snprintf(buf + len, buflen - len,
793                                 "state=%s\n"
794                                 "phy=%s\n"
795                                 "freq=%d\n"
796                                 "num_sta_non_erp=%d\n"
797                                 "num_sta_no_short_slot_time=%d\n"
798                                 "num_sta_no_short_preamble=%d\n"
799                                 "olbc=%d\n"
800                                 "num_sta_ht_no_gf=%d\n"
801                                 "num_sta_no_ht=%d\n"
802                                 "num_sta_ht_20_mhz=%d\n"
803                                 "num_sta_ht40_intolerant=%d\n"
804                                 "olbc_ht=%d\n"
805                                 "ht_op_mode=0x%x\n",
806                                 hostapd_state_text(iface->state),
807                                 iface->phy,
808                                 iface->freq,
809                                 iface->num_sta_non_erp,
810                                 iface->num_sta_no_short_slot_time,
811                                 iface->num_sta_no_short_preamble,
812                                 iface->olbc,
813                                 iface->num_sta_ht_no_gf,
814                                 iface->num_sta_no_ht,
815                                 iface->num_sta_ht_20mhz,
816                                 iface->num_sta_ht40_intolerant,
817                                 iface->olbc_ht,
818                                 iface->ht_op_mode);
819           if (os_snprintf_error(buflen - len, ret))
820                     return len;
821           len += ret;
822 
823           if (mode) {
824                     ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
825                                           hw_mode_str(mode->mode));
826                     if (os_snprintf_error(buflen - len, ret))
827                               return len;
828                     len += ret;
829           }
830 
831           if (iconf->country[0] && iconf->country[1]) {
832                     ret = os_snprintf(buf + len, buflen - len,
833                                           "country_code=%c%c\ncountry3=0x%X\n",
834                                           iconf->country[0], iconf->country[1],
835                                           iconf->country[2]);
836                     if (os_snprintf_error(buflen - len, ret))
837                               return len;
838                     len += ret;
839           }
840 
841           if (!iface->cac_started || !iface->dfs_cac_ms) {
842                     ret = os_snprintf(buf + len, buflen - len,
843                                           "cac_time_seconds=%d\n"
844                                           "cac_time_left_seconds=N/A\n",
845                                           iface->dfs_cac_ms / 1000);
846           } else {
847                     /* CAC started and CAC time set - calculate remaining time */
848                     struct os_reltime now;
849                     long left_time;
850 
851                     os_reltime_age(&iface->dfs_cac_start, &now);
852                     left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
853                     ret = os_snprintf(buf + len, buflen - len,
854                                           "cac_time_seconds=%u\n"
855                                           "cac_time_left_seconds=%lu\n",
856                                           iface->dfs_cac_ms / 1000,
857                                           left_time > 0 ? left_time : 0);
858           }
859           if (os_snprintf_error(buflen - len, ret))
860                     return len;
861           len += ret;
862 
863           ret = os_snprintf(buf + len, buflen - len,
864                                 "channel=%u\n"
865                                 "edmg_enable=%d\n"
866                                 "edmg_channel=%d\n"
867                                 "secondary_channel=%d\n"
868                                 "ieee80211n=%d\n"
869                                 "ieee80211ac=%d\n"
870                                 "ieee80211ax=%d\n"
871                                 "ieee80211be=%d\n"
872                                 "beacon_int=%u\n"
873                                 "dtim_period=%d\n",
874                                 iface->conf->channel,
875                                 iface->conf->enable_edmg,
876                                 iface->conf->edmg_channel,
877                                 iface->conf->ieee80211n && !hapd->conf->disable_11n ?
878                                 iface->conf->secondary_channel : 0,
879                                 iface->conf->ieee80211n && !hapd->conf->disable_11n,
880                                 iface->conf->ieee80211ac &&
881                                 !hapd->conf->disable_11ac,
882                                 iface->conf->ieee80211ax &&
883                                 !hapd->conf->disable_11ax,
884                                 iface->conf->ieee80211be &&
885                                 !hapd->conf->disable_11be,
886                                 iface->conf->beacon_int,
887                                 hapd->conf->dtim_period);
888           if (os_snprintf_error(buflen - len, ret))
889                     return len;
890           len += ret;
891 
892 #ifdef CONFIG_IEEE80211BE
893           if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
894                     ret = os_snprintf(buf + len, buflen - len,
895                                           "eht_oper_chwidth=%d\n"
896                                           "eht_oper_centr_freq_seg0_idx=%d\n",
897                                           iface->conf->eht_oper_chwidth,
898                                           iface->conf->eht_oper_centr_freq_seg0_idx);
899                     if (os_snprintf_error(buflen - len, ret))
900                               return len;
901                     len += ret;
902 
903                     if (is_6ghz_op_class(iface->conf->op_class) &&
904                         hostapd_get_oper_chwidth(iface->conf) ==
905                         CONF_OPER_CHWIDTH_320MHZ) {
906                               ret = os_snprintf(buf + len, buflen - len,
907                                                     "eht_bw320_offset=%d\n",
908                                                     iface->conf->eht_bw320_offset);
909                               if (os_snprintf_error(buflen - len, ret))
910                                         return len;
911                               len += ret;
912                     }
913 
914                     if (hapd->conf->mld_ap) {
915                               struct hostapd_data *link_bss;
916 
917                               ret = os_snprintf(buf + len, buflen - len,
918                                                     "num_links=%d\n",
919                                                     hapd->mld->num_links);
920                               if (os_snprintf_error(buflen - len, ret))
921                                         return len;
922                               len += ret;
923 
924                               /* Self BSS */
925                               ret = os_snprintf(buf + len, buflen - len,
926                                                     "link_id=%d\n"
927                                                     "link_addr=" MACSTR "\n",
928                                                     hapd->mld_link_id,
929                                                     MAC2STR(hapd->own_addr));
930                               if (os_snprintf_error(buflen - len, ret))
931                                         return len;
932                               len += ret;
933 
934                               /* Partner BSSs */
935                               for_each_mld_link(link_bss, hapd) {
936                                         if (link_bss == hapd)
937                                                   continue;
938 
939                                         ret = os_snprintf(buf + len, buflen - len,
940                                                               "partner_link[%d]=" MACSTR
941                                                               "\n",
942                                                               link_bss->mld_link_id,
943                                                               MAC2STR(link_bss->own_addr));
944                                         if (os_snprintf_error(buflen - len, ret))
945                                                   return len;
946                                         len += ret;
947                               }
948                     }
949           }
950 #endif /* CONFIG_IEEE80211BE */
951 
952 #ifdef CONFIG_IEEE80211AX
953           if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
954                     ret = os_snprintf(buf + len, buflen - len,
955                                           "he_oper_chwidth=%d\n"
956                                           "he_oper_centr_freq_seg0_idx=%d\n"
957                                           "he_oper_centr_freq_seg1_idx=%d\n",
958                                           iface->conf->he_oper_chwidth,
959                                           iface->conf->he_oper_centr_freq_seg0_idx,
960                                           iface->conf->he_oper_centr_freq_seg1_idx);
961                     if (os_snprintf_error(buflen - len, ret))
962                               return len;
963                     len += ret;
964 
965                     if (!iconf->he_op.he_bss_color_disabled &&
966                         iconf->he_op.he_bss_color) {
967                               ret = os_snprintf(buf + len, buflen - len,
968                                                     "he_bss_color=%d\n",
969                                                     iconf->he_op.he_bss_color);
970                               if (os_snprintf_error(buflen - len, ret))
971                                         return len;
972                               len += ret;
973                     }
974           }
975 #endif /* CONFIG_IEEE80211AX */
976 
977           if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
978                     ret = os_snprintf(buf + len, buflen - len,
979                                           "vht_oper_chwidth=%d\n"
980                                           "vht_oper_centr_freq_seg0_idx=%d\n"
981                                           "vht_oper_centr_freq_seg1_idx=%d\n"
982                                           "vht_caps_info=%08x\n",
983                                           iface->conf->vht_oper_chwidth,
984                                           iface->conf->vht_oper_centr_freq_seg0_idx,
985                                           iface->conf->vht_oper_centr_freq_seg1_idx,
986                                           iface->conf->vht_capab);
987                     if (os_snprintf_error(buflen - len, ret))
988                               return len;
989                     len += ret;
990           }
991 
992           if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
993                     u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
994                     u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
995 
996                     ret = os_snprintf(buf + len, buflen - len,
997                                           "rx_vht_mcs_map=%04x\n"
998                                           "tx_vht_mcs_map=%04x\n",
999                                           rxmap, txmap);
1000                     if (os_snprintf_error(buflen - len, ret))
1001                               return len;
1002                     len += ret;
1003           }
1004 
1005           if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
1006                     ret = os_snprintf(buf + len, buflen - len,
1007                                           "ht_caps_info=%04x\n",
1008                                           hapd->iconf->ht_capab);
1009                     if (os_snprintf_error(buflen - len, ret))
1010                               return len;
1011                     len += ret;
1012           }
1013 
1014           if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
1015                     len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
1016                                                                mode->mcs_set);
1017           }
1018 
1019           if (iface->current_rates && iface->num_rates) {
1020                     ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
1021                     if (os_snprintf_error(buflen - len, ret))
1022                               return len;
1023                     len += ret;
1024 
1025                     for (j = 0; j < iface->num_rates; j++) {
1026                               ret = os_snprintf(buf + len, buflen - len, "%s%02x",
1027                                                     j > 0 ? " " : "",
1028                                                     iface->current_rates[j].rate / 5);
1029                               if (os_snprintf_error(buflen - len, ret))
1030                                         return len;
1031                               len += ret;
1032                     }
1033                     ret = os_snprintf(buf + len, buflen - len, "\n");
1034                     if (os_snprintf_error(buflen - len, ret))
1035                               return len;
1036                     len += ret;
1037           }
1038 
1039           for (j = 0; mode && j < mode->num_channels; j++) {
1040                     if (mode->channels[j].freq == iface->freq) {
1041                               ret = os_snprintf(buf + len, buflen - len,
1042                                                     "max_txpower=%u\n",
1043                                                     mode->channels[j].max_tx_power);
1044                               if (os_snprintf_error(buflen - len, ret))
1045                                         return len;
1046                               len += ret;
1047                               break;
1048                     }
1049           }
1050 
1051           for (i = 0; i < iface->num_bss; i++) {
1052                     struct hostapd_data *bss = iface->bss[i];
1053                     ret = os_snprintf(buf + len, buflen - len,
1054                                           "bss[%d]=%s\n"
1055                                           "bssid[%d]=" MACSTR "\n"
1056                                           "ssid[%d]=%s\n"
1057                                           "num_sta[%d]=%d\n",
1058                                           (int) i, bss->conf->iface,
1059                                           (int) i, MAC2STR(bss->own_addr),
1060                                           (int) i,
1061                                           wpa_ssid_txt(bss->conf->ssid.ssid,
1062                                                          bss->conf->ssid.ssid_len),
1063                                           (int) i, bss->num_sta);
1064                     if (os_snprintf_error(buflen - len, ret))
1065                               return len;
1066                     len += ret;
1067 
1068 #ifdef CONFIG_IEEE80211BE
1069                     if (bss->conf->mld_ap) {
1070                               ret = os_snprintf(buf + len, buflen - len,
1071                                                     "mld_addr[%d]=" MACSTR "\n"
1072                                                     "mld_id[%d]=%d\n"
1073                                                     "mld_link_id[%d]=%d\n",
1074                                                     (int) i, MAC2STR(bss->mld->mld_addr),
1075                                                     (int) i, hostapd_get_mld_id(bss),
1076                                                     (int) i, bss->mld_link_id);
1077                               if (os_snprintf_error(buflen - len, ret))
1078                                         return len;
1079                               len += ret;
1080                     }
1081 #endif /* CONFIG_IEEE80211BE */
1082           }
1083 
1084           if (hapd->conf->chan_util_avg_period) {
1085                     ret = os_snprintf(buf + len, buflen - len,
1086                                           "chan_util_avg=%u\n",
1087                                           iface->chan_util_average);
1088                     if (os_snprintf_error(buflen - len, ret))
1089                               return len;
1090                     len += ret;
1091           }
1092 
1093           return len;
1094 }
1095 
1096 
hostapd_parse_csa_settings(const char * pos,struct csa_settings * settings)1097 int hostapd_parse_csa_settings(const char *pos,
1098                                      struct csa_settings *settings)
1099 {
1100           char *end;
1101 
1102           os_memset(settings, 0, sizeof(*settings));
1103           settings->cs_count = strtol(pos, &end, 10);
1104           if (pos == end) {
1105                     wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
1106                     return -1;
1107           }
1108 
1109           settings->freq_params.freq = atoi(end);
1110           if (settings->freq_params.freq == 0) {
1111                     wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
1112                     return -1;
1113           }
1114 
1115 #define SET_CSA_SETTING(str) \
1116           do { \
1117                     const char *pos2 = os_strstr(pos, " " #str "="); \
1118                     if (pos2) { \
1119                               pos2 += sizeof(" " #str "=") - 1; \
1120                               settings->freq_params.str = atoi(pos2); \
1121                     } \
1122           } while (0)
1123 
1124 #define SET_CSA_SETTING_EXT(str) \
1125           do { \
1126                     const char *pos2 = os_strstr(pos, " " #str "="); \
1127                     if (pos2) { \
1128                               pos2 += sizeof(" " #str "=") - 1; \
1129                               settings->str = atoi(pos2); \
1130                     } \
1131           } while (0)
1132 
1133           SET_CSA_SETTING(center_freq1);
1134           SET_CSA_SETTING(center_freq2);
1135           SET_CSA_SETTING(bandwidth);
1136           SET_CSA_SETTING(sec_channel_offset);
1137           SET_CSA_SETTING_EXT(punct_bitmap);
1138           settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
1139           settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
1140           settings->freq_params.he_enabled = !!os_strstr(pos, " he");
1141           settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
1142           settings->block_tx = !!os_strstr(pos, " blocktx");
1143 #undef SET_CSA_SETTING
1144 #undef SET_CSA_SETTING_EXT
1145 
1146           return 0;
1147 }
1148 
1149 
hostapd_ctrl_iface_stop_ap(struct hostapd_data * hapd)1150 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
1151 {
1152           return hostapd_drv_stop_ap(hapd);
1153 }
1154 
1155 
hostapd_ctrl_iface_pmksa_list(struct hostapd_data * hapd,char * buf,size_t len)1156 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
1157                                           size_t len)
1158 {
1159           return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
1160 }
1161 
1162 
hostapd_ctrl_iface_pmksa_flush(struct hostapd_data * hapd)1163 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
1164 {
1165           wpa_auth_pmksa_flush(hapd->wpa_auth);
1166 }
1167 
1168 
hostapd_ctrl_iface_pmksa_add(struct hostapd_data * hapd,char * cmd)1169 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
1170 {
1171           u8 spa[ETH_ALEN];
1172           u8 pmkid[PMKID_LEN];
1173           u8 pmk[PMK_LEN_MAX];
1174           size_t pmk_len;
1175           char *pos, *pos2;
1176           int akmp = 0, expiration = 0;
1177 
1178           /*
1179            * Entry format:
1180            * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
1181            */
1182 
1183           if (hwaddr_aton(cmd, spa))
1184                     return -1;
1185 
1186           pos = os_strchr(cmd, ' ');
1187           if (!pos)
1188                     return -1;
1189           pos++;
1190 
1191           if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1192                     return -1;
1193 
1194           pos = os_strchr(pos, ' ');
1195           if (!pos)
1196                     return -1;
1197           pos++;
1198 
1199           pos2 = os_strchr(pos, ' ');
1200           if (!pos2)
1201                     return -1;
1202           pmk_len = (pos2 - pos) / 2;
1203           if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
1204               hexstr2bin(pos, pmk, pmk_len) < 0)
1205                     return -1;
1206 
1207           pos = pos2 + 1;
1208 
1209           if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
1210                     return -1;
1211 
1212           return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
1213                                            pmkid, expiration, akmp, NULL);
1214 }
1215 
1216 
1217 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
1218 #ifdef CONFIG_MESH
1219 
hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t len)1220 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
1221                                                const u8 *addr, char *buf, size_t len)
1222 {
1223           return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
1224 }
1225 
1226 
hostapd_ctrl_iface_pmksa_create_entry(const u8 * aa,char * cmd)1227 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
1228 {
1229           u8 spa[ETH_ALEN];
1230           u8 pmkid[PMKID_LEN];
1231           u8 pmk[PMK_LEN_MAX];
1232           char *pos;
1233           int expiration;
1234 
1235           /*
1236            * Entry format:
1237            * <BSSID> <PMKID> <PMK> <expiration in seconds>
1238            */
1239 
1240           if (hwaddr_aton(cmd, spa))
1241                     return NULL;
1242 
1243           pos = os_strchr(cmd, ' ');
1244           if (!pos)
1245                     return NULL;
1246           pos++;
1247 
1248           if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1249                     return NULL;
1250 
1251           pos = os_strchr(pos, ' ');
1252           if (!pos)
1253                     return NULL;
1254           pos++;
1255 
1256           if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
1257                     return NULL;
1258 
1259           pos = os_strchr(pos, ' ');
1260           if (!pos)
1261                     return NULL;
1262           pos++;
1263 
1264           if (sscanf(pos, "%d", &expiration) != 1)
1265                     return NULL;
1266 
1267           return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
1268                                                      WPA_KEY_MGMT_SAE, pmkid, expiration);
1269 }
1270 
1271 #endif /* CONFIG_MESH */
1272 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
1273 
1274 
1275 #ifdef CONFIG_WNM_AP
1276 
hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data * hapd,const char * cmd)1277 int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
1278                                                    const char *cmd)
1279 {
1280           u8 addr[ETH_ALEN];
1281           int disassoc_timer;
1282           struct sta_info *sta;
1283 
1284           if (hwaddr_aton(cmd, addr))
1285                     return -1;
1286           if (cmd[17] != ' ')
1287                     return -1;
1288           disassoc_timer = atoi(cmd + 17);
1289 
1290           sta = ap_get_sta(hapd, addr);
1291           if (sta == NULL) {
1292                     wpa_printf(MSG_DEBUG, "Station " MACSTR
1293                                  " not found for disassociation imminent message",
1294                                  MAC2STR(addr));
1295                     return -1;
1296           }
1297 
1298           return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
1299 }
1300 
1301 
hostapd_ctrl_iface_ess_disassoc(struct hostapd_data * hapd,const char * cmd)1302 int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
1303                                             const char *cmd)
1304 {
1305           u8 addr[ETH_ALEN];
1306           const char *url, *timerstr;
1307           int disassoc_timer;
1308           struct sta_info *sta;
1309 
1310           if (hwaddr_aton(cmd, addr))
1311                     return -1;
1312 
1313           sta = ap_get_sta(hapd, addr);
1314           if (sta == NULL) {
1315                     wpa_printf(MSG_DEBUG, "Station " MACSTR
1316                                  " not found for ESS disassociation imminent message",
1317                                  MAC2STR(addr));
1318                     return -1;
1319           }
1320 
1321           timerstr = cmd + 17;
1322           if (*timerstr != ' ')
1323                     return -1;
1324           timerstr++;
1325           disassoc_timer = atoi(timerstr);
1326           if (disassoc_timer < 0 || disassoc_timer > 65535)
1327                     return -1;
1328 
1329           url = os_strchr(timerstr, ' ');
1330           if (url == NULL)
1331                     return -1;
1332           url++;
1333 
1334           return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
1335 }
1336 
1337 
hostapd_ctrl_iface_bss_tm_req(struct hostapd_data * hapd,const char * cmd)1338 int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1339                                           const char *cmd)
1340 {
1341           u8 addr[ETH_ALEN];
1342           const char *pos, *end;
1343           int disassoc_timer = 0;
1344           struct sta_info *sta;
1345           u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
1346           u8 bss_term_dur[12];
1347           char *url = NULL;
1348           int ret;
1349           u8 nei_rep[1000];
1350           int nei_len;
1351           u8 mbo[10];
1352           size_t mbo_len = 0;
1353 
1354           if (hwaddr_aton(cmd, addr)) {
1355                     wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
1356                     return -1;
1357           }
1358 
1359           sta = ap_get_sta(hapd, addr);
1360           if (sta == NULL) {
1361                     wpa_printf(MSG_DEBUG, "Station " MACSTR
1362                                  " not found for BSS TM Request message",
1363                                  MAC2STR(addr));
1364                     return -1;
1365           }
1366 
1367           pos = os_strstr(cmd, " disassoc_timer=");
1368           if (pos) {
1369                     pos += 16;
1370                     disassoc_timer = atoi(pos);
1371                     if (disassoc_timer < 0 || disassoc_timer > 65535) {
1372                               wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
1373                               return -1;
1374                     }
1375           }
1376 
1377           pos = os_strstr(cmd, " valid_int=");
1378           if (pos) {
1379                     pos += 11;
1380                     valid_int = atoi(pos);
1381           }
1382 
1383           pos = os_strstr(cmd, " dialog_token=");
1384           if (pos) {
1385                     pos += 14;
1386                     dialog_token = atoi(pos);
1387           }
1388 
1389           pos = os_strstr(cmd, " bss_term=");
1390           if (pos) {
1391                     pos += 10;
1392                     req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
1393                     /* TODO: TSF configurable/learnable */
1394                     bss_term_dur[0] = 4; /* Subelement ID */
1395                     bss_term_dur[1] = 10; /* Length */
1396                     os_memset(&bss_term_dur[2], 0, 8);
1397                     end = os_strchr(pos, ',');
1398                     if (end == NULL) {
1399                               wpa_printf(MSG_DEBUG, "Invalid bss_term data");
1400                               return -1;
1401                     }
1402                     end++;
1403                     WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
1404           }
1405 
1406           nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
1407                                                               sizeof(nei_rep));
1408           if (nei_len < 0)
1409                     return -1;
1410 
1411           pos = os_strstr(cmd, " url=");
1412           if (pos) {
1413                     size_t len;
1414                     pos += 5;
1415                     end = os_strchr(pos, ' ');
1416                     if (end)
1417                               len = end - pos;
1418                     else
1419                               len = os_strlen(pos);
1420                     url = os_malloc(len + 1);
1421                     if (url == NULL)
1422                               return -1;
1423                     os_memcpy(url, pos, len);
1424                     url[len] = '\0';
1425                     req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1426           }
1427 
1428           if (os_strstr(cmd, " pref=1"))
1429                     req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1430           if (os_strstr(cmd, " abridged=1"))
1431                     req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1432           if (os_strstr(cmd, " disassoc_imminent=1"))
1433                     req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1434           if (os_strstr(cmd, " link_removal_imminent=1"))
1435                     req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT;
1436 
1437 #ifdef CONFIG_MBO
1438           pos = os_strstr(cmd, "mbo=");
1439           if (pos) {
1440                     unsigned int mbo_reason, cell_pref, reassoc_delay;
1441                     u8 *mbo_pos = mbo;
1442 
1443                     ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
1444                                    &reassoc_delay, &cell_pref);
1445                     if (ret != 3) {
1446                               wpa_printf(MSG_DEBUG,
1447                                            "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
1448                               ret = -1;
1449                               goto fail;
1450                     }
1451 
1452                     if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
1453                               wpa_printf(MSG_DEBUG,
1454                                            "Invalid MBO transition reason code %u",
1455                                            mbo_reason);
1456                               ret = -1;
1457                               goto fail;
1458                     }
1459 
1460                     /* Valid values for Cellular preference are: 0, 1, 255 */
1461                     if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
1462                               wpa_printf(MSG_DEBUG,
1463                                            "Invalid MBO cellular capability %u",
1464                                            cell_pref);
1465                               ret = -1;
1466                               goto fail;
1467                     }
1468 
1469                     if (reassoc_delay > 65535 ||
1470                         (reassoc_delay &&
1471                          !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
1472                               wpa_printf(MSG_DEBUG,
1473                                            "MBO: Assoc retry delay is only valid in disassoc imminent mode");
1474                               ret = -1;
1475                               goto fail;
1476                     }
1477 
1478                     *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
1479                     *mbo_pos++ = 1;
1480                     *mbo_pos++ = mbo_reason;
1481                     *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
1482                     *mbo_pos++ = 1;
1483                     *mbo_pos++ = cell_pref;
1484 
1485                     if (reassoc_delay) {
1486                               *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
1487                               *mbo_pos++ = 2;
1488                               WPA_PUT_LE16(mbo_pos, reassoc_delay);
1489                               mbo_pos += 2;
1490                     }
1491 
1492                     mbo_len = mbo_pos - mbo;
1493           }
1494 #endif /* CONFIG_MBO */
1495 
1496           ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
1497                                           valid_int, bss_term_dur, dialog_token, url,
1498                                           nei_len ? nei_rep : NULL, nei_len,
1499                                           mbo_len ? mbo : NULL, mbo_len);
1500 #ifdef CONFIG_MBO
1501 fail:
1502 #endif /* CONFIG_MBO */
1503           os_free(url);
1504           return ret;
1505 }
1506 
1507 #endif /* CONFIG_WNM_AP */
1508 
1509 
hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry ** acl,int * num,const char * txtaddr)1510 int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
1511                                            const char *txtaddr)
1512 {
1513           u8 addr[ETH_ALEN];
1514           struct vlan_description vlan_id;
1515 
1516           if (!(*num))
1517                     return 0;
1518 
1519           if (hwaddr_aton(txtaddr, addr))
1520                     return -1;
1521 
1522           if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
1523                     hostapd_remove_acl_mac(acl, num, addr);
1524 
1525           return 0;
1526 }
1527 
1528 
hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry ** acl,int * num)1529 void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
1530                                                int *num)
1531 {
1532           while (*num)
1533                     hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
1534 }
1535 
1536 
hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry * acl,int num,char * buf,size_t buflen)1537 int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
1538                                             char *buf, size_t buflen)
1539 {
1540           int i = 0, len = 0, ret = 0;
1541 
1542           if (!acl)
1543                     return 0;
1544 
1545           while (i < num) {
1546                     ret = os_snprintf(buf + len, buflen - len,
1547                                           MACSTR " VLAN_ID=%d\n",
1548                                           MAC2STR(acl[i].addr),
1549                                           acl[i].vlan_id.untagged);
1550                     if (ret < 0 || (size_t) ret >= buflen - len)
1551                               return len;
1552                     i++;
1553                     len += ret;
1554           }
1555           return len;
1556 }
1557 
1558 
hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry ** acl,int * num,const char * cmd)1559 int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
1560                                            const char *cmd)
1561 {
1562           u8 addr[ETH_ALEN];
1563           struct vlan_description vlan_id;
1564           int ret = 0, vlanid = 0;
1565           const char *pos;
1566 
1567           if (hwaddr_aton(cmd, addr))
1568                     return -1;
1569 
1570           pos = os_strstr(cmd, "VLAN_ID=");
1571           if (pos)
1572                     vlanid = atoi(pos + 8);
1573 
1574           if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
1575                     ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
1576                     if (ret != -1 && *acl)
1577                               qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
1578           }
1579 
1580           return ret < 0 ? -1 : 0;
1581 }
1582 
1583 
hostapd_disassoc_accept_mac(struct hostapd_data * hapd)1584 int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
1585 {
1586           struct sta_info *sta;
1587           struct vlan_description vlan_id;
1588 
1589           if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
1590                     return 0;
1591 
1592           for (sta = hapd->sta_list; sta; sta = sta->next) {
1593                     if (!hostapd_maclist_found(hapd->conf->accept_mac,
1594                                                      hapd->conf->num_accept_mac,
1595                                                      sta->addr, &vlan_id) ||
1596                         (vlan_id.notempty &&
1597                          vlan_compare(&vlan_id, sta->vlan_desc)))
1598                               ap_sta_disconnect(hapd, sta, sta->addr,
1599                                                     WLAN_REASON_UNSPECIFIED);
1600           }
1601 
1602           return 0;
1603 }
1604 
1605 
hostapd_disassoc_deny_mac(struct hostapd_data * hapd)1606 int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
1607 {
1608           struct sta_info *sta;
1609           struct vlan_description vlan_id;
1610 
1611           for (sta = hapd->sta_list; sta; sta = sta->next) {
1612                     if (hostapd_maclist_found(hapd->conf->deny_mac,
1613                                                     hapd->conf->num_deny_mac, sta->addr,
1614                                                     &vlan_id) &&
1615                         (!vlan_id.notempty ||
1616                          !vlan_compare(&vlan_id, sta->vlan_desc)))
1617                               ap_sta_disconnect(hapd, sta, sta->addr,
1618                                                     WLAN_REASON_UNSPECIFIED);
1619           }
1620 
1621           return 0;
1622 }
1623