wmm_ac.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. /*
  2. * Wi-Fi Multimedia Admission Control (WMM-AC)
  3. * Copyright(c) 2014, Intel Mobile Communication GmbH.
  4. * Copyright(c) 2014, Intel Corporation. All rights reserved.
  5. *
  6. * This software may be distributed under the terms of the BSD license.
  7. * See README for more details.
  8. */
  9. #include "includes.h"
  10. #include "utils/common.h"
  11. #include "utils/list.h"
  12. #include "utils/eloop.h"
  13. #include "common/ieee802_11_common.h"
  14. #include "wpa_supplicant_i.h"
  15. #include "bss.h"
  16. #include "driver_i.h"
  17. #include "wmm_ac.h"
  18. static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx);
  19. static const enum wmm_ac up_to_ac[8] = {
  20. WMM_AC_BK,
  21. WMM_AC_BE,
  22. WMM_AC_BE,
  23. WMM_AC_BK,
  24. WMM_AC_VI,
  25. WMM_AC_VI,
  26. WMM_AC_VO,
  27. WMM_AC_VO
  28. };
  29. static inline u8 wmm_ac_get_tsid(const struct wmm_tspec_element *tspec)
  30. {
  31. return (tspec->ts_info[0] >> 1) & 0x0f;
  32. }
  33. static u8 wmm_ac_get_direction(const struct wmm_tspec_element *tspec)
  34. {
  35. return (tspec->ts_info[0] >> 5) & 0x03;
  36. }
  37. static u8 wmm_ac_get_user_priority(const struct wmm_tspec_element *tspec)
  38. {
  39. return (tspec->ts_info[1] >> 3) & 0x07;
  40. }
  41. static u8 wmm_ac_direction_to_idx(u8 direction)
  42. {
  43. switch (direction) {
  44. case WMM_AC_DIR_UPLINK:
  45. return TS_DIR_IDX_UPLINK;
  46. case WMM_AC_DIR_DOWNLINK:
  47. return TS_DIR_IDX_DOWNLINK;
  48. case WMM_AC_DIR_BIDIRECTIONAL:
  49. return TS_DIR_IDX_BIDI;
  50. default:
  51. wpa_printf(MSG_ERROR, "Invalid direction: %d", direction);
  52. return WMM_AC_DIR_UPLINK;
  53. }
  54. }
  55. static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr,
  56. const struct wmm_tspec_element *tspec)
  57. {
  58. struct wmm_tspec_element *_tspec;
  59. int ret;
  60. u16 admitted_time = le_to_host16(tspec->medium_time);
  61. u8 up = wmm_ac_get_user_priority(tspec);
  62. u8 ac = up_to_ac[up];
  63. u8 dir = wmm_ac_get_direction(tspec);
  64. u8 tsid = wmm_ac_get_tsid(tspec);
  65. enum ts_dir_idx idx = wmm_ac_direction_to_idx(dir);
  66. /* should have been verified before, but double-check here */
  67. if (wpa_s->tspecs[ac][idx]) {
  68. wpa_printf(MSG_ERROR,
  69. "WMM AC: tspec (ac=%d, dir=%d) already exists!",
  70. ac, dir);
  71. return -1;
  72. }
  73. /* copy tspec */
  74. _tspec = os_memdup(tspec, sizeof(*_tspec));
  75. if (!_tspec)
  76. return -1;
  77. if (dir != WMM_AC_DIR_DOWNLINK) {
  78. ret = wpa_drv_add_ts(wpa_s, tsid, addr, up, admitted_time);
  79. wpa_printf(MSG_DEBUG,
  80. "WMM AC: Add TS: addr=" MACSTR
  81. " TSID=%u admitted time=%u, ret=%d",
  82. MAC2STR(addr), tsid, admitted_time, ret);
  83. if (ret < 0) {
  84. os_free(_tspec);
  85. return -1;
  86. }
  87. }
  88. wpa_s->tspecs[ac][idx] = _tspec;
  89. wpa_printf(MSG_DEBUG, "Traffic stream was created successfully");
  90. wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_ADDED
  91. "tsid=%d addr=" MACSTR " admitted_time=%d",
  92. tsid, MAC2STR(addr), admitted_time);
  93. return 0;
  94. }
  95. static void wmm_ac_del_ts_idx(struct wpa_supplicant *wpa_s, u8 ac,
  96. enum ts_dir_idx dir)
  97. {
  98. struct wmm_tspec_element *tspec = wpa_s->tspecs[ac][dir];
  99. u8 tsid;
  100. if (!tspec)
  101. return;
  102. tsid = wmm_ac_get_tsid(tspec);
  103. wpa_printf(MSG_DEBUG, "WMM AC: Del TS ac=%d tsid=%d", ac, tsid);
  104. /* update the driver in case of uplink/bidi */
  105. if (wmm_ac_get_direction(tspec) != WMM_AC_DIR_DOWNLINK)
  106. wpa_drv_del_ts(wpa_s, tsid, wpa_s->bssid);
  107. wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REMOVED
  108. "tsid=%d addr=" MACSTR, tsid, MAC2STR(wpa_s->bssid));
  109. os_free(wpa_s->tspecs[ac][dir]);
  110. wpa_s->tspecs[ac][dir] = NULL;
  111. }
  112. static void wmm_ac_del_req(struct wpa_supplicant *wpa_s, int failed)
  113. {
  114. struct wmm_ac_addts_request *req = wpa_s->addts_request;
  115. if (!req)
  116. return;
  117. if (failed)
  118. wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED
  119. "tsid=%u", wmm_ac_get_tsid(&req->tspec));
  120. eloop_cancel_timeout(wmm_ac_addts_req_timeout, wpa_s, req);
  121. wpa_s->addts_request = NULL;
  122. os_free(req);
  123. }
  124. static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx)
  125. {
  126. struct wpa_supplicant *wpa_s = eloop_ctx;
  127. struct wmm_ac_addts_request *addts_req = timeout_ctx;
  128. wpa_printf(MSG_DEBUG,
  129. "Timeout getting ADDTS response (tsid=%d up=%d)",
  130. wmm_ac_get_tsid(&addts_req->tspec),
  131. wmm_ac_get_user_priority(&addts_req->tspec));
  132. wmm_ac_del_req(wpa_s, 1);
  133. }
  134. static int wmm_ac_send_addts_request(struct wpa_supplicant *wpa_s,
  135. const struct wmm_ac_addts_request *req)
  136. {
  137. struct wpabuf *buf;
  138. int ret;
  139. wpa_printf(MSG_DEBUG, "Sending ADDTS Request to " MACSTR,
  140. MAC2STR(req->address));
  141. /* category + action code + dialog token + status + sizeof(tspec) */
  142. buf = wpabuf_alloc(4 + sizeof(req->tspec));
  143. if (!buf) {
  144. wpa_printf(MSG_ERROR, "WMM AC: Allocation error");
  145. return -1;
  146. }
  147. wpabuf_put_u8(buf, WLAN_ACTION_WMM);
  148. wpabuf_put_u8(buf, WMM_ACTION_CODE_ADDTS_REQ);
  149. wpabuf_put_u8(buf, req->dialog_token);
  150. wpabuf_put_u8(buf, 0); /* status code */
  151. wpabuf_put_data(buf, &req->tspec, sizeof(req->tspec));
  152. ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, req->address,
  153. wpa_s->own_addr, wpa_s->bssid,
  154. wpabuf_head(buf), wpabuf_len(buf), 0);
  155. if (ret) {
  156. wpa_printf(MSG_WARNING,
  157. "WMM AC: Failed to send ADDTS Request");
  158. }
  159. wpabuf_free(buf);
  160. return ret;
  161. }
  162. static int wmm_ac_send_delts(struct wpa_supplicant *wpa_s,
  163. const struct wmm_tspec_element *tspec,
  164. const u8 *address)
  165. {
  166. struct wpabuf *buf;
  167. int ret;
  168. /* category + action code + dialog token + status + sizeof(tspec) */
  169. buf = wpabuf_alloc(4 + sizeof(*tspec));
  170. if (!buf)
  171. return -1;
  172. wpa_printf(MSG_DEBUG, "Sending DELTS to " MACSTR, MAC2STR(address));
  173. /* category + action code + dialog token + status + sizeof(tspec) */
  174. wpabuf_put_u8(buf, WLAN_ACTION_WMM);
  175. wpabuf_put_u8(buf, WMM_ACTION_CODE_DELTS);
  176. wpabuf_put_u8(buf, 0); /* Dialog Token (not used) */
  177. wpabuf_put_u8(buf, 0); /* Status Code (not used) */
  178. wpabuf_put_data(buf, tspec, sizeof(*tspec));
  179. ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, address,
  180. wpa_s->own_addr, wpa_s->bssid,
  181. wpabuf_head(buf), wpabuf_len(buf), 0);
  182. if (ret)
  183. wpa_printf(MSG_WARNING, "Failed to send DELTS frame");
  184. wpabuf_free(buf);
  185. return ret;
  186. }
  187. /* return the AC using the given TSPEC tid */
  188. static int wmm_ac_find_tsid(struct wpa_supplicant *wpa_s, u8 tsid,
  189. enum ts_dir_idx *dir)
  190. {
  191. int ac;
  192. enum ts_dir_idx idx;
  193. for (ac = 0; ac < WMM_AC_NUM; ac++) {
  194. for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
  195. if (wpa_s->tspecs[ac][idx] &&
  196. wmm_ac_get_tsid(wpa_s->tspecs[ac][idx]) == tsid) {
  197. if (dir)
  198. *dir = idx;
  199. return ac;
  200. }
  201. }
  202. }
  203. return -1;
  204. }
  205. static struct wmm_ac_addts_request *
  206. wmm_ac_build_addts_req(struct wpa_supplicant *wpa_s,
  207. const struct wmm_ac_ts_setup_params *params,
  208. const u8 *address)
  209. {
  210. struct wmm_ac_addts_request *addts_req;
  211. struct wmm_tspec_element *tspec;
  212. u8 ac = up_to_ac[params->user_priority];
  213. u8 uapsd = wpa_s->wmm_ac_assoc_info->ac_params[ac].uapsd;
  214. addts_req = os_zalloc(sizeof(*addts_req));
  215. if (!addts_req)
  216. return NULL;
  217. tspec = &addts_req->tspec;
  218. os_memcpy(addts_req->address, address, ETH_ALEN);
  219. /* The dialog token cannot be zero */
  220. if (++wpa_s->wmm_ac_last_dialog_token == 0)
  221. wpa_s->wmm_ac_last_dialog_token++;
  222. addts_req->dialog_token = wpa_s->wmm_ac_last_dialog_token;
  223. tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
  224. tspec->length = sizeof(*tspec) - 2; /* reduce eid and length */
  225. tspec->oui[0] = 0x00;
  226. tspec->oui[1] = 0x50;
  227. tspec->oui[2] = 0xf2;
  228. tspec->oui_type = WMM_OUI_TYPE;
  229. tspec->oui_subtype = WMM_OUI_SUBTYPE_TSPEC_ELEMENT;
  230. tspec->version = WMM_VERSION;
  231. tspec->ts_info[0] = params->tsid << 1;
  232. tspec->ts_info[0] |= params->direction << 5;
  233. tspec->ts_info[0] |= WMM_AC_ACCESS_POLICY_EDCA << 7;
  234. tspec->ts_info[1] = uapsd << 2;
  235. tspec->ts_info[1] |= params->user_priority << 3;
  236. tspec->ts_info[2] = 0;
  237. tspec->nominal_msdu_size = host_to_le16(params->nominal_msdu_size);
  238. if (params->fixed_nominal_msdu)
  239. tspec->nominal_msdu_size |=
  240. host_to_le16(WMM_AC_FIXED_MSDU_SIZE);
  241. tspec->mean_data_rate = host_to_le32(params->mean_data_rate);
  242. tspec->minimum_phy_rate = host_to_le32(params->minimum_phy_rate);
  243. tspec->surplus_bandwidth_allowance =
  244. host_to_le16(params->surplus_bandwidth_allowance);
  245. return addts_req;
  246. }
  247. static int param_in_range(const char *name, long value,
  248. long min_val, long max_val)
  249. {
  250. if (value < min_val || (max_val >= 0 && value > max_val)) {
  251. wpa_printf(MSG_DEBUG,
  252. "WMM AC: param %s (%ld) is out of range (%ld-%ld)",
  253. name, value, min_val, max_val);
  254. return 0;
  255. }
  256. return 1;
  257. }
  258. static int wmm_ac_should_replace_ts(struct wpa_supplicant *wpa_s,
  259. u8 tsid, u8 ac, u8 dir)
  260. {
  261. enum ts_dir_idx idx;
  262. int cur_ac, existing_ts = 0, replace_ts = 0;
  263. cur_ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
  264. if (cur_ac >= 0) {
  265. if (cur_ac != ac) {
  266. wpa_printf(MSG_DEBUG,
  267. "WMM AC: TSID %i already exists on different ac (%d)",
  268. tsid, cur_ac);
  269. return -1;
  270. }
  271. /* same tsid - this tspec will replace the current one */
  272. replace_ts |= BIT(idx);
  273. }
  274. for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
  275. if (wpa_s->tspecs[ac][idx])
  276. existing_ts |= BIT(idx);
  277. }
  278. switch (dir) {
  279. case WMM_AC_DIR_UPLINK:
  280. /* replace existing uplink/bidi tspecs */
  281. replace_ts |= existing_ts & (BIT(TS_DIR_IDX_UPLINK) |
  282. BIT(TS_DIR_IDX_BIDI));
  283. break;
  284. case WMM_AC_DIR_DOWNLINK:
  285. /* replace existing downlink/bidi tspecs */
  286. replace_ts |= existing_ts & (BIT(TS_DIR_IDX_DOWNLINK) |
  287. BIT(TS_DIR_IDX_BIDI));
  288. break;
  289. case WMM_AC_DIR_BIDIRECTIONAL:
  290. /* replace all existing tspecs */
  291. replace_ts |= existing_ts;
  292. break;
  293. default:
  294. return -1;
  295. }
  296. return replace_ts;
  297. }
  298. static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
  299. const struct wmm_ac_ts_setup_params *params)
  300. {
  301. enum wmm_ac req_ac;
  302. #define PARAM_IN_RANGE(field, min_value, max_value) \
  303. param_in_range(#field, params->field, min_value, max_value)
  304. if (!PARAM_IN_RANGE(tsid, 0, WMM_AC_MAX_TID) ||
  305. !PARAM_IN_RANGE(user_priority, 0, WMM_AC_MAX_USER_PRIORITY) ||
  306. !PARAM_IN_RANGE(nominal_msdu_size, 1, WMM_AC_MAX_NOMINAL_MSDU) ||
  307. !PARAM_IN_RANGE(mean_data_rate, 1, -1) ||
  308. !PARAM_IN_RANGE(minimum_phy_rate, 1, -1) ||
  309. !PARAM_IN_RANGE(surplus_bandwidth_allowance, WMM_AC_MIN_SBA_UNITY,
  310. -1))
  311. return 0;
  312. #undef PARAM_IN_RANGE
  313. if (!(params->direction == WMM_TSPEC_DIRECTION_UPLINK ||
  314. params->direction == WMM_TSPEC_DIRECTION_DOWNLINK ||
  315. params->direction == WMM_TSPEC_DIRECTION_BI_DIRECTIONAL)) {
  316. wpa_printf(MSG_DEBUG, "WMM AC: invalid TS direction: %d",
  317. params->direction);
  318. return 0;
  319. }
  320. req_ac = up_to_ac[params->user_priority];
  321. /* Requested accesss category must have acm */
  322. if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
  323. wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
  324. return 0;
  325. }
  326. if (wmm_ac_should_replace_ts(wpa_s, params->tsid, req_ac,
  327. params->direction) < 0)
  328. return 0;
  329. return 1;
  330. }
  331. static struct wmm_ac_assoc_data *
  332. wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies,
  333. size_t ies_len)
  334. {
  335. struct ieee802_11_elems elems;
  336. struct wmm_parameter_element *wmm_params;
  337. struct wmm_ac_assoc_data *assoc_data;
  338. int i;
  339. /* Parsing WMM Parameter Element */
  340. if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
  341. wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies");
  342. return NULL;
  343. }
  344. if (!elems.wmm) {
  345. wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE");
  346. return NULL;
  347. }
  348. if (elems.wmm_len != sizeof(*wmm_params)) {
  349. wpa_printf(MSG_DEBUG, "WMM AC: Invalid WMM ie length");
  350. return NULL;
  351. }
  352. wmm_params = (struct wmm_parameter_element *)(elems.wmm);
  353. assoc_data = os_zalloc(sizeof(*assoc_data));
  354. if (!assoc_data)
  355. return NULL;
  356. for (i = 0; i < WMM_AC_NUM; i++)
  357. assoc_data->ac_params[i].acm =
  358. !!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM);
  359. wpa_printf(MSG_DEBUG,
  360. "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u",
  361. assoc_data->ac_params[WMM_AC_BE].acm,
  362. assoc_data->ac_params[WMM_AC_BK].acm,
  363. assoc_data->ac_params[WMM_AC_VI].acm,
  364. assoc_data->ac_params[WMM_AC_VO].acm);
  365. return assoc_data;
  366. }
  367. static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies,
  368. size_t ies_len, const struct wmm_params *wmm_params)
  369. {
  370. struct wmm_ac_assoc_data *assoc_data;
  371. u8 ac;
  372. if (wpa_s->wmm_ac_assoc_info) {
  373. wpa_printf(MSG_ERROR, "WMM AC: Already initialized");
  374. return -1;
  375. }
  376. if (!ies) {
  377. wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
  378. return -1;
  379. }
  380. if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
  381. wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
  382. return -1;
  383. }
  384. os_memset(wpa_s->tspecs, 0, sizeof(wpa_s->tspecs));
  385. wpa_s->wmm_ac_last_dialog_token = 0;
  386. wpa_s->addts_request = NULL;
  387. assoc_data = wmm_ac_process_param_elem(wpa_s, ies, ies_len);
  388. if (!assoc_data)
  389. return -1;
  390. wpa_printf(MSG_DEBUG, "WMM AC: U-APSD queues=0x%x",
  391. wmm_params->uapsd_queues);
  392. for (ac = 0; ac < WMM_AC_NUM; ac++) {
  393. assoc_data->ac_params[ac].uapsd =
  394. !!(wmm_params->uapsd_queues & BIT(ac));
  395. }
  396. wpa_s->wmm_ac_assoc_info = assoc_data;
  397. return 0;
  398. }
  399. static void wmm_ac_del_ts(struct wpa_supplicant *wpa_s, u8 ac, int dir_bitmap)
  400. {
  401. enum ts_dir_idx idx;
  402. for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
  403. if (!(dir_bitmap & BIT(idx)))
  404. continue;
  405. wmm_ac_del_ts_idx(wpa_s, ac, idx);
  406. }
  407. }
  408. static void wmm_ac_deinit(struct wpa_supplicant *wpa_s)
  409. {
  410. int i;
  411. for (i = 0; i < WMM_AC_NUM; i++)
  412. wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
  413. /* delete pending add_ts requset */
  414. wmm_ac_del_req(wpa_s, 1);
  415. os_free(wpa_s->wmm_ac_assoc_info);
  416. wpa_s->wmm_ac_assoc_info = NULL;
  417. }
  418. void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
  419. size_t ies_len, const struct wmm_params *wmm_params)
  420. {
  421. if (wmm_ac_init(wpa_s, ies, ies_len, wmm_params))
  422. return;
  423. wpa_printf(MSG_DEBUG,
  424. "WMM AC: Valid WMM association, WMM AC is enabled");
  425. }
  426. void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s)
  427. {
  428. if (!wpa_s->wmm_ac_assoc_info)
  429. return;
  430. wmm_ac_deinit(wpa_s);
  431. wpa_printf(MSG_DEBUG, "WMM AC: WMM AC is disabled");
  432. }
  433. int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid)
  434. {
  435. struct wmm_tspec_element tspec;
  436. int ac;
  437. enum ts_dir_idx dir;
  438. if (!wpa_s->wmm_ac_assoc_info) {
  439. wpa_printf(MSG_DEBUG,
  440. "WMM AC: Failed to delete TS, WMM AC is disabled");
  441. return -1;
  442. }
  443. ac = wmm_ac_find_tsid(wpa_s, tsid, &dir);
  444. if (ac < 0) {
  445. wpa_printf(MSG_DEBUG, "WMM AC: TS does not exist");
  446. return -1;
  447. }
  448. tspec = *wpa_s->tspecs[ac][dir];
  449. wmm_ac_del_ts_idx(wpa_s, ac, dir);
  450. wmm_ac_send_delts(wpa_s, &tspec, wpa_s->bssid);
  451. return 0;
  452. }
  453. int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
  454. struct wmm_ac_ts_setup_params *params)
  455. {
  456. struct wmm_ac_addts_request *addts_req;
  457. if (!wpa_s->wmm_ac_assoc_info) {
  458. wpa_printf(MSG_DEBUG,
  459. "WMM AC: Cannot add TS - missing assoc data");
  460. return -1;
  461. }
  462. if (wpa_s->addts_request) {
  463. wpa_printf(MSG_DEBUG,
  464. "WMM AC: can't add TS - ADDTS request is already pending");
  465. return -1;
  466. }
  467. /*
  468. * we can setup downlink TS even without driver support.
  469. * however, we need driver support for the other directions.
  470. */
  471. if (params->direction != WMM_AC_DIR_DOWNLINK &&
  472. !wpa_s->wmm_ac_supported) {
  473. wpa_printf(MSG_DEBUG,
  474. "Cannot set uplink/bidi TS without driver support");
  475. return -1;
  476. }
  477. if (!wmm_ac_ts_req_is_valid(wpa_s, params))
  478. return -1;
  479. wpa_printf(MSG_DEBUG, "WMM AC: TS setup request (addr=" MACSTR
  480. " tsid=%u user priority=%u direction=%d)",
  481. MAC2STR(wpa_s->bssid), params->tsid,
  482. params->user_priority, params->direction);
  483. addts_req = wmm_ac_build_addts_req(wpa_s, params, wpa_s->bssid);
  484. if (!addts_req)
  485. return -1;
  486. if (wmm_ac_send_addts_request(wpa_s, addts_req))
  487. goto err;
  488. /* save as pending and set ADDTS resp timeout to 1 second */
  489. wpa_s->addts_request = addts_req;
  490. eloop_register_timeout(1, 0, wmm_ac_addts_req_timeout,
  491. wpa_s, addts_req);
  492. return 0;
  493. err:
  494. os_free(addts_req);
  495. return -1;
  496. }
  497. static void wmm_ac_handle_delts(struct wpa_supplicant *wpa_s, const u8 *sa,
  498. const struct wmm_tspec_element *tspec)
  499. {
  500. int ac;
  501. u8 tsid;
  502. enum ts_dir_idx idx;
  503. tsid = wmm_ac_get_tsid(tspec);
  504. wpa_printf(MSG_DEBUG,
  505. "WMM AC: DELTS frame has been received TSID=%u addr="
  506. MACSTR, tsid, MAC2STR(sa));
  507. ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
  508. if (ac < 0) {
  509. wpa_printf(MSG_DEBUG,
  510. "WMM AC: Ignoring DELTS frame - TSID does not exist");
  511. return;
  512. }
  513. wmm_ac_del_ts_idx(wpa_s, ac, idx);
  514. wpa_printf(MSG_DEBUG,
  515. "TS was deleted successfully (tsid=%u address=" MACSTR ")",
  516. tsid, MAC2STR(sa));
  517. }
  518. static void wmm_ac_handle_addts_resp(struct wpa_supplicant *wpa_s, const u8 *sa,
  519. const u8 resp_dialog_token, const u8 status_code,
  520. const struct wmm_tspec_element *tspec)
  521. {
  522. struct wmm_ac_addts_request *req = wpa_s->addts_request;
  523. u8 ac, tsid, up, dir;
  524. int replace_tspecs;
  525. tsid = wmm_ac_get_tsid(tspec);
  526. dir = wmm_ac_get_direction(tspec);
  527. up = wmm_ac_get_user_priority(tspec);
  528. ac = up_to_ac[up];
  529. /* make sure we have a matching addts request */
  530. if (!req || req->dialog_token != resp_dialog_token) {
  531. wpa_printf(MSG_DEBUG,
  532. "WMM AC: no req with dialog=%u, ignoring frame",
  533. resp_dialog_token);
  534. return;
  535. }
  536. /* make sure the params are the same */
  537. if (os_memcmp(req->address, sa, ETH_ALEN) != 0 ||
  538. tsid != wmm_ac_get_tsid(&req->tspec) ||
  539. up != wmm_ac_get_user_priority(&req->tspec) ||
  540. dir != wmm_ac_get_direction(&req->tspec)) {
  541. wpa_printf(MSG_DEBUG,
  542. "WMM AC: ADDTS params do not match, ignoring frame");
  543. return;
  544. }
  545. /* delete pending request */
  546. wmm_ac_del_req(wpa_s, 0);
  547. wpa_printf(MSG_DEBUG,
  548. "ADDTS response status=%d tsid=%u up=%u direction=%u",
  549. status_code, tsid, up, dir);
  550. if (status_code != WMM_ADDTS_STATUS_ADMISSION_ACCEPTED) {
  551. wpa_printf(MSG_INFO, "WMM AC: ADDTS request was rejected");
  552. goto err_msg;
  553. }
  554. replace_tspecs = wmm_ac_should_replace_ts(wpa_s, tsid, ac, dir);
  555. if (replace_tspecs < 0)
  556. goto err_delts;
  557. wpa_printf(MSG_DEBUG, "ts idx replace bitmap: 0x%x", replace_tspecs);
  558. /* when replacing tspecs - delete first */
  559. wmm_ac_del_ts(wpa_s, ac, replace_tspecs);
  560. /* Creating a new traffic stream */
  561. wpa_printf(MSG_DEBUG,
  562. "WMM AC: adding a new TS with TSID=%u address="MACSTR
  563. " medium time=%u access category=%d dir=%d ",
  564. tsid, MAC2STR(sa),
  565. le_to_host16(tspec->medium_time), ac, dir);
  566. if (wmm_ac_add_ts(wpa_s, sa, tspec))
  567. goto err_delts;
  568. return;
  569. err_delts:
  570. /* ask the ap to delete the tspec */
  571. wmm_ac_send_delts(wpa_s, tspec, sa);
  572. err_msg:
  573. wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED "tsid=%u",
  574. tsid);
  575. }
  576. void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
  577. const u8 *sa, const u8 *data, size_t len)
  578. {
  579. u8 action;
  580. u8 dialog_token;
  581. u8 status_code;
  582. struct ieee802_11_elems elems;
  583. struct wmm_tspec_element *tspec;
  584. if (wpa_s->wmm_ac_assoc_info == NULL) {
  585. wpa_printf(MSG_DEBUG,
  586. "WMM AC: WMM AC is disabled, ignoring action frame");
  587. return;
  588. }
  589. action = data[0];
  590. if (action != WMM_ACTION_CODE_ADDTS_RESP &&
  591. action != WMM_ACTION_CODE_DELTS) {
  592. wpa_printf(MSG_DEBUG,
  593. "WMM AC: Unknown action (%d), ignoring action frame",
  594. action);
  595. return;
  596. }
  597. /* WMM AC action frame */
  598. if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) {
  599. wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR
  600. " is other than ours, ignoring frame", MAC2STR(da));
  601. return;
  602. }
  603. if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
  604. wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR
  605. " different other than our bssid", MAC2STR(da));
  606. return;
  607. }
  608. if (len < 2 + sizeof(struct wmm_tspec_element)) {
  609. wpa_printf(MSG_DEBUG,
  610. "WMM AC: Short ADDTS response ignored (len=%lu)",
  611. (unsigned long) len);
  612. return;
  613. }
  614. data++;
  615. len--;
  616. dialog_token = data[0];
  617. status_code = data[1];
  618. if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) != ParseOK) {
  619. wpa_printf(MSG_DEBUG,
  620. "WMM AC: Could not parse WMM AC action from " MACSTR,
  621. MAC2STR(sa));
  622. return;
  623. }
  624. /* the struct also contains the type and value, so decrease it */
  625. if (elems.wmm_tspec_len != sizeof(struct wmm_tspec_element) - 2) {
  626. wpa_printf(MSG_DEBUG, "WMM AC: missing or wrong length TSPEC");
  627. return;
  628. }
  629. tspec = (struct wmm_tspec_element *)(elems.wmm_tspec - 2);
  630. wpa_printf(MSG_DEBUG, "WMM AC: RX WMM AC Action from " MACSTR,
  631. MAC2STR(sa));
  632. wpa_hexdump(MSG_MSGDUMP, "WMM AC: WMM AC Action content", data, len);
  633. switch (action) {
  634. case WMM_ACTION_CODE_ADDTS_RESP:
  635. wmm_ac_handle_addts_resp(wpa_s, sa, dialog_token, status_code,
  636. tspec);
  637. break;
  638. case WMM_ACTION_CODE_DELTS:
  639. wmm_ac_handle_delts(wpa_s, sa, tspec);
  640. break;
  641. default:
  642. break;
  643. }
  644. }
  645. static const char * get_ac_str(u8 ac)
  646. {
  647. switch (ac) {
  648. case WMM_AC_BE:
  649. return "BE";
  650. case WMM_AC_BK:
  651. return "BK";
  652. case WMM_AC_VI:
  653. return "VI";
  654. case WMM_AC_VO:
  655. return "VO";
  656. default:
  657. return "N/A";
  658. }
  659. }
  660. static const char * get_direction_str(u8 direction)
  661. {
  662. switch (direction) {
  663. case WMM_AC_DIR_DOWNLINK:
  664. return "Downlink";
  665. case WMM_AC_DIR_UPLINK:
  666. return "Uplink";
  667. case WMM_AC_DIR_BIDIRECTIONAL:
  668. return "Bi-directional";
  669. default:
  670. return "N/A";
  671. }
  672. }
  673. int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
  674. {
  675. struct wmm_ac_assoc_data *assoc_info = wpa_s->wmm_ac_assoc_info;
  676. enum ts_dir_idx idx;
  677. int pos = 0;
  678. u8 ac, up;
  679. if (!assoc_info) {
  680. return wpa_scnprintf(buf, buflen - pos,
  681. "Not associated to a WMM AP, WMM AC is Disabled\n");
  682. }
  683. pos += wpa_scnprintf(buf + pos, buflen - pos, "WMM AC is Enabled\n");
  684. for (ac = 0; ac < WMM_AC_NUM; ac++) {
  685. int ts_count = 0;
  686. pos += wpa_scnprintf(buf + pos, buflen - pos,
  687. "%s: acm=%d uapsd=%d\n",
  688. get_ac_str(ac),
  689. assoc_info->ac_params[ac].acm,
  690. assoc_info->ac_params[ac].uapsd);
  691. for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
  692. struct wmm_tspec_element *tspec;
  693. u8 dir, tsid;
  694. const char *dir_str;
  695. tspec = wpa_s->tspecs[ac][idx];
  696. if (!tspec)
  697. continue;
  698. ts_count++;
  699. dir = wmm_ac_get_direction(tspec);
  700. dir_str = get_direction_str(dir);
  701. tsid = wmm_ac_get_tsid(tspec);
  702. up = wmm_ac_get_user_priority(tspec);
  703. pos += wpa_scnprintf(buf + pos, buflen - pos,
  704. "\tTSID=%u UP=%u\n"
  705. "\tAddress = "MACSTR"\n"
  706. "\tWMM AC dir = %s\n"
  707. "\tTotal admitted time = %u\n\n",
  708. tsid, up,
  709. MAC2STR(wpa_s->bssid),
  710. dir_str,
  711. le_to_host16(tspec->medium_time));
  712. }
  713. if (!ts_count) {
  714. pos += wpa_scnprintf(buf + pos, buflen - pos,
  715. "\t(No Traffic Stream)\n\n");
  716. }
  717. }
  718. return pos;
  719. }
  720. static u8 wmm_ac_get_tspecs_count(struct wpa_supplicant *wpa_s)
  721. {
  722. int ac, dir, tspecs_count = 0;
  723. for (ac = 0; ac < WMM_AC_NUM; ac++) {
  724. for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
  725. if (wpa_s->tspecs[ac][dir])
  726. tspecs_count++;
  727. }
  728. }
  729. return tspecs_count;
  730. }
  731. void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s)
  732. {
  733. int ac, dir, tspecs_count;
  734. wpa_printf(MSG_DEBUG, "WMM AC: Save last configured tspecs");
  735. if (!wpa_s->wmm_ac_assoc_info)
  736. return;
  737. tspecs_count = wmm_ac_get_tspecs_count(wpa_s);
  738. if (!tspecs_count) {
  739. wpa_printf(MSG_DEBUG, "WMM AC: No configured TSPECs");
  740. return;
  741. }
  742. wpa_printf(MSG_DEBUG, "WMM AC: Saving tspecs");
  743. wmm_ac_clear_saved_tspecs(wpa_s);
  744. wpa_s->last_tspecs = os_calloc(tspecs_count,
  745. sizeof(*wpa_s->last_tspecs));
  746. if (!wpa_s->last_tspecs) {
  747. wpa_printf(MSG_ERROR, "WMM AC: Failed to save tspecs!");
  748. return;
  749. }
  750. for (ac = 0; ac < WMM_AC_NUM; ac++) {
  751. for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
  752. if (!wpa_s->tspecs[ac][dir])
  753. continue;
  754. wpa_s->last_tspecs[wpa_s->last_tspecs_count++] =
  755. *wpa_s->tspecs[ac][dir];
  756. }
  757. }
  758. wpa_printf(MSG_DEBUG, "WMM AC: Successfully saved %d TSPECs",
  759. wpa_s->last_tspecs_count);
  760. }
  761. void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s)
  762. {
  763. if (wpa_s->last_tspecs) {
  764. wpa_printf(MSG_DEBUG, "WMM AC: Clear saved tspecs");
  765. os_free(wpa_s->last_tspecs);
  766. wpa_s->last_tspecs = NULL;
  767. wpa_s->last_tspecs_count = 0;
  768. }
  769. }
  770. int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s)
  771. {
  772. unsigned int i;
  773. if (!wpa_s->wmm_ac_assoc_info || !wpa_s->last_tspecs_count)
  774. return 0;
  775. wpa_printf(MSG_DEBUG, "WMM AC: Restore %u saved tspecs",
  776. wpa_s->last_tspecs_count);
  777. for (i = 0; i < wpa_s->last_tspecs_count; i++)
  778. wmm_ac_add_ts(wpa_s, wpa_s->bssid, &wpa_s->last_tspecs[i]);
  779. return 0;
  780. }