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_memdup(tspec
, sizeof(*_tspec
));
94 if (dir
!= WMM_AC_DIR_DOWNLINK
) {
95 ret
= wpa_drv_add_ts(wpa_s
, tsid
, addr
, up
, admitted_time
);
97 "WMM AC: Add TS: addr=" MACSTR
98 " TSID=%u admitted time=%u, ret=%d",
99 MAC2STR(addr
), tsid
, admitted_time
, ret
);
106 wpa_s
->tspecs
[ac
][idx
] = _tspec
;
108 wpa_printf(MSG_DEBUG
, "Traffic stream was created successfully");
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
);
118 static void wmm_ac_del_ts_idx(struct wpa_supplicant
*wpa_s
, u8 ac
,
121 struct wmm_tspec_element
*tspec
= wpa_s
->tspecs
[ac
][dir
];
127 tsid
= wmm_ac_get_tsid(tspec
);
128 wpa_printf(MSG_DEBUG
, "WMM AC: Del TS ac=%d tsid=%d", ac
, tsid
);
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
);
134 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REMOVED
135 "tsid=%d addr=" MACSTR
, tsid
, MAC2STR(wpa_s
->bssid
));
137 os_free(wpa_s
->tspecs
[ac
][dir
]);
138 wpa_s
->tspecs
[ac
][dir
] = NULL
;
142 static void wmm_ac_del_req(struct wpa_supplicant
*wpa_s
, int failed
)
144 struct wmm_ac_addts_request
*req
= wpa_s
->addts_request
;
150 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REQ_FAILED
151 "tsid=%u", wmm_ac_get_tsid(&req
->tspec
));
153 eloop_cancel_timeout(wmm_ac_addts_req_timeout
, wpa_s
, req
);
154 wpa_s
->addts_request
= NULL
;
159 static void wmm_ac_addts_req_timeout(void *eloop_ctx
, void *timeout_ctx
)
161 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
162 struct wmm_ac_addts_request
*addts_req
= timeout_ctx
;
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
));
169 wmm_ac_del_req(wpa_s
, 1);
173 static int wmm_ac_send_addts_request(struct wpa_supplicant
*wpa_s
,
174 const struct wmm_ac_addts_request
*req
)
179 wpa_printf(MSG_DEBUG
, "Sending ADDTS Request to " MACSTR
,
180 MAC2STR(req
->address
));
182 /* category + action code + dialog token + status + sizeof(tspec) */
183 buf
= wpabuf_alloc(4 + sizeof(req
->tspec
));
185 wpa_printf(MSG_ERROR
, "WMM AC: Allocation error");
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
));
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);
199 wpa_printf(MSG_WARNING
,
200 "WMM AC: Failed to send ADDTS Request");
208 static int wmm_ac_send_delts(struct wpa_supplicant
*wpa_s
,
209 const struct wmm_tspec_element
*tspec
,
215 /* category + action code + dialog token + status + sizeof(tspec) */
216 buf
= wpabuf_alloc(4 + sizeof(*tspec
));
220 wpa_printf(MSG_DEBUG
, "Sending DELTS to " MACSTR
, MAC2STR(address
));
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
));
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);
233 wpa_printf(MSG_WARNING
, "Failed to send DELTS frame");
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
)
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
) {
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
,
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
;
272 addts_req
= os_zalloc(sizeof(*addts_req
));
276 tspec
= &addts_req
->tspec
;
277 os_memcpy(addts_req
->address
, address
, ETH_ALEN
);
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
++;
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
;
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;
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
);
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
);
314 static int param_in_range(const char *name
, long value
,
315 long min_val
, long max_val
)
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
);
328 static int wmm_ac_should_replace_ts(struct wpa_supplicant
*wpa_s
,
329 u8 tsid
, u8 ac
, u8 dir
)
332 int cur_ac
, existing_ts
= 0, replace_ts
= 0;
334 cur_ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &idx
);
337 wpa_printf(MSG_DEBUG
,
338 "WMM AC: TSID %i already exists on different ac (%d)",
343 /* same tsid - this tspec will replace the current one */
344 replace_ts
|= BIT(idx
);
347 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
348 if (wpa_s
->tspecs
[ac
][idx
])
349 existing_ts
|= BIT(idx
);
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
));
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
));
363 case WMM_AC_DIR_BIDIRECTIONAL
:
364 /* replace all existing tspecs */
365 replace_ts
|= existing_ts
;
375 static int wmm_ac_ts_req_is_valid(struct wpa_supplicant
*wpa_s
,
376 const struct wmm_ac_ts_setup_params
*params
)
380 #define PARAM_IN_RANGE(field, min_value, max_value) \
381 param_in_range(#field, params->field, min_value, max_value)
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
,
391 #undef PARAM_IN_RANGE
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",
401 req_ac
= up_to_ac
[params
->user_priority
];
403 /* Requested accesss 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
);
409 if (wmm_ac_should_replace_ts(wpa_s
, params
->tsid
, req_ac
,
410 params
->direction
) < 0)
417 static struct wmm_ac_assoc_data
*
418 wmm_ac_process_param_elem(struct wpa_supplicant
*wpa_s
, const u8
*ies
,
421 struct ieee802_11_elems elems
;
422 struct wmm_parameter_element
*wmm_params
;
423 struct wmm_ac_assoc_data
*assoc_data
;
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");
433 wpa_printf(MSG_DEBUG
, "WMM AC: No WMM IE");
437 if (elems
.wmm_len
!= sizeof(*wmm_params
)) {
438 wpa_printf(MSG_DEBUG
, "WMM AC: Invalid WMM ie length");
442 wmm_params
= (struct wmm_parameter_element
*)(elems
.wmm
);
444 assoc_data
= os_zalloc(sizeof(*assoc_data
));
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
);
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
);
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
)
466 struct wmm_ac_assoc_data
*assoc_data
;
469 if (wpa_s
->wmm_ac_assoc_info
) {
470 wpa_printf(MSG_ERROR
, "WMM AC: Already initialized");
474 if (!ies
|| !(wmm_params
->info_bitmap
& WMM_PARAMS_UAPSD_QUEUES_INFO
)) {
475 /* WMM AC not in use for this connection */
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
;
483 assoc_data
= wmm_ac_process_param_elem(wpa_s
, ies
, ies_len
);
487 wpa_printf(MSG_DEBUG
, "WMM AC: U-APSD queues=0x%x",
488 wmm_params
->uapsd_queues
);
490 for (ac
= 0; ac
< WMM_AC_NUM
; ac
++) {
491 assoc_data
->ac_params
[ac
].uapsd
=
492 !!(wmm_params
->uapsd_queues
& BIT(ac
));
495 wpa_s
->wmm_ac_assoc_info
= assoc_data
;
500 static void wmm_ac_del_ts(struct wpa_supplicant
*wpa_s
, u8 ac
, int dir_bitmap
)
504 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
505 if (!(dir_bitmap
& BIT(idx
)))
508 wmm_ac_del_ts_idx(wpa_s
, ac
, idx
);
513 static void wmm_ac_deinit(struct wpa_supplicant
*wpa_s
)
517 for (i
= 0; i
< WMM_AC_NUM
; i
++)
518 wmm_ac_del_ts(wpa_s
, i
, TS_DIR_IDX_ALL
);
520 /* delete pending add_ts request */
521 wmm_ac_del_req(wpa_s
, 1);
523 os_free(wpa_s
->wmm_ac_assoc_info
);
524 wpa_s
->wmm_ac_assoc_info
= NULL
;
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
)
531 if (wmm_ac_init(wpa_s
, ies
, ies_len
, wmm_params
))
534 wpa_printf(MSG_DEBUG
,
535 "WMM AC: Valid WMM association, WMM AC is enabled");
539 void wmm_ac_notify_disassoc(struct wpa_supplicant
*wpa_s
)
541 if (!wpa_s
->wmm_ac_assoc_info
)
544 wmm_ac_deinit(wpa_s
);
545 wpa_printf(MSG_DEBUG
, "WMM AC: WMM AC is disabled");
549 int wpas_wmm_ac_delts(struct wpa_supplicant
*wpa_s
, u8 tsid
)
551 struct wmm_tspec_element tspec
;
555 if (!wpa_s
->wmm_ac_assoc_info
) {
556 wpa_printf(MSG_DEBUG
,
557 "WMM AC: Failed to delete TS, WMM AC is disabled");
561 ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &dir
);
563 wpa_printf(MSG_DEBUG
, "WMM AC: TS does not exist");
567 tspec
= *wpa_s
->tspecs
[ac
][dir
];
569 wmm_ac_del_ts_idx(wpa_s
, ac
, dir
);
571 wmm_ac_send_delts(wpa_s
, &tspec
, wpa_s
->bssid
);
577 int wpas_wmm_ac_addts(struct wpa_supplicant
*wpa_s
,
578 struct wmm_ac_ts_setup_params
*params
)
580 struct wmm_ac_addts_request
*addts_req
;
582 if (!wpa_s
->wmm_ac_assoc_info
) {
583 wpa_printf(MSG_DEBUG
,
584 "WMM AC: Cannot add TS - missing assoc data");
588 if (wpa_s
->addts_request
) {
589 wpa_printf(MSG_DEBUG
,
590 "WMM AC: can't add TS - ADDTS request is already pending");
595 * we can setup downlink TS even without driver support.
596 * however, we need driver support for the other directions.
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");
605 if (!wmm_ac_ts_req_is_valid(wpa_s
, params
))
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
);
613 addts_req
= wmm_ac_build_addts_req(wpa_s
, params
, wpa_s
->bssid
);
617 if (wmm_ac_send_addts_request(wpa_s
, addts_req
))
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
,
631 static void wmm_ac_handle_delts(struct wpa_supplicant
*wpa_s
, const u8
*sa
,
632 const struct wmm_tspec_element
*tspec
)
638 tsid
= wmm_ac_get_tsid(tspec
);
640 wpa_printf(MSG_DEBUG
,
641 "WMM AC: DELTS frame has been received TSID=%u addr="
642 MACSTR
, tsid
, MAC2STR(sa
));
644 ac
= wmm_ac_find_tsid(wpa_s
, tsid
, &idx
);
646 wpa_printf(MSG_DEBUG
,
647 "WMM AC: Ignoring DELTS frame - TSID does not exist");
651 wmm_ac_del_ts_idx(wpa_s
, ac
, idx
);
653 wpa_printf(MSG_DEBUG
,
654 "TS was deleted successfully (tsid=%u address=" MACSTR
")",
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
)
663 struct wmm_ac_addts_request
*req
= wpa_s
->addts_request
;
664 u8 ac
, tsid
, up
, dir
;
667 tsid
= wmm_ac_get_tsid(tspec
);
668 dir
= wmm_ac_get_direction(tspec
);
669 up
= wmm_ac_get_user_priority(tspec
);
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",
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");
690 /* delete pending request */
691 wmm_ac_del_req(wpa_s
, 0);
693 wpa_printf(MSG_DEBUG
,
694 "ADDTS response status=%d tsid=%u up=%u direction=%u",
695 status_code
, tsid
, up
, dir
);
697 if (status_code
!= WMM_ADDTS_STATUS_ADMISSION_ACCEPTED
) {
698 wpa_printf(MSG_INFO
, "WMM AC: ADDTS request was rejected");
702 replace_tspecs
= wmm_ac_should_replace_ts(wpa_s
, tsid
, ac
, dir
);
703 if (replace_tspecs
< 0)
706 wpa_printf(MSG_DEBUG
, "ts idx replace bitmap: 0x%x", replace_tspecs
);
708 /* when replacing tspecs - delete first */
709 wmm_ac_del_ts(wpa_s
, ac
, replace_tspecs
);
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 ",
716 le_to_host16(tspec
->medium_time
), ac
, dir
);
718 if (wmm_ac_add_ts(wpa_s
, sa
, tspec
))
724 /* ask the ap to delete the tspec */
725 wmm_ac_send_delts(wpa_s
, tspec
, sa
);
727 wpa_msg(wpa_s
, MSG_INFO
, WMM_AC_EVENT_TSPEC_REQ_FAILED
"tsid=%u",
732 void wmm_ac_rx_action(struct wpa_supplicant
*wpa_s
, const u8
*da
,
733 const u8
*sa
, const u8
*data
, size_t len
)
738 struct ieee802_11_elems elems
;
739 struct wmm_tspec_element
*tspec
;
741 if (wpa_s
->wmm_ac_assoc_info
== NULL
) {
742 wpa_printf(MSG_DEBUG
,
743 "WMM AC: WMM AC is disabled, ignoring action frame");
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",
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
));
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
));
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
);
779 dialog_token
= data
[0];
780 status_code
= data
[1];
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
,
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");
795 tspec
= (struct wmm_tspec_element
*)(elems
.wmm_tspec
- 2);
797 wpa_printf(MSG_DEBUG
, "WMM AC: RX WMM AC Action from " MACSTR
,
799 wpa_hexdump(MSG_MSGDUMP
, "WMM AC: WMM AC Action content", data
, len
);
802 case WMM_ACTION_CODE_ADDTS_RESP
:
803 wmm_ac_handle_addts_resp(wpa_s
, sa
, dialog_token
, status_code
,
806 case WMM_ACTION_CODE_DELTS
:
807 wmm_ac_handle_delts(wpa_s
, sa
, tspec
);
815 static const char * get_ac_str(u8 ac
)
832 static const char * get_direction_str(u8 direction
)
835 case WMM_AC_DIR_DOWNLINK
:
837 case WMM_AC_DIR_UPLINK
:
839 case WMM_AC_DIR_BIDIRECTIONAL
:
840 return "Bi-directional";
847 int wpas_wmm_ac_status(struct wpa_supplicant
*wpa_s
, char *buf
, size_t buflen
)
849 struct wmm_ac_assoc_data
*assoc_info
= wpa_s
->wmm_ac_assoc_info
;
855 return wpa_scnprintf(buf
, buflen
- pos
,
856 "Not associated to a WMM AP, WMM AC is Disabled\n");
859 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
, "WMM AC is Enabled\n");
861 for (ac
= 0; ac
< WMM_AC_NUM
; ac
++) {
864 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
865 "%s: acm=%d uapsd=%d\n",
867 assoc_info
->ac_params
[ac
].acm
,
868 assoc_info
->ac_params
[ac
].uapsd
);
870 for (idx
= 0; idx
< TS_DIR_IDX_COUNT
; idx
++) {
871 struct wmm_tspec_element
*tspec
;
875 tspec
= wpa_s
->tspecs
[ac
][idx
];
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
);
886 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
888 "\tAddress = "MACSTR
"\n"
889 "\tWMM AC dir = %s\n"
890 "\tTotal admitted time = %u\n\n",
892 MAC2STR(wpa_s
->bssid
),
894 le_to_host16(tspec
->medium_time
));
898 pos
+= wpa_scnprintf(buf
+ pos
, buflen
- pos
,
899 "\t(No Traffic Stream)\n\n");
907 static u8
wmm_ac_get_tspecs_count(struct wpa_supplicant
*wpa_s
)
909 int ac
, dir
, tspecs_count
= 0;
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
])
922 void wmm_ac_save_tspecs(struct wpa_supplicant
*wpa_s
)
924 int ac
, dir
, tspecs_count
;
926 wpa_printf(MSG_DEBUG
, "WMM AC: Save last configured tspecs");
928 if (!wpa_s
->wmm_ac_assoc_info
)
931 tspecs_count
= wmm_ac_get_tspecs_count(wpa_s
);
933 wpa_printf(MSG_DEBUG
, "WMM AC: No configured TSPECs");
937 wpa_printf(MSG_DEBUG
, "WMM AC: Saving tspecs");
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!");
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
])
952 wpa_s
->last_tspecs
[wpa_s
->last_tspecs_count
++] =
953 *wpa_s
->tspecs
[ac
][dir
];
957 wpa_printf(MSG_DEBUG
, "WMM AC: Successfully saved %d TSPECs",
958 wpa_s
->last_tspecs_count
);
962 void wmm_ac_clear_saved_tspecs(struct wpa_supplicant
*wpa_s
)
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;
973 int wmm_ac_restore_tspecs(struct wpa_supplicant
*wpa_s
)
977 if (!wpa_s
->wmm_ac_assoc_info
|| !wpa_s
->last_tspecs_count
)
980 wpa_printf(MSG_DEBUG
, "WMM AC: Restore %u saved tspecs",
981 wpa_s
->last_tspecs_count
);
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
]);