rrm.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. * hostapd / Radio Measurement (RRM)
  3. * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
  4. * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
  5. * Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi>
  6. *
  7. * This software may be distributed under the terms of the BSD license.
  8. * See README for more details.
  9. */
  10. #include "utils/includes.h"
  11. #include "utils/common.h"
  12. #include "common/wpa_ctrl.h"
  13. #include "hostapd.h"
  14. #include "ap_drv_ops.h"
  15. #include "sta_info.h"
  16. #include "eloop.h"
  17. #include "neighbor_db.h"
  18. #include "rrm.h"
  19. #define HOSTAPD_RRM_REQUEST_TIMEOUT 5
  20. static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
  21. {
  22. struct hostapd_data *hapd = eloop_data;
  23. wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
  24. hapd->lci_req_token);
  25. hapd->lci_req_active = 0;
  26. }
  27. static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
  28. const u8 *pos, size_t len)
  29. {
  30. if (!hapd->lci_req_active || hapd->lci_req_token != token) {
  31. wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
  32. return;
  33. }
  34. hapd->lci_req_active = 0;
  35. eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
  36. wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
  37. }
  38. static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
  39. {
  40. struct hostapd_data *hapd = eloop_data;
  41. wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
  42. hapd->range_req_token);
  43. hapd->range_req_active = 0;
  44. }
  45. static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
  46. const u8 *pos, size_t len)
  47. {
  48. if (!hapd->range_req_active || hapd->range_req_token != token) {
  49. wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
  50. token);
  51. return;
  52. }
  53. hapd->range_req_active = 0;
  54. eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
  55. wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
  56. }
  57. static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
  58. const u8 *addr, u8 token, u8 rep_mode,
  59. const u8 *pos, size_t len)
  60. {
  61. char report[2 * 255 + 1];
  62. wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
  63. token, len, MAC2STR(addr));
  64. /* Skip to the beginning of the Beacon report */
  65. if (len < 3)
  66. return;
  67. pos += 3;
  68. len -= 3;
  69. report[0] = '\0';
  70. if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
  71. return;
  72. wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
  73. MAC2STR(addr), token, rep_mode, report);
  74. }
  75. static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
  76. const u8 *buf, size_t len)
  77. {
  78. const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
  79. const u8 *pos, *ie, *end;
  80. u8 token, rep_mode;
  81. end = buf + len;
  82. token = mgmt->u.action.u.rrm.dialog_token;
  83. pos = mgmt->u.action.u.rrm.variable;
  84. while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
  85. if (ie[1] < 3) {
  86. wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
  87. break;
  88. }
  89. rep_mode = ie[3];
  90. wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
  91. rep_mode, ie[4]);
  92. switch (ie[4]) {
  93. case MEASURE_TYPE_LCI:
  94. hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
  95. break;
  96. case MEASURE_TYPE_FTM_RANGE:
  97. hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
  98. break;
  99. case MEASURE_TYPE_BEACON:
  100. hostapd_handle_beacon_report(hapd, mgmt->sa, token,
  101. rep_mode, ie + 2, ie[1]);
  102. break;
  103. default:
  104. wpa_printf(MSG_DEBUG,
  105. "Measurement report type %u is not supported",
  106. ie[4]);
  107. break;
  108. }
  109. pos = ie + ie[1] + 2;
  110. }
  111. }
  112. static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
  113. {
  114. const u8 *subelem;
  115. /* Range Request element + Location Subject + Maximum Age subelement */
  116. if (len < 3 + 1 + 4)
  117. return 0;
  118. /* Subelements are arranged as IEs */
  119. subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
  120. if (subelem && subelem[1] == 2)
  121. return WPA_GET_LE16(subelem + 2);
  122. return 0;
  123. }
  124. static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
  125. {
  126. struct os_time curr, diff;
  127. unsigned long diff_l;
  128. if (nr->stationary || max_age == 0xffff)
  129. return 1;
  130. if (!max_age)
  131. return 0;
  132. if (os_get_time(&curr))
  133. return 0;
  134. os_time_sub(&curr, &nr->lci_date, &diff);
  135. /* avoid overflow */
  136. if (diff.sec > 0xffff)
  137. return 0;
  138. /* LCI age is calculated in 10th of a second units. */
  139. diff_l = diff.sec * 10 + diff.usec / 100000;
  140. return max_age > diff_l;
  141. }
  142. static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
  143. struct hostapd_neighbor_entry *nr,
  144. int send_lci, int send_civic)
  145. {
  146. size_t len = 2 + wpabuf_len(nr->nr);
  147. if (send_lci && nr->lci)
  148. len += 2 + wpabuf_len(nr->lci);
  149. if (send_civic && nr->civic)
  150. len += 2 + wpabuf_len(nr->civic);
  151. return len;
  152. }
  153. static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
  154. const u8 *addr, u8 dialog_token,
  155. struct wpa_ssid_value *ssid, u8 lci,
  156. u8 civic, u16 lci_max_age)
  157. {
  158. struct hostapd_neighbor_entry *nr;
  159. struct wpabuf *buf;
  160. u8 *msmt_token;
  161. /*
  162. * The number and length of the Neighbor Report elements in a Neighbor
  163. * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
  164. * of RRM header.
  165. */
  166. buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
  167. if (!buf)
  168. return;
  169. wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
  170. wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
  171. wpabuf_put_u8(buf, dialog_token);
  172. dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
  173. list) {
  174. int send_lci;
  175. size_t len;
  176. if (ssid->ssid_len != nr->ssid.ssid_len ||
  177. os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
  178. continue;
  179. send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
  180. len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
  181. if (len - 2 > 0xff) {
  182. wpa_printf(MSG_DEBUG,
  183. "NR entry for " MACSTR " exceeds 0xFF bytes",
  184. MAC2STR(nr->bssid));
  185. continue;
  186. }
  187. if (len > wpabuf_tailroom(buf))
  188. break;
  189. wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
  190. wpabuf_put_u8(buf, len - 2);
  191. wpabuf_put_buf(buf, nr->nr);
  192. if (send_lci && nr->lci) {
  193. wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
  194. wpabuf_put_u8(buf, wpabuf_len(nr->lci));
  195. /*
  196. * Override measurement token - the first byte of the
  197. * Measurement Report element.
  198. */
  199. msmt_token = wpabuf_put(buf, 0);
  200. wpabuf_put_buf(buf, nr->lci);
  201. *msmt_token = lci;
  202. }
  203. if (civic && nr->civic) {
  204. wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
  205. wpabuf_put_u8(buf, wpabuf_len(nr->civic));
  206. /*
  207. * Override measurement token - the first byte of the
  208. * Measurement Report element.
  209. */
  210. msmt_token = wpabuf_put(buf, 0);
  211. wpabuf_put_buf(buf, nr->civic);
  212. *msmt_token = civic;
  213. }
  214. }
  215. hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
  216. wpabuf_head(buf), wpabuf_len(buf));
  217. wpabuf_free(buf);
  218. }
  219. static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
  220. const u8 *buf, size_t len)
  221. {
  222. const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
  223. const u8 *pos, *ie, *end;
  224. struct wpa_ssid_value ssid = {
  225. .ssid_len = 0
  226. };
  227. u8 token;
  228. u8 lci = 0, civic = 0; /* Measurement tokens */
  229. u16 lci_max_age = 0;
  230. if (!(hapd->conf->radio_measurements[0] &
  231. WLAN_RRM_CAPS_NEIGHBOR_REPORT))
  232. return;
  233. end = buf + len;
  234. token = mgmt->u.action.u.rrm.dialog_token;
  235. pos = mgmt->u.action.u.rrm.variable;
  236. len = end - pos;
  237. ie = get_ie(pos, len, WLAN_EID_SSID);
  238. if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
  239. ssid.ssid_len = ie[1];
  240. os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
  241. } else {
  242. ssid.ssid_len = hapd->conf->ssid.ssid_len;
  243. os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
  244. }
  245. while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
  246. if (ie[1] < 3)
  247. break;
  248. wpa_printf(MSG_DEBUG,
  249. "Neighbor report request, measure type %u",
  250. ie[4]);
  251. switch (ie[4]) { /* Measurement Type */
  252. case MEASURE_TYPE_LCI:
  253. lci = ie[2]; /* Measurement Token */
  254. lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
  255. ie[1]);
  256. break;
  257. case MEASURE_TYPE_LOCATION_CIVIC:
  258. civic = ie[2]; /* Measurement token */
  259. break;
  260. }
  261. pos = ie + ie[1] + 2;
  262. len = end - pos;
  263. }
  264. hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
  265. lci_max_age);
  266. }
  267. void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
  268. const u8 *buf, size_t len)
  269. {
  270. const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
  271. /*
  272. * Check for enough bytes: header + (1B)Category + (1B)Action +
  273. * (1B)Dialog Token.
  274. */
  275. if (len < IEEE80211_HDRLEN + 3)
  276. return;
  277. wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
  278. mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
  279. switch (mgmt->u.action.u.rrm.action) {
  280. case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
  281. hostapd_handle_radio_msmt_report(hapd, buf, len);
  282. break;
  283. case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
  284. hostapd_handle_nei_report_req(hapd, buf, len);
  285. break;
  286. default:
  287. wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
  288. mgmt->u.action.u.rrm.action);
  289. break;
  290. }
  291. }
  292. int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
  293. {
  294. struct wpabuf *buf;
  295. struct sta_info *sta = ap_get_sta(hapd, addr);
  296. int ret;
  297. if (!sta) {
  298. wpa_printf(MSG_INFO,
  299. "Request LCI: Destination address is not in station list");
  300. return -1;
  301. }
  302. if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
  303. wpa_printf(MSG_INFO,
  304. "Request LCI: Destination address is not connected");
  305. return -1;
  306. }
  307. if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
  308. wpa_printf(MSG_INFO,
  309. "Request LCI: Station does not support LCI in RRM");
  310. return -1;
  311. }
  312. if (hapd->lci_req_active) {
  313. wpa_printf(MSG_DEBUG,
  314. "Request LCI: LCI request is already in process, overriding");
  315. hapd->lci_req_active = 0;
  316. eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
  317. NULL);
  318. }
  319. /* Measurement request (5) + Measurement element with LCI (10) */
  320. buf = wpabuf_alloc(5 + 10);
  321. if (!buf)
  322. return -1;
  323. hapd->lci_req_token++;
  324. /* For wraparounds - the token must be nonzero */
  325. if (!hapd->lci_req_token)
  326. hapd->lci_req_token++;
  327. wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
  328. wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
  329. wpabuf_put_u8(buf, hapd->lci_req_token);
  330. wpabuf_put_le16(buf, 0); /* Number of repetitions */
  331. wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
  332. wpabuf_put_u8(buf, 3 + 1 + 4);
  333. wpabuf_put_u8(buf, 1); /* Measurement Token */
  334. /*
  335. * Parallel and Enable bits are 0, Duration, Request, and Report are
  336. * reserved.
  337. */
  338. wpabuf_put_u8(buf, 0);
  339. wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
  340. wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
  341. wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
  342. wpabuf_put_u8(buf, 2);
  343. wpabuf_put_le16(buf, 0xffff);
  344. ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
  345. wpabuf_head(buf), wpabuf_len(buf));
  346. wpabuf_free(buf);
  347. if (ret)
  348. return ret;
  349. hapd->lci_req_active = 1;
  350. eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
  351. hostapd_lci_rep_timeout_handler, hapd, NULL);
  352. return 0;
  353. }
  354. int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
  355. u16 random_interval, u8 min_ap,
  356. const u8 *responders, unsigned int n_responders)
  357. {
  358. struct wpabuf *buf;
  359. struct sta_info *sta;
  360. u8 *len;
  361. unsigned int i;
  362. int ret;
  363. wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
  364. " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
  365. random_interval, min_ap, n_responders);
  366. if (min_ap == 0 || min_ap > n_responders) {
  367. wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
  368. return -1;
  369. }
  370. sta = ap_get_sta(hapd, addr);
  371. if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
  372. wpa_printf(MSG_INFO,
  373. "Request range: Destination address is not connected");
  374. return -1;
  375. }
  376. if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
  377. wpa_printf(MSG_ERROR,
  378. "Request range: Destination station does not support FTM range report in RRM");
  379. return -1;
  380. }
  381. if (hapd->range_req_active) {
  382. wpa_printf(MSG_DEBUG,
  383. "Request range: Range request is already in process; overriding");
  384. hapd->range_req_active = 0;
  385. eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
  386. hostapd_range_rep_timeout_handler, hapd,
  387. NULL);
  388. }
  389. /* Action + measurement type + token + reps + EID + len = 7 */
  390. buf = wpabuf_alloc(7 + 255);
  391. if (!buf)
  392. return -1;
  393. hapd->range_req_token++;
  394. if (!hapd->range_req_token) /* For wraparounds */
  395. hapd->range_req_token++;
  396. /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
  397. wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
  398. wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
  399. wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
  400. wpabuf_put_le16(buf, 0); /* Number of Repetitions */
  401. /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
  402. wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
  403. len = wpabuf_put(buf, 1); /* Length will be set later */
  404. wpabuf_put_u8(buf, 1); /* Measurement Token */
  405. /*
  406. * Parallel and Enable bits are 0; Duration, Request, and Report are
  407. * reserved.
  408. */
  409. wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
  410. wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
  411. /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
  412. wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
  413. wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
  414. /* FTM Range Subelements */
  415. /*
  416. * Taking the neighbor report part of the range request from neighbor
  417. * database instead of requesting the separate bits of data from the
  418. * user.
  419. */
  420. for (i = 0; i < n_responders; i++) {
  421. struct hostapd_neighbor_entry *nr;
  422. nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
  423. NULL);
  424. if (!nr) {
  425. wpa_printf(MSG_INFO, "Missing neighbor report for "
  426. MACSTR, MAC2STR(responders + ETH_ALEN * i));
  427. wpabuf_free(buf);
  428. return -1;
  429. }
  430. if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
  431. wpa_printf(MSG_ERROR, "Too long range request");
  432. wpabuf_free(buf);
  433. return -1;
  434. }
  435. wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
  436. wpabuf_put_u8(buf, wpabuf_len(nr->nr));
  437. wpabuf_put_buf(buf, nr->nr);
  438. }
  439. /* Action + measurement type + token + reps + EID + len = 7 */
  440. *len = wpabuf_len(buf) - 7;
  441. ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
  442. wpabuf_head(buf), wpabuf_len(buf));
  443. wpabuf_free(buf);
  444. if (ret)
  445. return ret;
  446. hapd->range_req_active = 1;
  447. eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
  448. hostapd_range_rep_timeout_handler, hapd, NULL);
  449. return 0;
  450. }
  451. void hostapd_clean_rrm(struct hostapd_data *hapd)
  452. {
  453. hostpad_free_neighbor_db(hapd);
  454. eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
  455. hapd->lci_req_active = 0;
  456. eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
  457. hapd->range_req_active = 0;
  458. }
  459. int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
  460. u8 req_mode, const struct wpabuf *req)
  461. {
  462. struct wpabuf *buf;
  463. struct sta_info *sta = ap_get_sta(hapd, addr);
  464. int ret;
  465. enum beacon_report_mode mode;
  466. const u8 *pos;
  467. /* Request data:
  468. * Operating Class (1), Channel Number (1), Randomization Interval (2),
  469. * Measurement Duration (2), Measurement Mode (1), BSSID (6),
  470. * Optional Subelements (variable)
  471. */
  472. if (wpabuf_len(req) < 13) {
  473. wpa_printf(MSG_INFO, "Beacon request: Too short request data");
  474. return -1;
  475. }
  476. pos = wpabuf_head(req);
  477. mode = pos[6];
  478. if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
  479. wpa_printf(MSG_INFO,
  480. "Beacon request: " MACSTR " is not connected",
  481. MAC2STR(addr));
  482. return -1;
  483. }
  484. switch (mode) {
  485. case BEACON_REPORT_MODE_PASSIVE:
  486. if (!(sta->rrm_enabled_capa[0] &
  487. WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
  488. wpa_printf(MSG_INFO,
  489. "Beacon request: " MACSTR
  490. " does not support passive beacon report",
  491. MAC2STR(addr));
  492. return -1;
  493. }
  494. break;
  495. case BEACON_REPORT_MODE_ACTIVE:
  496. if (!(sta->rrm_enabled_capa[0] &
  497. WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
  498. wpa_printf(MSG_INFO,
  499. "Beacon request: " MACSTR
  500. " does not support active beacon report",
  501. MAC2STR(addr));
  502. return -1;
  503. }
  504. break;
  505. case BEACON_REPORT_MODE_TABLE:
  506. if (!(sta->rrm_enabled_capa[0] &
  507. WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
  508. wpa_printf(MSG_INFO,
  509. "Beacon request: " MACSTR
  510. " does not support table beacon report",
  511. MAC2STR(addr));
  512. return -1;
  513. }
  514. break;
  515. default:
  516. wpa_printf(MSG_INFO,
  517. "Beacon request: Unknown measurement mode %d", mode);
  518. return -1;
  519. }
  520. buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
  521. if (!buf)
  522. return -1;
  523. hapd->beacon_req_token++;
  524. if (!hapd->beacon_req_token)
  525. hapd->beacon_req_token++;
  526. wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
  527. wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
  528. wpabuf_put_u8(buf, hapd->beacon_req_token);
  529. wpabuf_put_le16(buf, 0); /* Number of repetitions */
  530. /* Measurement Request element */
  531. wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
  532. wpabuf_put_u8(buf, 3 + wpabuf_len(req));
  533. wpabuf_put_u8(buf, 1); /* Measurement Token */
  534. wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
  535. wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
  536. wpabuf_put_buf(buf, req);
  537. ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
  538. wpabuf_head(buf), wpabuf_len(buf));
  539. wpabuf_free(buf);
  540. if (ret < 0)
  541. return ret;
  542. return hapd->beacon_req_token;
  543. }
  544. void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
  545. const struct ieee80211_mgmt *mgmt,
  546. size_t len, int ok)
  547. {
  548. if (len < 24 + 3)
  549. return;
  550. wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
  551. " %u ack=%d", MAC2STR(mgmt->da),
  552. mgmt->u.action.u.rrm.dialog_token, ok);
  553. }