ctrl_iface_ap.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  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. if (sta->power_capab) {
  217. ret = os_snprintf(buf + len, buflen - len,
  218. "min_txpower=%d\n"
  219. "max_txpower=%d\n",
  220. sta->min_tx_power, sta->max_tx_power);
  221. if (!os_snprintf_error(buflen - len, ret))
  222. len += ret;
  223. }
  224. #ifdef CONFIG_IEEE80211AC
  225. if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
  226. res = os_snprintf(buf + len, buflen - len,
  227. "vht_caps_info=0x%08x\n",
  228. le_to_host32(sta->vht_capabilities->
  229. vht_capabilities_info));
  230. if (!os_snprintf_error(buflen - len, res))
  231. len += res;
  232. }
  233. #endif /* CONFIG_IEEE80211AC */
  234. #ifdef CONFIG_IEEE80211N
  235. if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
  236. res = os_snprintf(buf + len, buflen - len,
  237. "ht_caps_info=0x%04x\n",
  238. le_to_host16(sta->ht_capabilities->
  239. ht_capabilities_info));
  240. if (!os_snprintf_error(buflen - len, res))
  241. len += res;
  242. }
  243. #endif /* CONFIG_IEEE80211N */
  244. if (sta->ext_capability &&
  245. buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
  246. len += os_snprintf(buf + len, buflen - len, "ext_capab=");
  247. len += wpa_snprintf_hex(buf + len, buflen - len,
  248. sta->ext_capability + 1,
  249. sta->ext_capability[0]);
  250. len += os_snprintf(buf + len, buflen - len, "\n");
  251. }
  252. return len;
  253. }
  254. int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
  255. char *buf, size_t buflen)
  256. {
  257. return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
  258. }
  259. int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
  260. char *buf, size_t buflen)
  261. {
  262. u8 addr[ETH_ALEN];
  263. int ret;
  264. const char *pos;
  265. struct sta_info *sta;
  266. if (hwaddr_aton(txtaddr, addr)) {
  267. ret = os_snprintf(buf, buflen, "FAIL\n");
  268. if (os_snprintf_error(buflen, ret))
  269. return 0;
  270. return ret;
  271. }
  272. sta = ap_get_sta(hapd, addr);
  273. if (sta == NULL)
  274. return -1;
  275. pos = os_strchr(txtaddr, ' ');
  276. if (pos) {
  277. pos++;
  278. #ifdef HOSTAPD_DUMP_STATE
  279. if (os_strcmp(pos, "eapol") == 0) {
  280. if (sta->eapol_sm == NULL)
  281. return -1;
  282. return eapol_auth_dump_state(sta->eapol_sm, buf,
  283. buflen);
  284. }
  285. #endif /* HOSTAPD_DUMP_STATE */
  286. return -1;
  287. }
  288. ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
  289. ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
  290. return ret;
  291. }
  292. int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
  293. char *buf, size_t buflen)
  294. {
  295. u8 addr[ETH_ALEN];
  296. struct sta_info *sta;
  297. int ret;
  298. if (hwaddr_aton(txtaddr, addr) ||
  299. (sta = ap_get_sta(hapd, addr)) == NULL) {
  300. ret = os_snprintf(buf, buflen, "FAIL\n");
  301. if (os_snprintf_error(buflen, ret))
  302. return 0;
  303. return ret;
  304. }
  305. if (!sta->next)
  306. return 0;
  307. return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
  308. }
  309. #ifdef CONFIG_P2P_MANAGER
  310. static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
  311. u8 minor_reason_code, const u8 *addr)
  312. {
  313. struct ieee80211_mgmt *mgmt;
  314. int ret;
  315. u8 *pos;
  316. if (!hapd->drv_priv || !hapd->driver->send_frame)
  317. return -1;
  318. mgmt = os_zalloc(sizeof(*mgmt) + 100);
  319. if (mgmt == NULL)
  320. return -1;
  321. mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
  322. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
  323. " with minor reason code %u (stype=%u (%s))",
  324. MAC2STR(addr), minor_reason_code, stype,
  325. fc2str(le_to_host16(mgmt->frame_control)));
  326. os_memcpy(mgmt->da, addr, ETH_ALEN);
  327. os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
  328. os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
  329. if (stype == WLAN_FC_STYPE_DEAUTH) {
  330. mgmt->u.deauth.reason_code =
  331. host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
  332. pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
  333. } else {
  334. mgmt->u.disassoc.reason_code =
  335. host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
  336. pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
  337. }
  338. *pos++ = WLAN_EID_VENDOR_SPECIFIC;
  339. *pos++ = 4 + 3 + 1;
  340. WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
  341. pos += 4;
  342. *pos++ = P2P_ATTR_MINOR_REASON_CODE;
  343. WPA_PUT_LE16(pos, 1);
  344. pos += 2;
  345. *pos++ = minor_reason_code;
  346. ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
  347. pos - (u8 *) mgmt, 1);
  348. os_free(mgmt);
  349. return ret < 0 ? -1 : 0;
  350. }
  351. #endif /* CONFIG_P2P_MANAGER */
  352. int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
  353. const char *txtaddr)
  354. {
  355. u8 addr[ETH_ALEN];
  356. struct sta_info *sta;
  357. const char *pos;
  358. u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
  359. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
  360. txtaddr);
  361. if (hwaddr_aton(txtaddr, addr))
  362. return -1;
  363. pos = os_strstr(txtaddr, " reason=");
  364. if (pos)
  365. reason = atoi(pos + 8);
  366. pos = os_strstr(txtaddr, " test=");
  367. if (pos) {
  368. struct ieee80211_mgmt mgmt;
  369. int encrypt;
  370. if (!hapd->drv_priv || !hapd->driver->send_frame)
  371. return -1;
  372. pos += 6;
  373. encrypt = atoi(pos);
  374. os_memset(&mgmt, 0, sizeof(mgmt));
  375. mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
  376. WLAN_FC_STYPE_DEAUTH);
  377. os_memcpy(mgmt.da, addr, ETH_ALEN);
  378. os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
  379. os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
  380. mgmt.u.deauth.reason_code = host_to_le16(reason);
  381. if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
  382. IEEE80211_HDRLEN +
  383. sizeof(mgmt.u.deauth),
  384. encrypt) < 0)
  385. return -1;
  386. return 0;
  387. }
  388. #ifdef CONFIG_P2P_MANAGER
  389. pos = os_strstr(txtaddr, " p2p=");
  390. if (pos) {
  391. return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
  392. atoi(pos + 5), addr);
  393. }
  394. #endif /* CONFIG_P2P_MANAGER */
  395. if (os_strstr(txtaddr, " tx=0"))
  396. hostapd_drv_sta_remove(hapd, addr);
  397. else
  398. hostapd_drv_sta_deauth(hapd, addr, reason);
  399. sta = ap_get_sta(hapd, addr);
  400. if (sta)
  401. ap_sta_deauthenticate(hapd, sta, reason);
  402. else if (addr[0] == 0xff)
  403. hostapd_free_stas(hapd);
  404. return 0;
  405. }
  406. int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
  407. const char *txtaddr)
  408. {
  409. u8 addr[ETH_ALEN];
  410. struct sta_info *sta;
  411. const char *pos;
  412. u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
  413. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
  414. txtaddr);
  415. if (hwaddr_aton(txtaddr, addr))
  416. return -1;
  417. pos = os_strstr(txtaddr, " reason=");
  418. if (pos)
  419. reason = atoi(pos + 8);
  420. pos = os_strstr(txtaddr, " test=");
  421. if (pos) {
  422. struct ieee80211_mgmt mgmt;
  423. int encrypt;
  424. if (!hapd->drv_priv || !hapd->driver->send_frame)
  425. return -1;
  426. pos += 6;
  427. encrypt = atoi(pos);
  428. os_memset(&mgmt, 0, sizeof(mgmt));
  429. mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
  430. WLAN_FC_STYPE_DISASSOC);
  431. os_memcpy(mgmt.da, addr, ETH_ALEN);
  432. os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
  433. os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
  434. mgmt.u.disassoc.reason_code = host_to_le16(reason);
  435. if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
  436. IEEE80211_HDRLEN +
  437. sizeof(mgmt.u.deauth),
  438. encrypt) < 0)
  439. return -1;
  440. return 0;
  441. }
  442. #ifdef CONFIG_P2P_MANAGER
  443. pos = os_strstr(txtaddr, " p2p=");
  444. if (pos) {
  445. return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
  446. atoi(pos + 5), addr);
  447. }
  448. #endif /* CONFIG_P2P_MANAGER */
  449. if (os_strstr(txtaddr, " tx=0"))
  450. hostapd_drv_sta_remove(hapd, addr);
  451. else
  452. hostapd_drv_sta_disassoc(hapd, addr, reason);
  453. sta = ap_get_sta(hapd, addr);
  454. if (sta)
  455. ap_sta_disassociate(hapd, sta, reason);
  456. else if (addr[0] == 0xff)
  457. hostapd_free_stas(hapd);
  458. return 0;
  459. }
  460. #ifdef CONFIG_TAXONOMY
  461. int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
  462. const char *txtaddr,
  463. char *buf, size_t buflen)
  464. {
  465. u8 addr[ETH_ALEN];
  466. struct sta_info *sta;
  467. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
  468. if (hwaddr_aton(txtaddr, addr))
  469. return -1;
  470. sta = ap_get_sta(hapd, addr);
  471. if (!sta)
  472. return -1;
  473. return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
  474. }
  475. #endif /* CONFIG_TAXONOMY */
  476. int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
  477. const char *txtaddr)
  478. {
  479. u8 addr[ETH_ALEN];
  480. struct sta_info *sta;
  481. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
  482. if (hwaddr_aton(txtaddr, addr))
  483. return -1;
  484. sta = ap_get_sta(hapd, addr);
  485. if (!sta)
  486. return -1;
  487. hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
  488. sta->flags & WLAN_STA_WMM);
  489. return 0;
  490. }
  491. int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
  492. size_t buflen)
  493. {
  494. struct hostapd_iface *iface = hapd->iface;
  495. int len = 0, ret;
  496. size_t i;
  497. ret = os_snprintf(buf + len, buflen - len,
  498. "state=%s\n"
  499. "phy=%s\n"
  500. "freq=%d\n"
  501. "num_sta_non_erp=%d\n"
  502. "num_sta_no_short_slot_time=%d\n"
  503. "num_sta_no_short_preamble=%d\n"
  504. "olbc=%d\n"
  505. "num_sta_ht_no_gf=%d\n"
  506. "num_sta_no_ht=%d\n"
  507. "num_sta_ht_20_mhz=%d\n"
  508. "num_sta_ht40_intolerant=%d\n"
  509. "olbc_ht=%d\n"
  510. "ht_op_mode=0x%x\n",
  511. hostapd_state_text(iface->state),
  512. iface->phy,
  513. iface->freq,
  514. iface->num_sta_non_erp,
  515. iface->num_sta_no_short_slot_time,
  516. iface->num_sta_no_short_preamble,
  517. iface->olbc,
  518. iface->num_sta_ht_no_gf,
  519. iface->num_sta_no_ht,
  520. iface->num_sta_ht_20mhz,
  521. iface->num_sta_ht40_intolerant,
  522. iface->olbc_ht,
  523. iface->ht_op_mode);
  524. if (os_snprintf_error(buflen - len, ret))
  525. return len;
  526. len += ret;
  527. if (!iface->cac_started || !iface->dfs_cac_ms) {
  528. ret = os_snprintf(buf + len, buflen - len,
  529. "cac_time_seconds=%d\n"
  530. "cac_time_left_seconds=N/A\n",
  531. iface->dfs_cac_ms / 1000);
  532. } else {
  533. /* CAC started and CAC time set - calculate remaining time */
  534. struct os_reltime now;
  535. unsigned int left_time;
  536. os_reltime_age(&iface->dfs_cac_start, &now);
  537. left_time = iface->dfs_cac_ms / 1000 - now.sec;
  538. ret = os_snprintf(buf + len, buflen - len,
  539. "cac_time_seconds=%u\n"
  540. "cac_time_left_seconds=%u\n",
  541. iface->dfs_cac_ms / 1000,
  542. left_time);
  543. }
  544. if (os_snprintf_error(buflen - len, ret))
  545. return len;
  546. len += ret;
  547. ret = os_snprintf(buf + len, buflen - len,
  548. "channel=%u\n"
  549. "secondary_channel=%d\n"
  550. "ieee80211n=%d\n"
  551. "ieee80211ac=%d\n"
  552. "beacon_int=%u\n"
  553. "dtim_period=%d\n",
  554. iface->conf->channel,
  555. iface->conf->ieee80211n && !hapd->conf->disable_11n ?
  556. iface->conf->secondary_channel : 0,
  557. iface->conf->ieee80211n && !hapd->conf->disable_11n,
  558. iface->conf->ieee80211ac &&
  559. !hapd->conf->disable_11ac,
  560. iface->conf->beacon_int,
  561. hapd->conf->dtim_period);
  562. if (os_snprintf_error(buflen - len, ret))
  563. return len;
  564. len += ret;
  565. if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
  566. ret = os_snprintf(buf + len, buflen - len,
  567. "vht_oper_chwidth=%d\n"
  568. "vht_oper_centr_freq_seg0_idx=%d\n"
  569. "vht_oper_centr_freq_seg1_idx=%d\n"
  570. "vht_caps_info=%08x\n",
  571. iface->conf->vht_oper_chwidth,
  572. iface->conf->vht_oper_centr_freq_seg0_idx,
  573. iface->conf->vht_oper_centr_freq_seg1_idx,
  574. iface->conf->vht_capab);
  575. if (os_snprintf_error(buflen - len, ret))
  576. return len;
  577. len += ret;
  578. }
  579. if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
  580. ret = os_snprintf(buf + len, buflen - len,
  581. "ht_caps_info=%04x\n",
  582. hapd->iconf->ht_capab);
  583. if (os_snprintf_error(buflen - len, ret))
  584. return len;
  585. len += ret;
  586. }
  587. for (i = 0; i < iface->num_bss; i++) {
  588. struct hostapd_data *bss = iface->bss[i];
  589. ret = os_snprintf(buf + len, buflen - len,
  590. "bss[%d]=%s\n"
  591. "bssid[%d]=" MACSTR "\n"
  592. "ssid[%d]=%s\n"
  593. "num_sta[%d]=%d\n",
  594. (int) i, bss->conf->iface,
  595. (int) i, MAC2STR(bss->own_addr),
  596. (int) i,
  597. wpa_ssid_txt(bss->conf->ssid.ssid,
  598. bss->conf->ssid.ssid_len),
  599. (int) i, bss->num_sta);
  600. if (os_snprintf_error(buflen - len, ret))
  601. return len;
  602. len += ret;
  603. }
  604. return len;
  605. }
  606. int hostapd_parse_csa_settings(const char *pos,
  607. struct csa_settings *settings)
  608. {
  609. char *end;
  610. os_memset(settings, 0, sizeof(*settings));
  611. settings->cs_count = strtol(pos, &end, 10);
  612. if (pos == end) {
  613. wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
  614. return -1;
  615. }
  616. settings->freq_params.freq = atoi(end);
  617. if (settings->freq_params.freq == 0) {
  618. wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
  619. return -1;
  620. }
  621. #define SET_CSA_SETTING(str) \
  622. do { \
  623. const char *pos2 = os_strstr(pos, " " #str "="); \
  624. if (pos2) { \
  625. pos2 += sizeof(" " #str "=") - 1; \
  626. settings->freq_params.str = atoi(pos2); \
  627. } \
  628. } while (0)
  629. SET_CSA_SETTING(center_freq1);
  630. SET_CSA_SETTING(center_freq2);
  631. SET_CSA_SETTING(bandwidth);
  632. SET_CSA_SETTING(sec_channel_offset);
  633. settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
  634. settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
  635. settings->block_tx = !!os_strstr(pos, " blocktx");
  636. #undef SET_CSA_SETTING
  637. return 0;
  638. }
  639. int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
  640. {
  641. return hostapd_drv_stop_ap(hapd);
  642. }
  643. int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
  644. size_t len)
  645. {
  646. return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
  647. }
  648. void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
  649. {
  650. wpa_auth_pmksa_flush(hapd->wpa_auth);
  651. }
  652. int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
  653. {
  654. u8 spa[ETH_ALEN];
  655. u8 pmkid[PMKID_LEN];
  656. u8 pmk[PMK_LEN_MAX];
  657. size_t pmk_len;
  658. char *pos, *pos2;
  659. int akmp = 0, expiration = 0;
  660. /*
  661. * Entry format:
  662. * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
  663. */
  664. if (hwaddr_aton(cmd, spa))
  665. return -1;
  666. pos = os_strchr(cmd, ' ');
  667. if (!pos)
  668. return -1;
  669. pos++;
  670. if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
  671. return -1;
  672. pos = os_strchr(pos, ' ');
  673. if (!pos)
  674. return -1;
  675. pos++;
  676. pos2 = os_strchr(pos, ' ');
  677. if (!pos2)
  678. return -1;
  679. pmk_len = (pos2 - pos) / 2;
  680. if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
  681. hexstr2bin(pos, pmk, pmk_len) < 0)
  682. return -1;
  683. pos = pos2 + 1;
  684. if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
  685. return -1;
  686. return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
  687. pmkid, expiration, akmp);
  688. }
  689. #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
  690. #ifdef CONFIG_MESH
  691. int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
  692. const u8 *addr, char *buf, size_t len)
  693. {
  694. return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
  695. }
  696. void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
  697. {
  698. u8 spa[ETH_ALEN];
  699. u8 pmkid[PMKID_LEN];
  700. u8 pmk[PMK_LEN_MAX];
  701. char *pos;
  702. int expiration;
  703. /*
  704. * Entry format:
  705. * <BSSID> <PMKID> <PMK> <expiration in seconds>
  706. */
  707. if (hwaddr_aton(cmd, spa))
  708. return NULL;
  709. pos = os_strchr(cmd, ' ');
  710. if (!pos)
  711. return NULL;
  712. pos++;
  713. if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
  714. return NULL;
  715. pos = os_strchr(pos, ' ');
  716. if (!pos)
  717. return NULL;
  718. pos++;
  719. if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
  720. return NULL;
  721. pos = os_strchr(pos, ' ');
  722. if (!pos)
  723. return NULL;
  724. pos++;
  725. if (sscanf(pos, "%d", &expiration) != 1)
  726. return NULL;
  727. return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
  728. }
  729. #endif /* CONFIG_MESH */
  730. #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */