ctrl_iface_ap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
  24. struct sta_info *sta,
  25. char *buf, size_t buflen)
  26. {
  27. struct hostap_sta_driver_data data;
  28. int ret;
  29. if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
  30. return 0;
  31. ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
  32. "rx_bytes=%lu\ntx_bytes=%lu\n",
  33. data.rx_packets, data.tx_packets,
  34. data.rx_bytes, data.tx_bytes);
  35. if (os_snprintf_error(buflen, ret))
  36. return 0;
  37. return ret;
  38. }
  39. static int hostapd_get_sta_conn_time(struct sta_info *sta,
  40. char *buf, size_t buflen)
  41. {
  42. struct os_reltime age;
  43. int ret;
  44. if (!sta->connected_time.sec)
  45. return 0;
  46. os_reltime_age(&sta->connected_time, &age);
  47. ret = os_snprintf(buf, buflen, "connected_time=%u\n",
  48. (unsigned int) age.sec);
  49. if (os_snprintf_error(buflen, ret))
  50. return 0;
  51. return ret;
  52. }
  53. static const char * timeout_next_str(int val)
  54. {
  55. switch (val) {
  56. case STA_NULLFUNC:
  57. return "NULLFUNC POLL";
  58. case STA_DISASSOC:
  59. return "DISASSOC";
  60. case STA_DEAUTH:
  61. return "DEAUTH";
  62. case STA_REMOVE:
  63. return "REMOVE";
  64. case STA_DISASSOC_FROM_CLI:
  65. return "DISASSOC_FROM_CLI";
  66. }
  67. return "?";
  68. }
  69. static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
  70. struct sta_info *sta,
  71. char *buf, size_t buflen)
  72. {
  73. int len, res, ret, i;
  74. if (!sta)
  75. return 0;
  76. len = 0;
  77. ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
  78. MAC2STR(sta->addr));
  79. if (os_snprintf_error(buflen - len, ret))
  80. return len;
  81. len += ret;
  82. ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
  83. if (ret < 0)
  84. return len;
  85. len += ret;
  86. ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
  87. "listen_interval=%d\nsupported_rates=",
  88. sta->aid, sta->capability, sta->listen_interval);
  89. if (os_snprintf_error(buflen - len, ret))
  90. return len;
  91. len += ret;
  92. for (i = 0; i < sta->supported_rates_len; i++) {
  93. ret = os_snprintf(buf + len, buflen - len, "%02x%s",
  94. sta->supported_rates[i],
  95. i + 1 < sta->supported_rates_len ? " " : "");
  96. if (os_snprintf_error(buflen - len, ret))
  97. return len;
  98. len += ret;
  99. }
  100. ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
  101. timeout_next_str(sta->timeout_next));
  102. if (os_snprintf_error(buflen - len, ret))
  103. return len;
  104. len += ret;
  105. res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
  106. if (res >= 0)
  107. len += res;
  108. res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
  109. if (res >= 0)
  110. len += res;
  111. res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
  112. if (res >= 0)
  113. len += res;
  114. res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
  115. buflen - len);
  116. if (res >= 0)
  117. len += res;
  118. res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
  119. if (res >= 0)
  120. len += res;
  121. len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
  122. len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
  123. #ifdef CONFIG_SAE
  124. if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
  125. res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
  126. sta->sae->group);
  127. if (!os_snprintf_error(buflen - len, res))
  128. len += res;
  129. }
  130. #endif /* CONFIG_SAE */
  131. if (sta->vlan_id > 0) {
  132. res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
  133. sta->vlan_id);
  134. if (!os_snprintf_error(buflen - len, res))
  135. len += res;
  136. }
  137. return len;
  138. }
  139. int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
  140. char *buf, size_t buflen)
  141. {
  142. return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
  143. }
  144. int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
  145. char *buf, size_t buflen)
  146. {
  147. u8 addr[ETH_ALEN];
  148. int ret;
  149. const char *pos;
  150. struct sta_info *sta;
  151. if (hwaddr_aton(txtaddr, addr)) {
  152. ret = os_snprintf(buf, buflen, "FAIL\n");
  153. if (os_snprintf_error(buflen, ret))
  154. return 0;
  155. return ret;
  156. }
  157. sta = ap_get_sta(hapd, addr);
  158. if (sta == NULL)
  159. return -1;
  160. pos = os_strchr(txtaddr, ' ');
  161. if (pos) {
  162. pos++;
  163. #ifdef HOSTAPD_DUMP_STATE
  164. if (os_strcmp(pos, "eapol") == 0) {
  165. if (sta->eapol_sm == NULL)
  166. return -1;
  167. return eapol_auth_dump_state(sta->eapol_sm, buf,
  168. buflen);
  169. }
  170. #endif /* HOSTAPD_DUMP_STATE */
  171. return -1;
  172. }
  173. ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
  174. ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
  175. return ret;
  176. }
  177. int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
  178. char *buf, size_t buflen)
  179. {
  180. u8 addr[ETH_ALEN];
  181. struct sta_info *sta;
  182. int ret;
  183. if (hwaddr_aton(txtaddr, addr) ||
  184. (sta = ap_get_sta(hapd, addr)) == NULL) {
  185. ret = os_snprintf(buf, buflen, "FAIL\n");
  186. if (os_snprintf_error(buflen, ret))
  187. return 0;
  188. return ret;
  189. }
  190. if (!sta->next)
  191. return 0;
  192. return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
  193. }
  194. #ifdef CONFIG_P2P_MANAGER
  195. static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
  196. u8 minor_reason_code, const u8 *addr)
  197. {
  198. struct ieee80211_mgmt *mgmt;
  199. int ret;
  200. u8 *pos;
  201. if (hapd->driver->send_frame == NULL)
  202. return -1;
  203. mgmt = os_zalloc(sizeof(*mgmt) + 100);
  204. if (mgmt == NULL)
  205. return -1;
  206. mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
  207. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
  208. " with minor reason code %u (stype=%u (%s))",
  209. MAC2STR(addr), minor_reason_code, stype,
  210. fc2str(mgmt->frame_control));
  211. os_memcpy(mgmt->da, addr, ETH_ALEN);
  212. os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
  213. os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
  214. if (stype == WLAN_FC_STYPE_DEAUTH) {
  215. mgmt->u.deauth.reason_code =
  216. host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
  217. pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
  218. } else {
  219. mgmt->u.disassoc.reason_code =
  220. host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
  221. pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
  222. }
  223. *pos++ = WLAN_EID_VENDOR_SPECIFIC;
  224. *pos++ = 4 + 3 + 1;
  225. WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
  226. pos += 4;
  227. *pos++ = P2P_ATTR_MINOR_REASON_CODE;
  228. WPA_PUT_LE16(pos, 1);
  229. pos += 2;
  230. *pos++ = minor_reason_code;
  231. ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
  232. pos - (u8 *) mgmt, 1);
  233. os_free(mgmt);
  234. return ret < 0 ? -1 : 0;
  235. }
  236. #endif /* CONFIG_P2P_MANAGER */
  237. int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
  238. const char *txtaddr)
  239. {
  240. u8 addr[ETH_ALEN];
  241. struct sta_info *sta;
  242. const char *pos;
  243. u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
  244. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
  245. txtaddr);
  246. if (hwaddr_aton(txtaddr, addr))
  247. return -1;
  248. pos = os_strstr(txtaddr, " reason=");
  249. if (pos)
  250. reason = atoi(pos + 8);
  251. pos = os_strstr(txtaddr, " test=");
  252. if (pos) {
  253. struct ieee80211_mgmt mgmt;
  254. int encrypt;
  255. if (hapd->driver->send_frame == NULL)
  256. return -1;
  257. pos += 6;
  258. encrypt = atoi(pos);
  259. os_memset(&mgmt, 0, sizeof(mgmt));
  260. mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
  261. WLAN_FC_STYPE_DEAUTH);
  262. os_memcpy(mgmt.da, addr, ETH_ALEN);
  263. os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
  264. os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
  265. mgmt.u.deauth.reason_code = host_to_le16(reason);
  266. if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
  267. IEEE80211_HDRLEN +
  268. sizeof(mgmt.u.deauth),
  269. encrypt) < 0)
  270. return -1;
  271. return 0;
  272. }
  273. #ifdef CONFIG_P2P_MANAGER
  274. pos = os_strstr(txtaddr, " p2p=");
  275. if (pos) {
  276. return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
  277. atoi(pos + 5), addr);
  278. }
  279. #endif /* CONFIG_P2P_MANAGER */
  280. hostapd_drv_sta_deauth(hapd, addr, reason);
  281. sta = ap_get_sta(hapd, addr);
  282. if (sta)
  283. ap_sta_deauthenticate(hapd, sta, reason);
  284. else if (addr[0] == 0xff)
  285. hostapd_free_stas(hapd);
  286. return 0;
  287. }
  288. int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
  289. const char *txtaddr)
  290. {
  291. u8 addr[ETH_ALEN];
  292. struct sta_info *sta;
  293. const char *pos;
  294. u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
  295. wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
  296. txtaddr);
  297. if (hwaddr_aton(txtaddr, addr))
  298. return -1;
  299. pos = os_strstr(txtaddr, " reason=");
  300. if (pos)
  301. reason = atoi(pos + 8);
  302. pos = os_strstr(txtaddr, " test=");
  303. if (pos) {
  304. struct ieee80211_mgmt mgmt;
  305. int encrypt;
  306. if (hapd->driver->send_frame == NULL)
  307. return -1;
  308. pos += 6;
  309. encrypt = atoi(pos);
  310. os_memset(&mgmt, 0, sizeof(mgmt));
  311. mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
  312. WLAN_FC_STYPE_DISASSOC);
  313. os_memcpy(mgmt.da, addr, ETH_ALEN);
  314. os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
  315. os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
  316. mgmt.u.disassoc.reason_code = host_to_le16(reason);
  317. if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
  318. IEEE80211_HDRLEN +
  319. sizeof(mgmt.u.deauth),
  320. encrypt) < 0)
  321. return -1;
  322. return 0;
  323. }
  324. #ifdef CONFIG_P2P_MANAGER
  325. pos = os_strstr(txtaddr, " p2p=");
  326. if (pos) {
  327. return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
  328. atoi(pos + 5), addr);
  329. }
  330. #endif /* CONFIG_P2P_MANAGER */
  331. hostapd_drv_sta_disassoc(hapd, addr, reason);
  332. sta = ap_get_sta(hapd, addr);
  333. if (sta)
  334. ap_sta_disassociate(hapd, sta, reason);
  335. else if (addr[0] == 0xff)
  336. hostapd_free_stas(hapd);
  337. return 0;
  338. }
  339. int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
  340. size_t buflen)
  341. {
  342. struct hostapd_iface *iface = hapd->iface;
  343. int len = 0, ret;
  344. size_t i;
  345. ret = os_snprintf(buf + len, buflen - len,
  346. "state=%s\n"
  347. "phy=%s\n"
  348. "freq=%d\n"
  349. "num_sta_non_erp=%d\n"
  350. "num_sta_no_short_slot_time=%d\n"
  351. "num_sta_no_short_preamble=%d\n"
  352. "olbc=%d\n"
  353. "num_sta_ht_no_gf=%d\n"
  354. "num_sta_no_ht=%d\n"
  355. "num_sta_ht_20_mhz=%d\n"
  356. "num_sta_ht40_intolerant=%d\n"
  357. "olbc_ht=%d\n"
  358. "ht_op_mode=0x%x\n",
  359. hostapd_state_text(iface->state),
  360. iface->phy,
  361. iface->freq,
  362. iface->num_sta_non_erp,
  363. iface->num_sta_no_short_slot_time,
  364. iface->num_sta_no_short_preamble,
  365. iface->olbc,
  366. iface->num_sta_ht_no_gf,
  367. iface->num_sta_no_ht,
  368. iface->num_sta_ht_20mhz,
  369. iface->num_sta_ht40_intolerant,
  370. iface->olbc_ht,
  371. iface->ht_op_mode);
  372. if (os_snprintf_error(buflen - len, ret))
  373. return len;
  374. len += ret;
  375. if (!iface->cac_started || !iface->dfs_cac_ms) {
  376. ret = os_snprintf(buf + len, buflen - len,
  377. "cac_time_seconds=%d\n"
  378. "cac_time_left_seconds=N/A\n",
  379. iface->dfs_cac_ms / 1000);
  380. } else {
  381. /* CAC started and CAC time set - calculate remaining time */
  382. struct os_reltime now;
  383. unsigned int left_time;
  384. os_reltime_age(&iface->dfs_cac_start, &now);
  385. left_time = iface->dfs_cac_ms / 1000 - now.sec;
  386. ret = os_snprintf(buf + len, buflen - len,
  387. "cac_time_seconds=%u\n"
  388. "cac_time_left_seconds=%u\n",
  389. iface->dfs_cac_ms / 1000,
  390. left_time);
  391. }
  392. if (os_snprintf_error(buflen - len, ret))
  393. return len;
  394. len += ret;
  395. ret = os_snprintf(buf + len, buflen - len,
  396. "channel=%u\n"
  397. "secondary_channel=%d\n"
  398. "ieee80211n=%d\n"
  399. "ieee80211ac=%d\n"
  400. "vht_oper_chwidth=%d\n"
  401. "vht_oper_centr_freq_seg0_idx=%d\n"
  402. "vht_oper_centr_freq_seg1_idx=%d\n",
  403. iface->conf->channel,
  404. iface->conf->secondary_channel,
  405. iface->conf->ieee80211n,
  406. iface->conf->ieee80211ac,
  407. iface->conf->vht_oper_chwidth,
  408. iface->conf->vht_oper_centr_freq_seg0_idx,
  409. iface->conf->vht_oper_centr_freq_seg1_idx);
  410. if (os_snprintf_error(buflen - len, ret))
  411. return len;
  412. len += ret;
  413. for (i = 0; i < iface->num_bss; i++) {
  414. struct hostapd_data *bss = iface->bss[i];
  415. ret = os_snprintf(buf + len, buflen - len,
  416. "bss[%d]=%s\n"
  417. "bssid[%d]=" MACSTR "\n"
  418. "ssid[%d]=%s\n"
  419. "num_sta[%d]=%d\n",
  420. (int) i, bss->conf->iface,
  421. (int) i, MAC2STR(bss->own_addr),
  422. (int) i,
  423. wpa_ssid_txt(bss->conf->ssid.ssid,
  424. bss->conf->ssid.ssid_len),
  425. (int) i, bss->num_sta);
  426. if (os_snprintf_error(buflen - len, ret))
  427. return len;
  428. len += ret;
  429. }
  430. return len;
  431. }
  432. int hostapd_parse_csa_settings(const char *pos,
  433. struct csa_settings *settings)
  434. {
  435. char *end;
  436. os_memset(settings, 0, sizeof(*settings));
  437. settings->cs_count = strtol(pos, &end, 10);
  438. if (pos == end) {
  439. wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
  440. return -1;
  441. }
  442. settings->freq_params.freq = atoi(end);
  443. if (settings->freq_params.freq == 0) {
  444. wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
  445. return -1;
  446. }
  447. #define SET_CSA_SETTING(str) \
  448. do { \
  449. const char *pos2 = os_strstr(pos, " " #str "="); \
  450. if (pos2) { \
  451. pos2 += sizeof(" " #str "=") - 1; \
  452. settings->freq_params.str = atoi(pos2); \
  453. } \
  454. } while (0)
  455. SET_CSA_SETTING(center_freq1);
  456. SET_CSA_SETTING(center_freq2);
  457. SET_CSA_SETTING(bandwidth);
  458. SET_CSA_SETTING(sec_channel_offset);
  459. settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
  460. settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
  461. settings->block_tx = !!os_strstr(pos, " blocktx");
  462. #undef SET_CSA_SETTING
  463. return 0;
  464. }
  465. int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
  466. {
  467. return hostapd_drv_stop_ap(hapd);
  468. }