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