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