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