ctrl_iface_ap.c 19 KB

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