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.
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
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"
21 static void wmm_ac_addts_req_timeout(void *eloop_ctx
, void *timeout_ctx
);
23 static const enum wmm_ac up_to_ac
[8] = {
35 static inline u8
wmm_ac_get_tsid(const struct wmm_tspec_element
*tspec
)
37 return (tspec
->ts_info
[0] >> 1) & 0x0f;
41 static u8
wmm_ac_get_direction(const struct wmm_tspec_element
*tspec
)
43 return (tspec
->ts_info
[0] >> 5) & 0x03;
47 static u8
wmm_ac_get_user_priority(const struct wmm_tspec_element
*tspec
)
49 return (tspec
->ts_info
[1] >> 3) & 0x07;
53 static u8
wmm_ac_direction_to_idx(u8 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
;
63 wpa_printf(MSG_ERROR
, "Invalid direction: %d", direction
);
64 return WMM_AC_DIR_UPLINK
;
69 static int wmm_ac_add_ts(struct wpa_supplicant
*wpa_s
, const u8
*addr
,
70 const struct wmm_tspec_element
*tspec
)
72 struct wmm_tspec_element
*_tspec
;
74 u16 admitted_time
= le_to_host16(tspec
->medium_time
);
75 u8 up
= wmm_ac_get_user_priority(tspec
);
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
);
81 /* should have been verified before, but double-check here */
82 if (wpa_s
->tspecs
[ac
][idx
]) {
84 "WMM AC: tspec (ac=%d, dir=%d) already exists!",
90 _tspec
= os_malloc(sizeof(*_tspec
));
94 /* store the admitted TSPEC */
95 os_memcpy(_tspec
, tspec
, sizeof(*_tspec
));
97 if (dir
!= WMM_AC_DIR_DOWNLINK
) {
98 ret
= wpa_drv_add_ts(wpa_s
, tsid
, addr
, up
, admitted_time
);
100 "WMM AC: Add TS: addr=" MACSTR
101 " TSID=%u admitted time=%u, ret=%d",
102 MAC2STR(addr
), tsid
, admitted_time
, ret
);
109 wpa_s
->tspecs
[ac
][idx
] = _tspec
;
111 wpa_printf(MSG_DEBUG
, "Traffic stream was created successfully");
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
);
121 static void wmm_ac_del_ts_idx(struct wpa_supplicant
*wpa_s
, u8 ac
,
124 struct wmm_tspec_element
*tspec
= wpa_s
->tspecs
[ac
][dir
];
130 tsid
= wmm_ac_get_tsid(tspec
);
131 wpa_printf(MSG_DEBUG
, "WMM AC: Del TS ac=%d tsid=%d", ac
, tsid
);
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
);
137 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REMOVED
138 "tsid=%d addr=" MACSTR
, tsid
, MAC2STR(wpa_s
->bssid
));
140 os_free(wpa_s
->tspecs
[ac
][dir
]);
141 wpa_s
->tspecs
[ac
][dir
] = NULL
;
145 static void wmm_ac_del_req(struct wpa_supplicant
*wpa_s
, int failed
)
147 struct wmm_ac_addts_request
*req
= wpa_s
->addts_request
;
153 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REQ_FAILED
154 "tsid=%u", wmm_ac_get_tsid(&req
->tspec
));
156 eloop_cancel_timeout(wmm_ac_addts_req_timeout
, wpa_s
, req
);
157 wpa_s
->addts_request
= NULL
;
162 static void wmm_ac_addts_req_timeout(void *eloop_ctx
, void *timeout_ctx
)
164 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
165 struct wmm_ac_addts_request
*addts_req
= timeout_ctx
;
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
));
172 wmm_ac_del_req(wpa_s
, 1);
176 static int wmm_ac_send_addts_request(struct wpa_supplicant
*wpa_s
,
177 const struct wmm_ac_addts_request
*req
)
182 wpa_printf(MSG_DEBUG
, "Sending ADDTS Request to " MACSTR
,
183 MAC2STR(req
->address
));
185 /* category + action code + dialog token + status + sizeof(tspec) */
186 buf
= wpabuf_alloc(4 + sizeof(req
->tspec
));
188 wpa_printf(MSG_ERROR
, "WMM AC: Allocation error");
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
));
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);
202 wpa_printf(MSG_WARNING
,
203 "WMM AC: Failed to send ADDTS Request");
211 static int wmm_ac_send_delts(struct wpa_supplicant
*wpa_s
,
212 const struct wmm_tspec_element
*tspec
,
218 /* category + action code + dialog token + status + sizeof(tspec) */
219 buf
= wpabuf_alloc(4 + sizeof(*tspec
));
223 wpa_printf(MSG_DEBUG
, "Sending DELTS to " MACSTR
, MAC2STR(address
));
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
));
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);
236 wpa_printf(MSG_WARNING
, "Failed to send DELTS frame");
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
)
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
) {
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
,
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
;
275 addts_req
= os_zalloc(sizeof(*addts_req
));
279 tspec
= &addts_req
->tspec
;
280 os_memcpy(addts_req
->address
, address
, ETH_ALEN
);
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
++;
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
;
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;
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
);
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
);
317 static int param_in_range(const char *name
, long value
,
318 long min_val
, long max_val
)
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
);
331 static int wmm_ac_should_replace_ts(struct wpa_supplicant
*wpa_s
,
332 u8 tsid
, u8 ac
, u8 dir
)
335 int cur_ac
, existing_ts
= 0, replace_ts
= 0;
337 cur_ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &idx
);
340 wpa_printf(MSG_DEBUG
,
341 "WMM AC: TSID %i already exists on different ac (%d)",
346 /* same tsid - this tspec will replace the current one */
347 replace_ts
|= BIT(idx
);
350 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
351 if (wpa_s
->tspecs
[ac
][idx
])
352 existing_ts
|= BIT(idx
);
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
));
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
));
366 case WMM_AC_DIR_BIDIRECTIONAL
:
367 /* replace all existing tspecs */
368 replace_ts
|= existing_ts
;
378 static int wmm_ac_ts_req_is_valid(struct wpa_supplicant
*wpa_s
,
379 const struct wmm_ac_ts_setup_params
*params
)
383 #define PARAM_IN_RANGE(field, min_value, max_value) \
384 param_in_range(#field, params->field, min_value, max_value)
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
,
394 #undef PARAM_IN_RANGE
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",
404 req_ac
= up_to_ac
[params
->user_priority
];
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
);
412 if (wmm_ac_should_replace_ts(wpa_s
, params
->tsid
, req_ac
,
413 params
->direction
) < 0)
420 static struct wmm_ac_assoc_data
*
421 wmm_ac_process_param_elem(struct wpa_supplicant
*wpa_s
, const u8
*ies
,
424 struct ieee802_11_elems elems
;
425 struct wmm_parameter_element
*wmm_params
;
426 struct wmm_ac_assoc_data
*assoc_data
;
429 /* Parsing WMM Parameter Element */
430 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 1) != ParseOK
) {
431 wpa_printf(MSG_DEBUG
, "WMM AC: could not parse assoc ies");
436 wpa_printf(MSG_DEBUG
, "WMM AC: No WMM IE");
440 if (elems
.wmm_len
!= sizeof(*wmm_params
)) {
441 wpa_printf(MSG_WARNING
, "WMM AC: Invalid WMM ie length");
445 wmm_params
= (struct wmm_parameter_element
*)(elems
.wmm
);
447 assoc_data
= os_zalloc(sizeof(*assoc_data
));
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
);
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
);
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
)
469 struct wmm_ac_assoc_data
*assoc_data
;
472 if (wpa_s
->wmm_ac_assoc_info
) {
473 wpa_printf(MSG_ERROR
, "WMM AC: Already initialized");
478 wpa_printf(MSG_ERROR
, "WMM AC: Missing IEs");
482 if (!(wmm_params
->info_bitmap
& WMM_PARAMS_UAPSD_QUEUES_INFO
)) {
483 wpa_printf(MSG_DEBUG
, "WMM AC: Missing U-APSD configuration");
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
;
491 assoc_data
= wmm_ac_process_param_elem(wpa_s
, ies
, ies_len
);
495 wpa_printf(MSG_DEBUG
, "WMM AC: U-APSD queues=0x%x",
496 wmm_params
->uapsd_queues
);
498 for (ac
= 0; ac
< WMM_AC_NUM
; ac
++) {
499 assoc_data
->ac_params
[ac
].uapsd
=
500 !!(wmm_params
->uapsd_queues
& BIT(ac
));
503 wpa_s
->wmm_ac_assoc_info
= assoc_data
;
508 static void wmm_ac_del_ts(struct wpa_supplicant
*wpa_s
, u8 ac
, int dir_bitmap
)
512 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
513 if (!(dir_bitmap
& BIT(idx
)))
516 wmm_ac_del_ts_idx(wpa_s
, ac
, idx
);
521 static void wmm_ac_deinit(struct wpa_supplicant
*wpa_s
)
525 for (i
= 0; i
< WMM_AC_NUM
; i
++)
526 wmm_ac_del_ts(wpa_s
, i
, TS_DIR_IDX_ALL
);
528 /* delete pending add_ts requset */
529 wmm_ac_del_req(wpa_s
, 1);
531 os_free(wpa_s
->wmm_ac_assoc_info
);
532 wpa_s
->wmm_ac_assoc_info
= NULL
;
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
)
539 if (wmm_ac_init(wpa_s
, ies
, ies_len
, wmm_params
))
542 wpa_printf(MSG_DEBUG
,
543 "WMM AC: Valid WMM association, WMM AC is enabled");
547 void wmm_ac_notify_disassoc(struct wpa_supplicant
*wpa_s
)
549 if (!wpa_s
->wmm_ac_assoc_info
)
552 wmm_ac_deinit(wpa_s
);
553 wpa_printf(MSG_DEBUG
, "WMM AC: WMM AC is disabled");
557 int wpas_wmm_ac_delts(struct wpa_supplicant
*wpa_s
, u8 tsid
)
559 struct wmm_tspec_element tspec
;
563 if (!wpa_s
->wmm_ac_assoc_info
) {
564 wpa_printf(MSG_DEBUG
,
565 "WMM AC: Failed to delete TS, WMM AC is disabled");
569 ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &dir
);
571 wpa_printf(MSG_DEBUG
, "WMM AC: TS does not exist");
575 tspec
= *wpa_s
->tspecs
[ac
][dir
];
577 wmm_ac_del_ts_idx(wpa_s
, ac
, dir
);
579 wmm_ac_send_delts(wpa_s
, &tspec
, wpa_s
->bssid
);
585 int wpas_wmm_ac_addts(struct wpa_supplicant
*wpa_s
,
586 struct wmm_ac_ts_setup_params
*params
)
588 struct wmm_ac_addts_request
*addts_req
;
590 if (!wpa_s
->wmm_ac_assoc_info
) {
591 wpa_printf(MSG_DEBUG
,
592 "WMM AC: Cannot add TS - missing assoc data");
596 if (wpa_s
->addts_request
) {
597 wpa_printf(MSG_DEBUG
,
598 "WMM AC: can't add TS - ADDTS request is already pending");
603 * we can setup downlink TS even without driver support.
604 * however, we need driver support for the other directions.
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");
613 if (!wmm_ac_ts_req_is_valid(wpa_s
, params
))
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
);
621 addts_req
= wmm_ac_build_addts_req(wpa_s
, params
, wpa_s
->bssid
);
625 if (wmm_ac_send_addts_request(wpa_s
, addts_req
))
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
,
639 static void wmm_ac_handle_delts(struct wpa_supplicant
*wpa_s
, const u8
*sa
,
640 const struct wmm_tspec_element
*tspec
)
646 tsid
= wmm_ac_get_tsid(tspec
);
648 wpa_printf(MSG_DEBUG
,
649 "WMM AC: DELTS frame has been received TSID=%u addr="
650 MACSTR
, tsid
, MAC2STR(sa
));
652 ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &idx
);
654 wpa_printf(MSG_DEBUG
,
655 "WMM AC: Ignoring DELTS frame - TSID does not exist");
659 wmm_ac_del_ts_idx(wpa_s
, ac
, idx
);
662 "TS was deleted successfully (tsid=%u address=" MACSTR
")",
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
)
671 struct wmm_ac_addts_request
*req
= wpa_s
->addts_request
;
672 u8 ac
, tsid
, up
, dir
;
675 tsid
= wmm_ac_get_tsid(tspec
);
676 dir
= wmm_ac_get_direction(tspec
);
677 up
= wmm_ac_get_user_priority(tspec
);
680 /* make sure we have a matching addts request */
681 if (!req
|| req
->dialog_token
!= resp_dialog_token
) {
682 wpa_printf(MSG_ERROR
,
683 "WMM AC: no req with dialog=%u, ignoring frame",
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_ERROR
,
694 "WMM AC: ADDTS params do not match, ignoring frame");
698 /* delete pending request */
699 wmm_ac_del_req(wpa_s
, 0);
702 "ADDTS response status=%d tsid=%u up=%u direction=%u",
703 status_code
, tsid
, up
, dir
);
705 if (status_code
!= WMM_ADDTS_STATUS_ADMISSION_ACCEPTED
) {
706 wpa_printf(MSG_INFO
, "WMM AC: ADDTS request was rejected");
710 replace_tspecs
= wmm_ac_should_replace_ts(wpa_s
, tsid
, ac
, dir
);
711 if (replace_tspecs
< 0)
714 wpa_printf(MSG_DEBUG
, "ts idx replace bitmap: 0x%x", replace_tspecs
);
716 /* when replacing tspecs - delete first */
717 wmm_ac_del_ts(wpa_s
, ac
, replace_tspecs
);
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 ",
724 le_to_host16(tspec
->medium_time
), ac
, dir
);
726 if (wmm_ac_add_ts(wpa_s
, sa
, tspec
))
732 /* ask the ap to delete the tspec */
733 wmm_ac_send_delts(wpa_s
, tspec
, sa
);
735 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REQ_FAILED
"tsid=%u",
740 void wmm_ac_rx_action(struct wpa_supplicant
*wpa_s
, const u8
*da
,
741 const u8
*sa
, const u8
*data
, size_t len
)
746 struct ieee802_11_elems elems
;
747 struct wmm_tspec_element
*tspec
;
749 if (wpa_s
->wmm_ac_assoc_info
== NULL
) {
750 wpa_printf(MSG_WARNING
,
751 "WMM AC: WMM AC is disabled, ignoring action frame");
757 if (action
!= WMM_ACTION_CODE_ADDTS_RESP
&&
758 action
!= WMM_ACTION_CODE_DELTS
) {
759 wpa_printf(MSG_WARNING
,
760 "WMM AC: Unknown action (%d), ignoring action frame",
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
));
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
));
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
);
787 dialog_token
= data
[0];
788 status_code
= data
[1];
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
,
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");
803 tspec
= (struct wmm_tspec_element
*)(elems
.wmm_tspec
- 2);
805 wpa_printf(MSG_DEBUG
, "WMM AC: RX WMM AC Action from " MACSTR
,
807 wpa_hexdump(MSG_MSGDUMP
, "WMM AC: WMM AC Action content", data
, len
);
810 case WMM_ACTION_CODE_ADDTS_RESP
:
811 wmm_ac_handle_addts_resp(wpa_s
, sa
, dialog_token
, status_code
,
814 case WMM_ACTION_CODE_DELTS
:
815 wmm_ac_handle_delts(wpa_s
, sa
, tspec
);
823 static const char * get_ac_str(u8 ac
)
840 static const char * get_direction_str(u8 direction
)
843 case WMM_AC_DIR_DOWNLINK
:
845 case WMM_AC_DIR_UPLINK
:
847 case WMM_AC_DIR_BIDIRECTIONAL
:
848 return "Bi-directional";
855 int wpas_wmm_ac_status(struct wpa_supplicant
*wpa_s
, char *buf
, size_t buflen
)
857 struct wmm_ac_assoc_data
*assoc_info
= wpa_s
->wmm_ac_assoc_info
;
863 return wpa_scnprintf(buf
, buflen
- pos
,
864 "Not associated to a WMM AP, WMM AC is Disabled\n");
867 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
, "WMM AC is Enabled\n");
869 for (ac
= 0; ac
< WMM_AC_NUM
; ac
++) {
872 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
873 "%s: acm=%d uapsd=%d\n",
875 assoc_info
->ac_params
[ac
].acm
,
876 assoc_info
->ac_params
[ac
].uapsd
);
878 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
879 struct wmm_tspec_element
*tspec
;
883 tspec
= wpa_s
->tspecs
[ac
][idx
];
889 dir
= wmm_ac_get_direction(tspec
);
890 dir_str
= get_direction_str(dir
);
891 tsid
= wmm_ac_get_tsid(tspec
);
893 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
895 "\tAddress = "MACSTR
"\n"
896 "\tWMM AC dir = %s\n"
897 "\tTotal admitted time = %u\n\n",
899 MAC2STR(wpa_s
->bssid
),
901 le_to_host16(tspec
->medium_time
));
905 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
906 "\t(No Traffic Stream)\n\n");