1c1d255d3SCy Schubert /* 2c1d255d3SCy Schubert * wpa_supplicant - Robust AV procedures 3c1d255d3SCy Schubert * Copyright (c) 2020, The Linux Foundation 4c1d255d3SCy Schubert * 5c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license. 6c1d255d3SCy Schubert * See README for more details. 7c1d255d3SCy Schubert */ 8c1d255d3SCy Schubert 9c1d255d3SCy Schubert #include "utils/includes.h" 10c1d255d3SCy Schubert #include "utils/common.h" 11*4b72b91aSCy Schubert #include "utils/eloop.h" 12c1d255d3SCy Schubert #include "common/wpa_ctrl.h" 13c1d255d3SCy Schubert #include "common/ieee802_11_common.h" 14c1d255d3SCy Schubert #include "wpa_supplicant_i.h" 15c1d255d3SCy Schubert #include "driver_i.h" 16c1d255d3SCy Schubert #include "bss.h" 17c1d255d3SCy Schubert 18c1d255d3SCy Schubert 19*4b72b91aSCy Schubert #define SCS_RESP_TIMEOUT 1 20*4b72b91aSCy Schubert #define DSCP_REQ_TIMEOUT 5 21*4b72b91aSCy Schubert 22*4b72b91aSCy Schubert 23c1d255d3SCy Schubert void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av, 24c1d255d3SCy Schubert struct wpabuf *buf) 25c1d255d3SCy Schubert { 26c1d255d3SCy Schubert u8 *len, *len1; 27c1d255d3SCy Schubert 28c1d255d3SCy Schubert /* MSCS descriptor element */ 29c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION); 30c1d255d3SCy Schubert len = wpabuf_put(buf, 1); 31c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR); 32c1d255d3SCy Schubert wpabuf_put_u8(buf, robust_av->request_type); 33c1d255d3SCy Schubert wpabuf_put_u8(buf, robust_av->up_bitmap); 34c1d255d3SCy Schubert wpabuf_put_u8(buf, robust_av->up_limit); 35c1d255d3SCy Schubert wpabuf_put_le32(buf, robust_av->stream_timeout); 36c1d255d3SCy Schubert 37c1d255d3SCy Schubert if (robust_av->request_type != SCS_REQ_REMOVE) { 38c1d255d3SCy Schubert /* TCLAS mask element */ 39c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION); 40c1d255d3SCy Schubert len1 = wpabuf_put(buf, 1); 41c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK); 42c1d255d3SCy Schubert 43c1d255d3SCy Schubert /* Frame classifier */ 44c1d255d3SCy Schubert wpabuf_put_data(buf, robust_av->frame_classifier, 45c1d255d3SCy Schubert robust_av->frame_classifier_len); 46c1d255d3SCy Schubert *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1; 47c1d255d3SCy Schubert } 48c1d255d3SCy Schubert 49c1d255d3SCy Schubert *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 50c1d255d3SCy Schubert } 51c1d255d3SCy Schubert 52c1d255d3SCy Schubert 53*4b72b91aSCy Schubert static int wpas_populate_type4_classifier(struct type4_params *type4_param, 54*4b72b91aSCy Schubert struct wpabuf *buf) 55*4b72b91aSCy Schubert { 56*4b72b91aSCy Schubert /* classifier parameters */ 57*4b72b91aSCy Schubert wpabuf_put_u8(buf, type4_param->classifier_mask); 58*4b72b91aSCy Schubert if (type4_param->ip_version == IPV4) { 59*4b72b91aSCy Schubert wpabuf_put_u8(buf, IPV4); /* IP version */ 60*4b72b91aSCy Schubert wpabuf_put_data(buf, &type4_param->ip_params.v4.src_ip.s_addr, 61*4b72b91aSCy Schubert 4); 62*4b72b91aSCy Schubert wpabuf_put_data(buf, &type4_param->ip_params.v4.dst_ip.s_addr, 63*4b72b91aSCy Schubert 4); 64*4b72b91aSCy Schubert wpabuf_put_be16(buf, type4_param->ip_params.v4.src_port); 65*4b72b91aSCy Schubert wpabuf_put_be16(buf, type4_param->ip_params.v4.dst_port); 66*4b72b91aSCy Schubert wpabuf_put_u8(buf, type4_param->ip_params.v4.dscp); 67*4b72b91aSCy Schubert wpabuf_put_u8(buf, type4_param->ip_params.v4.protocol); 68*4b72b91aSCy Schubert wpabuf_put_u8(buf, 0); /* Reserved octet */ 69*4b72b91aSCy Schubert } else { 70*4b72b91aSCy Schubert wpabuf_put_u8(buf, IPV6); 71*4b72b91aSCy Schubert wpabuf_put_data(buf, &type4_param->ip_params.v6.src_ip.s6_addr, 72*4b72b91aSCy Schubert 16); 73*4b72b91aSCy Schubert wpabuf_put_data(buf, &type4_param->ip_params.v6.dst_ip.s6_addr, 74*4b72b91aSCy Schubert 16); 75*4b72b91aSCy Schubert wpabuf_put_be16(buf, type4_param->ip_params.v6.src_port); 76*4b72b91aSCy Schubert wpabuf_put_be16(buf, type4_param->ip_params.v6.dst_port); 77*4b72b91aSCy Schubert wpabuf_put_u8(buf, type4_param->ip_params.v6.dscp); 78*4b72b91aSCy Schubert wpabuf_put_u8(buf, type4_param->ip_params.v6.next_header); 79*4b72b91aSCy Schubert wpabuf_put_data(buf, type4_param->ip_params.v6.flow_label, 3); 80*4b72b91aSCy Schubert } 81*4b72b91aSCy Schubert 82*4b72b91aSCy Schubert return 0; 83*4b72b91aSCy Schubert } 84*4b72b91aSCy Schubert 85*4b72b91aSCy Schubert 86*4b72b91aSCy Schubert static int wpas_populate_type10_classifier(struct type10_params *type10_param, 87*4b72b91aSCy Schubert struct wpabuf *buf) 88*4b72b91aSCy Schubert { 89*4b72b91aSCy Schubert /* classifier parameters */ 90*4b72b91aSCy Schubert wpabuf_put_u8(buf, type10_param->prot_instance); 91*4b72b91aSCy Schubert wpabuf_put_u8(buf, type10_param->prot_number); 92*4b72b91aSCy Schubert wpabuf_put_data(buf, type10_param->filter_value, 93*4b72b91aSCy Schubert type10_param->filter_len); 94*4b72b91aSCy Schubert wpabuf_put_data(buf, type10_param->filter_mask, 95*4b72b91aSCy Schubert type10_param->filter_len); 96*4b72b91aSCy Schubert return 0; 97*4b72b91aSCy Schubert } 98*4b72b91aSCy Schubert 99*4b72b91aSCy Schubert 100*4b72b91aSCy Schubert static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem, 101*4b72b91aSCy Schubert struct wpabuf *buf) 102*4b72b91aSCy Schubert { 103*4b72b91aSCy Schubert u8 *len, *len1; 104*4b72b91aSCy Schubert struct tclas_element *tclas_elem; 105*4b72b91aSCy Schubert unsigned int i; 106*4b72b91aSCy Schubert 107*4b72b91aSCy Schubert /* SCS Descriptor element */ 108*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR); 109*4b72b91aSCy Schubert len = wpabuf_put(buf, 1); 110*4b72b91aSCy Schubert wpabuf_put_u8(buf, desc_elem->scs_id); 111*4b72b91aSCy Schubert wpabuf_put_u8(buf, desc_elem->request_type); 112*4b72b91aSCy Schubert if (desc_elem->request_type == SCS_REQ_REMOVE) 113*4b72b91aSCy Schubert goto end; 114*4b72b91aSCy Schubert 115*4b72b91aSCy Schubert if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) { 116*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY); 117*4b72b91aSCy Schubert wpabuf_put_u8(buf, 1); 118*4b72b91aSCy Schubert wpabuf_put_u8(buf, desc_elem->intra_access_priority); 119*4b72b91aSCy Schubert } 120*4b72b91aSCy Schubert 121*4b72b91aSCy Schubert tclas_elem = desc_elem->tclas_elems; 122*4b72b91aSCy Schubert 123*4b72b91aSCy Schubert if (!tclas_elem) 124*4b72b91aSCy Schubert return -1; 125*4b72b91aSCy Schubert 126*4b72b91aSCy Schubert for (i = 0; i < desc_elem->num_tclas_elem; i++, tclas_elem++) { 127*4b72b91aSCy Schubert int ret; 128*4b72b91aSCy Schubert 129*4b72b91aSCy Schubert /* TCLAS element */ 130*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_EID_TCLAS); 131*4b72b91aSCy Schubert len1 = wpabuf_put(buf, 1); 132*4b72b91aSCy Schubert wpabuf_put_u8(buf, 255); /* User Priority: not compared */ 133*4b72b91aSCy Schubert /* Frame Classifier */ 134*4b72b91aSCy Schubert wpabuf_put_u8(buf, tclas_elem->classifier_type); 135*4b72b91aSCy Schubert /* Frame classifier parameters */ 136*4b72b91aSCy Schubert switch (tclas_elem->classifier_type) { 137*4b72b91aSCy Schubert case 4: 138*4b72b91aSCy Schubert ret = wpas_populate_type4_classifier( 139*4b72b91aSCy Schubert &tclas_elem->frame_classifier.type4_param, 140*4b72b91aSCy Schubert buf); 141*4b72b91aSCy Schubert break; 142*4b72b91aSCy Schubert case 10: 143*4b72b91aSCy Schubert ret = wpas_populate_type10_classifier( 144*4b72b91aSCy Schubert &tclas_elem->frame_classifier.type10_param, 145*4b72b91aSCy Schubert buf); 146*4b72b91aSCy Schubert break; 147*4b72b91aSCy Schubert default: 148*4b72b91aSCy Schubert return -1; 149*4b72b91aSCy Schubert } 150*4b72b91aSCy Schubert 151*4b72b91aSCy Schubert if (ret == -1) { 152*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 153*4b72b91aSCy Schubert "Failed to populate frame classifier"); 154*4b72b91aSCy Schubert return -1; 155*4b72b91aSCy Schubert } 156*4b72b91aSCy Schubert 157*4b72b91aSCy Schubert *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1; 158*4b72b91aSCy Schubert } 159*4b72b91aSCy Schubert 160*4b72b91aSCy Schubert if (desc_elem->num_tclas_elem > 1) { 161*4b72b91aSCy Schubert /* TCLAS Processing element */ 162*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_EID_TCLAS_PROCESSING); 163*4b72b91aSCy Schubert wpabuf_put_u8(buf, 1); 164*4b72b91aSCy Schubert wpabuf_put_u8(buf, desc_elem->tclas_processing); 165*4b72b91aSCy Schubert } 166*4b72b91aSCy Schubert 167*4b72b91aSCy Schubert end: 168*4b72b91aSCy Schubert *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 169*4b72b91aSCy Schubert return 0; 170*4b72b91aSCy Schubert } 171*4b72b91aSCy Schubert 172*4b72b91aSCy Schubert 173c1d255d3SCy Schubert int wpas_send_mscs_req(struct wpa_supplicant *wpa_s) 174c1d255d3SCy Schubert { 175c1d255d3SCy Schubert struct wpabuf *buf; 176c1d255d3SCy Schubert size_t buf_len; 177c1d255d3SCy Schubert int ret; 178c1d255d3SCy Schubert 179c1d255d3SCy Schubert if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) 180c1d255d3SCy Schubert return 0; 181c1d255d3SCy Schubert 182c1d255d3SCy Schubert if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS)) { 183c1d255d3SCy Schubert wpa_dbg(wpa_s, MSG_INFO, 184c1d255d3SCy Schubert "AP does not support MSCS - could not send MSCS Req"); 185c1d255d3SCy Schubert return -1; 186c1d255d3SCy Schubert } 187c1d255d3SCy Schubert 188c1d255d3SCy Schubert if (!wpa_s->mscs_setup_done && 189c1d255d3SCy Schubert wpa_s->robust_av.request_type != SCS_REQ_ADD) { 190c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, 191c1d255d3SCy Schubert "MSCS: Failed to send MSCS Request: request type invalid"); 192c1d255d3SCy Schubert return -1; 193c1d255d3SCy Schubert } 194c1d255d3SCy Schubert 195c1d255d3SCy Schubert buf_len = 3 + /* Action frame header */ 196c1d255d3SCy Schubert 3 + /* MSCS descriptor IE header */ 197c1d255d3SCy Schubert 1 + /* Request type */ 198c1d255d3SCy Schubert 2 + /* User priority control */ 199c1d255d3SCy Schubert 4 + /* Stream timeout */ 200c1d255d3SCy Schubert 3 + /* TCLAS Mask IE header */ 201c1d255d3SCy Schubert wpa_s->robust_av.frame_classifier_len; 202c1d255d3SCy Schubert 203c1d255d3SCy Schubert buf = wpabuf_alloc(buf_len); 204c1d255d3SCy Schubert if (!buf) { 205c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Failed to allocate MSCS req"); 206c1d255d3SCy Schubert return -1; 207c1d255d3SCy Schubert } 208c1d255d3SCy Schubert 209c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING); 210c1d255d3SCy Schubert wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ); 211c1d255d3SCy Schubert wpa_s->robust_av.dialog_token++; 212c1d255d3SCy Schubert wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token); 213c1d255d3SCy Schubert 214c1d255d3SCy Schubert /* MSCS descriptor element */ 215c1d255d3SCy Schubert wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf); 216c1d255d3SCy Schubert 217c1d255d3SCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", buf); 218c1d255d3SCy Schubert ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 219c1d255d3SCy Schubert wpa_s->own_addr, wpa_s->bssid, 220c1d255d3SCy Schubert wpabuf_head(buf), wpabuf_len(buf), 0); 221c1d255d3SCy Schubert if (ret < 0) 222c1d255d3SCy Schubert wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request"); 223c1d255d3SCy Schubert 224c1d255d3SCy Schubert wpabuf_free(buf); 225c1d255d3SCy Schubert return ret; 226c1d255d3SCy Schubert } 227c1d255d3SCy Schubert 228c1d255d3SCy Schubert 229*4b72b91aSCy Schubert static size_t tclas_elem_len(const struct tclas_element *elem) 230*4b72b91aSCy Schubert { 231*4b72b91aSCy Schubert size_t buf_len = 0; 232*4b72b91aSCy Schubert 233*4b72b91aSCy Schubert buf_len += 2 + /* TCLAS element header */ 234*4b72b91aSCy Schubert 1 + /* User Priority */ 235*4b72b91aSCy Schubert 1 ; /* Classifier Type */ 236*4b72b91aSCy Schubert 237*4b72b91aSCy Schubert if (elem->classifier_type == 4) { 238*4b72b91aSCy Schubert enum ip_version ip_ver; 239*4b72b91aSCy Schubert 240*4b72b91aSCy Schubert buf_len += 1 + /* Classifier mask */ 241*4b72b91aSCy Schubert 1 + /* IP version */ 242*4b72b91aSCy Schubert 1 + /* user priority */ 243*4b72b91aSCy Schubert 2 + /* src_port */ 244*4b72b91aSCy Schubert 2 + /* dst_port */ 245*4b72b91aSCy Schubert 1 ; /* dscp */ 246*4b72b91aSCy Schubert ip_ver = elem->frame_classifier.type4_param.ip_version; 247*4b72b91aSCy Schubert if (ip_ver == IPV4) { 248*4b72b91aSCy Schubert buf_len += 4 + /* src_ip */ 249*4b72b91aSCy Schubert 4 + /* dst_ip */ 250*4b72b91aSCy Schubert 1 + /* protocol */ 251*4b72b91aSCy Schubert 1 ; /* Reserved */ 252*4b72b91aSCy Schubert } else if (ip_ver == IPV6) { 253*4b72b91aSCy Schubert buf_len += 16 + /* src_ip */ 254*4b72b91aSCy Schubert 16 + /* dst_ip */ 255*4b72b91aSCy Schubert 1 + /* next_header */ 256*4b72b91aSCy Schubert 3 ; /* flow_label */ 257*4b72b91aSCy Schubert } else { 258*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "%s: Incorrect IP version %d", 259*4b72b91aSCy Schubert __func__, ip_ver); 260*4b72b91aSCy Schubert return 0; 261*4b72b91aSCy Schubert } 262*4b72b91aSCy Schubert } else if (elem->classifier_type == 10) { 263*4b72b91aSCy Schubert buf_len += 1 + /* protocol instance */ 264*4b72b91aSCy Schubert 1 + /* protocol number */ 265*4b72b91aSCy Schubert 2 * elem->frame_classifier.type10_param.filter_len; 266*4b72b91aSCy Schubert } else { 267*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "%s: Incorrect classifier type %u", 268*4b72b91aSCy Schubert __func__, elem->classifier_type); 269*4b72b91aSCy Schubert return 0; 270*4b72b91aSCy Schubert } 271*4b72b91aSCy Schubert 272*4b72b91aSCy Schubert return buf_len; 273*4b72b91aSCy Schubert } 274*4b72b91aSCy Schubert 275*4b72b91aSCy Schubert 276*4b72b91aSCy Schubert static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem, 277*4b72b91aSCy Schubert unsigned int num_scs_desc) 278*4b72b91aSCy Schubert { 279*4b72b91aSCy Schubert struct wpabuf *buf; 280*4b72b91aSCy Schubert size_t buf_len = 0; 281*4b72b91aSCy Schubert unsigned int i, j; 282*4b72b91aSCy Schubert 283*4b72b91aSCy Schubert buf_len = 3; /* Action frame header */ 284*4b72b91aSCy Schubert 285*4b72b91aSCy Schubert for (i = 0; i < num_scs_desc; i++, desc_elem++) { 286*4b72b91aSCy Schubert struct tclas_element *tclas_elem; 287*4b72b91aSCy Schubert 288*4b72b91aSCy Schubert buf_len += 2 + /* SCS descriptor IE header */ 289*4b72b91aSCy Schubert 1 + /* SCSID */ 290*4b72b91aSCy Schubert 1 ; /* Request type */ 291*4b72b91aSCy Schubert 292*4b72b91aSCy Schubert if (desc_elem->request_type == SCS_REQ_REMOVE) 293*4b72b91aSCy Schubert continue; 294*4b72b91aSCy Schubert 295*4b72b91aSCy Schubert if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) 296*4b72b91aSCy Schubert buf_len += 3; 297*4b72b91aSCy Schubert 298*4b72b91aSCy Schubert tclas_elem = desc_elem->tclas_elems; 299*4b72b91aSCy Schubert if (!tclas_elem) { 300*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "%s: TCLAS element null", 301*4b72b91aSCy Schubert __func__); 302*4b72b91aSCy Schubert return NULL; 303*4b72b91aSCy Schubert } 304*4b72b91aSCy Schubert 305*4b72b91aSCy Schubert for (j = 0; j < desc_elem->num_tclas_elem; j++, tclas_elem++) { 306*4b72b91aSCy Schubert size_t elen; 307*4b72b91aSCy Schubert 308*4b72b91aSCy Schubert elen = tclas_elem_len(tclas_elem); 309*4b72b91aSCy Schubert if (elen == 0) 310*4b72b91aSCy Schubert return NULL; 311*4b72b91aSCy Schubert buf_len += elen; 312*4b72b91aSCy Schubert } 313*4b72b91aSCy Schubert 314*4b72b91aSCy Schubert if (desc_elem->num_tclas_elem > 1) { 315*4b72b91aSCy Schubert buf_len += 1 + /* TCLAS Processing eid */ 316*4b72b91aSCy Schubert 1 + /* length */ 317*4b72b91aSCy Schubert 1 ; /* processing */ 318*4b72b91aSCy Schubert } 319*4b72b91aSCy Schubert } 320*4b72b91aSCy Schubert 321*4b72b91aSCy Schubert buf = wpabuf_alloc(buf_len); 322*4b72b91aSCy Schubert if (!buf) { 323*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "Failed to allocate SCS req"); 324*4b72b91aSCy Schubert return NULL; 325*4b72b91aSCy Schubert } 326*4b72b91aSCy Schubert 327*4b72b91aSCy Schubert return buf; 328*4b72b91aSCy Schubert } 329*4b72b91aSCy Schubert 330*4b72b91aSCy Schubert 331*4b72b91aSCy Schubert static void scs_request_timer(void *eloop_ctx, void *timeout_ctx) 332*4b72b91aSCy Schubert { 333*4b72b91aSCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 334*4b72b91aSCy Schubert struct active_scs_elem *scs_desc, *prev; 335*4b72b91aSCy Schubert 336*4b72b91aSCy Schubert if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) 337*4b72b91aSCy Schubert return; 338*4b72b91aSCy Schubert 339*4b72b91aSCy Schubert /* Once timeout is over, remove all SCS descriptors with no response */ 340*4b72b91aSCy Schubert dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids, 341*4b72b91aSCy Schubert struct active_scs_elem, list) { 342*4b72b91aSCy Schubert u8 bssid[ETH_ALEN] = { 0 }; 343*4b72b91aSCy Schubert const u8 *src; 344*4b72b91aSCy Schubert 345*4b72b91aSCy Schubert if (scs_desc->status == SCS_DESC_SUCCESS) 346*4b72b91aSCy Schubert continue; 347*4b72b91aSCy Schubert 348*4b72b91aSCy Schubert if (wpa_s->current_bss) 349*4b72b91aSCy Schubert src = wpa_s->current_bss->bssid; 350*4b72b91aSCy Schubert else 351*4b72b91aSCy Schubert src = bssid; 352*4b72b91aSCy Schubert 353*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR 354*4b72b91aSCy Schubert " SCSID=%u status_code=timedout", MAC2STR(src), 355*4b72b91aSCy Schubert scs_desc->scs_id); 356*4b72b91aSCy Schubert 357*4b72b91aSCy Schubert dl_list_del(&scs_desc->list); 358*4b72b91aSCy Schubert wpa_printf(MSG_INFO, "%s: SCSID %d removed after timeout", 359*4b72b91aSCy Schubert __func__, scs_desc->scs_id); 360*4b72b91aSCy Schubert os_free(scs_desc); 361*4b72b91aSCy Schubert } 362*4b72b91aSCy Schubert 363*4b72b91aSCy Schubert eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); 364*4b72b91aSCy Schubert wpa_s->ongoing_scs_req = false; 365*4b72b91aSCy Schubert } 366*4b72b91aSCy Schubert 367*4b72b91aSCy Schubert 368*4b72b91aSCy Schubert int wpas_send_scs_req(struct wpa_supplicant *wpa_s) 369*4b72b91aSCy Schubert { 370*4b72b91aSCy Schubert struct wpabuf *buf = NULL; 371*4b72b91aSCy Schubert struct scs_desc_elem *desc_elem = NULL; 372*4b72b91aSCy Schubert int ret = -1; 373*4b72b91aSCy Schubert unsigned int i; 374*4b72b91aSCy Schubert 375*4b72b91aSCy Schubert if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) 376*4b72b91aSCy Schubert return -1; 377*4b72b91aSCy Schubert 378*4b72b91aSCy Schubert if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_SCS)) { 379*4b72b91aSCy Schubert wpa_dbg(wpa_s, MSG_INFO, 380*4b72b91aSCy Schubert "AP does not support SCS - could not send SCS Request"); 381*4b72b91aSCy Schubert return -1; 382*4b72b91aSCy Schubert } 383*4b72b91aSCy Schubert 384*4b72b91aSCy Schubert desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems; 385*4b72b91aSCy Schubert if (!desc_elem) 386*4b72b91aSCy Schubert return -1; 387*4b72b91aSCy Schubert 388*4b72b91aSCy Schubert buf = allocate_scs_buf(desc_elem, 389*4b72b91aSCy Schubert wpa_s->scs_robust_av_req.num_scs_desc); 390*4b72b91aSCy Schubert if (!buf) 391*4b72b91aSCy Schubert return -1; 392*4b72b91aSCy Schubert 393*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING); 394*4b72b91aSCy Schubert wpabuf_put_u8(buf, ROBUST_AV_SCS_REQ); 395*4b72b91aSCy Schubert wpa_s->scs_dialog_token++; 396*4b72b91aSCy Schubert if (wpa_s->scs_dialog_token == 0) 397*4b72b91aSCy Schubert wpa_s->scs_dialog_token++; 398*4b72b91aSCy Schubert wpabuf_put_u8(buf, wpa_s->scs_dialog_token); 399*4b72b91aSCy Schubert 400*4b72b91aSCy Schubert for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc; 401*4b72b91aSCy Schubert i++, desc_elem++) { 402*4b72b91aSCy Schubert /* SCS Descriptor element */ 403*4b72b91aSCy Schubert if (wpas_populate_scs_descriptor_ie(desc_elem, buf) < 0) 404*4b72b91aSCy Schubert goto end; 405*4b72b91aSCy Schubert } 406*4b72b91aSCy Schubert 407*4b72b91aSCy Schubert wpa_hexdump_buf(MSG_DEBUG, "SCS Request", buf); 408*4b72b91aSCy Schubert ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 409*4b72b91aSCy Schubert wpa_s->own_addr, wpa_s->bssid, 410*4b72b91aSCy Schubert wpabuf_head(buf), wpabuf_len(buf), 0); 411*4b72b91aSCy Schubert if (ret < 0) { 412*4b72b91aSCy Schubert wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request"); 413*4b72b91aSCy Schubert wpa_s->scs_dialog_token--; 414*4b72b91aSCy Schubert goto end; 415*4b72b91aSCy Schubert } 416*4b72b91aSCy Schubert 417*4b72b91aSCy Schubert desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems; 418*4b72b91aSCy Schubert for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc; 419*4b72b91aSCy Schubert i++, desc_elem++) { 420*4b72b91aSCy Schubert struct active_scs_elem *active_scs_elem; 421*4b72b91aSCy Schubert 422*4b72b91aSCy Schubert if (desc_elem->request_type != SCS_REQ_ADD) 423*4b72b91aSCy Schubert continue; 424*4b72b91aSCy Schubert 425*4b72b91aSCy Schubert active_scs_elem = os_malloc(sizeof(struct active_scs_elem)); 426*4b72b91aSCy Schubert if (!active_scs_elem) 427*4b72b91aSCy Schubert break; 428*4b72b91aSCy Schubert active_scs_elem->scs_id = desc_elem->scs_id; 429*4b72b91aSCy Schubert active_scs_elem->status = SCS_DESC_SENT; 430*4b72b91aSCy Schubert dl_list_add(&wpa_s->active_scs_ids, &active_scs_elem->list); 431*4b72b91aSCy Schubert } 432*4b72b91aSCy Schubert 433*4b72b91aSCy Schubert /* 434*4b72b91aSCy Schubert * Register a timeout after which this request will be removed from 435*4b72b91aSCy Schubert * the cache. 436*4b72b91aSCy Schubert */ 437*4b72b91aSCy Schubert eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s, 438*4b72b91aSCy Schubert NULL); 439*4b72b91aSCy Schubert wpa_s->ongoing_scs_req = true; 440*4b72b91aSCy Schubert 441*4b72b91aSCy Schubert end: 442*4b72b91aSCy Schubert wpabuf_free(buf); 443*4b72b91aSCy Schubert free_up_scs_desc(&wpa_s->scs_robust_av_req); 444*4b72b91aSCy Schubert 445*4b72b91aSCy Schubert return ret; 446*4b72b91aSCy Schubert } 447*4b72b91aSCy Schubert 448*4b72b91aSCy Schubert 449*4b72b91aSCy Schubert void free_up_tclas_elem(struct scs_desc_elem *elem) 450*4b72b91aSCy Schubert { 451*4b72b91aSCy Schubert struct tclas_element *tclas_elems = elem->tclas_elems; 452*4b72b91aSCy Schubert unsigned int num_tclas_elem = elem->num_tclas_elem; 453*4b72b91aSCy Schubert struct tclas_element *tclas_data; 454*4b72b91aSCy Schubert unsigned int j; 455*4b72b91aSCy Schubert 456*4b72b91aSCy Schubert elem->tclas_elems = NULL; 457*4b72b91aSCy Schubert elem->num_tclas_elem = 0; 458*4b72b91aSCy Schubert 459*4b72b91aSCy Schubert if (!tclas_elems) 460*4b72b91aSCy Schubert return; 461*4b72b91aSCy Schubert 462*4b72b91aSCy Schubert tclas_data = tclas_elems; 463*4b72b91aSCy Schubert for (j = 0; j < num_tclas_elem; j++, tclas_data++) { 464*4b72b91aSCy Schubert if (tclas_data->classifier_type != 10) 465*4b72b91aSCy Schubert continue; 466*4b72b91aSCy Schubert 467*4b72b91aSCy Schubert os_free(tclas_data->frame_classifier.type10_param.filter_value); 468*4b72b91aSCy Schubert os_free(tclas_data->frame_classifier.type10_param.filter_mask); 469*4b72b91aSCy Schubert } 470*4b72b91aSCy Schubert 471*4b72b91aSCy Schubert os_free(tclas_elems); 472*4b72b91aSCy Schubert } 473*4b72b91aSCy Schubert 474*4b72b91aSCy Schubert 475*4b72b91aSCy Schubert void free_up_scs_desc(struct scs_robust_av_data *data) 476*4b72b91aSCy Schubert { 477*4b72b91aSCy Schubert struct scs_desc_elem *desc_elems = data->scs_desc_elems; 478*4b72b91aSCy Schubert unsigned int num_scs_desc = data->num_scs_desc; 479*4b72b91aSCy Schubert struct scs_desc_elem *desc_data; 480*4b72b91aSCy Schubert unsigned int i; 481*4b72b91aSCy Schubert 482*4b72b91aSCy Schubert data->scs_desc_elems = NULL; 483*4b72b91aSCy Schubert data->num_scs_desc = 0; 484*4b72b91aSCy Schubert 485*4b72b91aSCy Schubert if (!desc_elems) 486*4b72b91aSCy Schubert return; 487*4b72b91aSCy Schubert 488*4b72b91aSCy Schubert desc_data = desc_elems; 489*4b72b91aSCy Schubert for (i = 0; i < num_scs_desc; i++, desc_data++) { 490*4b72b91aSCy Schubert if (desc_data->request_type == SCS_REQ_REMOVE || 491*4b72b91aSCy Schubert !desc_data->tclas_elems) 492*4b72b91aSCy Schubert continue; 493*4b72b91aSCy Schubert 494*4b72b91aSCy Schubert free_up_tclas_elem(desc_data); 495*4b72b91aSCy Schubert } 496*4b72b91aSCy Schubert os_free(desc_elems); 497*4b72b91aSCy Schubert } 498*4b72b91aSCy Schubert 499*4b72b91aSCy Schubert 500c1d255d3SCy Schubert void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s, 501c1d255d3SCy Schubert const u8 *src, const u8 *buf, size_t len) 502c1d255d3SCy Schubert { 503c1d255d3SCy Schubert u8 dialog_token; 504c1d255d3SCy Schubert u16 status_code; 505c1d255d3SCy Schubert 506c1d255d3SCy Schubert if (len < 3) 507c1d255d3SCy Schubert return; 508c1d255d3SCy Schubert 509c1d255d3SCy Schubert dialog_token = *buf++; 510c1d255d3SCy Schubert if (dialog_token != wpa_s->robust_av.dialog_token) { 511c1d255d3SCy Schubert wpa_printf(MSG_INFO, 512c1d255d3SCy Schubert "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u", 513c1d255d3SCy Schubert dialog_token, wpa_s->robust_av.dialog_token); 514c1d255d3SCy Schubert return; 515c1d255d3SCy Schubert } 516c1d255d3SCy Schubert 517c1d255d3SCy Schubert status_code = WPA_GET_LE16(buf); 518c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR 519c1d255d3SCy Schubert " status_code=%u", MAC2STR(src), status_code); 520c1d255d3SCy Schubert wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS; 521c1d255d3SCy Schubert } 522c1d255d3SCy Schubert 523c1d255d3SCy Schubert 524c1d255d3SCy Schubert void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, 525c1d255d3SCy Schubert const u8 *ies, size_t ies_len) 526c1d255d3SCy Schubert { 527c1d255d3SCy Schubert const u8 *mscs_desc_ie, *mscs_status; 528c1d255d3SCy Schubert u16 status; 529c1d255d3SCy Schubert 530c1d255d3SCy Schubert /* Process optional MSCS Status subelement when MSCS IE is in 531c1d255d3SCy Schubert * (Re)Association Response frame */ 532c1d255d3SCy Schubert if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config) 533c1d255d3SCy Schubert return; 534c1d255d3SCy Schubert 535c1d255d3SCy Schubert mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR); 536c1d255d3SCy Schubert if (!mscs_desc_ie || mscs_desc_ie[1] <= 8) 537c1d255d3SCy Schubert return; 538c1d255d3SCy Schubert 539c1d255d3SCy Schubert /* Subelements start after (ie_id(1) + ie_len(1) + ext_id(1) + 540c1d255d3SCy Schubert * request type(1) + upc(2) + stream timeout(4) =) 10. 541c1d255d3SCy Schubert */ 542c1d255d3SCy Schubert mscs_status = get_ie(&mscs_desc_ie[10], mscs_desc_ie[1] - 8, 543c1d255d3SCy Schubert MCSC_SUBELEM_STATUS); 544c1d255d3SCy Schubert if (!mscs_status || mscs_status[1] < 2) 545c1d255d3SCy Schubert return; 546c1d255d3SCy Schubert 547c1d255d3SCy Schubert status = WPA_GET_LE16(mscs_status + 2); 548c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR 549c1d255d3SCy Schubert " status_code=%u", MAC2STR(bssid), status); 550c1d255d3SCy Schubert wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS; 551c1d255d3SCy Schubert } 552*4b72b91aSCy Schubert 553*4b72b91aSCy Schubert 554*4b72b91aSCy Schubert static void wpas_wait_for_dscp_req_timer(void *eloop_ctx, void *timeout_ctx) 555*4b72b91aSCy Schubert { 556*4b72b91aSCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx; 557*4b72b91aSCy Schubert 558*4b72b91aSCy Schubert /* Once timeout is over, reset wait flag and allow sending DSCP query */ 559*4b72b91aSCy Schubert wpa_printf(MSG_DEBUG, 560*4b72b91aSCy Schubert "QM: Wait time over for sending DSCP request - allow DSCP query"); 561*4b72b91aSCy Schubert wpa_s->wait_for_dscp_req = 0; 562*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait end"); 563*4b72b91aSCy Schubert } 564*4b72b91aSCy Schubert 565*4b72b91aSCy Schubert 566*4b72b91aSCy Schubert void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s, 567*4b72b91aSCy Schubert const u8 *ies, size_t ies_len) 568*4b72b91aSCy Schubert { 569*4b72b91aSCy Schubert const u8 *wfa_capa; 570*4b72b91aSCy Schubert 571*4b72b91aSCy Schubert wpa_s->connection_dscp = 0; 572*4b72b91aSCy Schubert if (wpa_s->wait_for_dscp_req) 573*4b72b91aSCy Schubert eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL); 574*4b72b91aSCy Schubert 575*4b72b91aSCy Schubert if (!ies || ies_len == 0 || !wpa_s->enable_dscp_policy_capa) 576*4b72b91aSCy Schubert return; 577*4b72b91aSCy Schubert 578*4b72b91aSCy Schubert wfa_capa = get_vendor_ie(ies, ies_len, WFA_CAPA_IE_VENDOR_TYPE); 579*4b72b91aSCy Schubert if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 || 580*4b72b91aSCy Schubert !(wfa_capa[7] & WFA_CAPA_QM_DSCP_POLICY)) 581*4b72b91aSCy Schubert return; /* AP does not enable QM DSCP Policy */ 582*4b72b91aSCy Schubert 583*4b72b91aSCy Schubert wpa_s->connection_dscp = 1; 584*4b72b91aSCy Schubert wpa_s->wait_for_dscp_req = !!(wfa_capa[7] & 585*4b72b91aSCy Schubert WFA_CAPA_QM_UNSOLIC_DSCP); 586*4b72b91aSCy Schubert if (!wpa_s->wait_for_dscp_req) 587*4b72b91aSCy Schubert return; 588*4b72b91aSCy Schubert 589*4b72b91aSCy Schubert /* Register a timeout after which dscp query can be sent to AP. */ 590*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait start"); 591*4b72b91aSCy Schubert eloop_register_timeout(DSCP_REQ_TIMEOUT, 0, 592*4b72b91aSCy Schubert wpas_wait_for_dscp_req_timer, wpa_s, NULL); 593*4b72b91aSCy Schubert } 594*4b72b91aSCy Schubert 595*4b72b91aSCy Schubert 596*4b72b91aSCy Schubert void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s, 597*4b72b91aSCy Schubert const u8 *src, const u8 *buf, 598*4b72b91aSCy Schubert size_t len) 599*4b72b91aSCy Schubert { 600*4b72b91aSCy Schubert u8 dialog_token; 601*4b72b91aSCy Schubert unsigned int i, count; 602*4b72b91aSCy Schubert struct active_scs_elem *scs_desc, *prev; 603*4b72b91aSCy Schubert 604*4b72b91aSCy Schubert if (len < 2) 605*4b72b91aSCy Schubert return; 606*4b72b91aSCy Schubert if (!wpa_s->ongoing_scs_req) { 607*4b72b91aSCy Schubert wpa_printf(MSG_INFO, 608*4b72b91aSCy Schubert "SCS: Drop received response due to no ongoing request"); 609*4b72b91aSCy Schubert return; 610*4b72b91aSCy Schubert } 611*4b72b91aSCy Schubert 612*4b72b91aSCy Schubert dialog_token = *buf++; 613*4b72b91aSCy Schubert len--; 614*4b72b91aSCy Schubert if (dialog_token != wpa_s->scs_dialog_token) { 615*4b72b91aSCy Schubert wpa_printf(MSG_INFO, 616*4b72b91aSCy Schubert "SCS: Drop received frame due to dialog token mismatch: received:%u expected:%u", 617*4b72b91aSCy Schubert dialog_token, wpa_s->scs_dialog_token); 618*4b72b91aSCy Schubert return; 619*4b72b91aSCy Schubert } 620*4b72b91aSCy Schubert 621*4b72b91aSCy Schubert /* This Count field does not exist in the IEEE Std 802.11-2020 622*4b72b91aSCy Schubert * definition of the SCS Response frame. However, it was accepted to 623*4b72b91aSCy Schubert * be added into REVme per REVme/D0.0 CC35 CID 49 (edits in document 624*4b72b91aSCy Schubert * 11-21-0688-07). */ 625*4b72b91aSCy Schubert count = *buf++; 626*4b72b91aSCy Schubert len--; 627*4b72b91aSCy Schubert if (count == 0 || count * 3 > len) { 628*4b72b91aSCy Schubert wpa_printf(MSG_INFO, 629*4b72b91aSCy Schubert "SCS: Drop received frame due to invalid count: %u (remaining %zu octets)", 630*4b72b91aSCy Schubert count, len); 631*4b72b91aSCy Schubert return; 632*4b72b91aSCy Schubert } 633*4b72b91aSCy Schubert 634*4b72b91aSCy Schubert for (i = 0; i < count; i++) { 635*4b72b91aSCy Schubert u8 id; 636*4b72b91aSCy Schubert u16 status; 637*4b72b91aSCy Schubert bool scs_desc_found = false; 638*4b72b91aSCy Schubert 639*4b72b91aSCy Schubert id = *buf++; 640*4b72b91aSCy Schubert status = WPA_GET_LE16(buf); 641*4b72b91aSCy Schubert buf += 2; 642*4b72b91aSCy Schubert len -= 3; 643*4b72b91aSCy Schubert 644*4b72b91aSCy Schubert dl_list_for_each(scs_desc, &wpa_s->active_scs_ids, 645*4b72b91aSCy Schubert struct active_scs_elem, list) { 646*4b72b91aSCy Schubert if (id == scs_desc->scs_id) { 647*4b72b91aSCy Schubert scs_desc_found = true; 648*4b72b91aSCy Schubert break; 649*4b72b91aSCy Schubert } 650*4b72b91aSCy Schubert } 651*4b72b91aSCy Schubert 652*4b72b91aSCy Schubert if (!scs_desc_found) { 653*4b72b91aSCy Schubert wpa_printf(MSG_INFO, "SCS: SCS ID invalid %u", id); 654*4b72b91aSCy Schubert continue; 655*4b72b91aSCy Schubert } 656*4b72b91aSCy Schubert 657*4b72b91aSCy Schubert if (status != WLAN_STATUS_SUCCESS) { 658*4b72b91aSCy Schubert dl_list_del(&scs_desc->list); 659*4b72b91aSCy Schubert os_free(scs_desc); 660*4b72b91aSCy Schubert } else if (status == WLAN_STATUS_SUCCESS) { 661*4b72b91aSCy Schubert scs_desc->status = SCS_DESC_SUCCESS; 662*4b72b91aSCy Schubert } 663*4b72b91aSCy Schubert 664*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR 665*4b72b91aSCy Schubert " SCSID=%u status_code=%u", MAC2STR(src), id, status); 666*4b72b91aSCy Schubert } 667*4b72b91aSCy Schubert 668*4b72b91aSCy Schubert eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); 669*4b72b91aSCy Schubert wpa_s->ongoing_scs_req = false; 670*4b72b91aSCy Schubert 671*4b72b91aSCy Schubert dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids, 672*4b72b91aSCy Schubert struct active_scs_elem, list) { 673*4b72b91aSCy Schubert if (scs_desc->status != SCS_DESC_SUCCESS) { 674*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, 675*4b72b91aSCy Schubert WPA_EVENT_SCS_RESULT "bssid=" MACSTR 676*4b72b91aSCy Schubert " SCSID=%u status_code=response_not_received", 677*4b72b91aSCy Schubert MAC2STR(src), scs_desc->scs_id); 678*4b72b91aSCy Schubert dl_list_del(&scs_desc->list); 679*4b72b91aSCy Schubert os_free(scs_desc); 680*4b72b91aSCy Schubert } 681*4b72b91aSCy Schubert } 682*4b72b91aSCy Schubert } 683*4b72b91aSCy Schubert 684*4b72b91aSCy Schubert 685*4b72b91aSCy Schubert static void wpas_clear_active_scs_ids(struct wpa_supplicant *wpa_s) 686*4b72b91aSCy Schubert { 687*4b72b91aSCy Schubert struct active_scs_elem *scs_elem; 688*4b72b91aSCy Schubert 689*4b72b91aSCy Schubert while ((scs_elem = dl_list_first(&wpa_s->active_scs_ids, 690*4b72b91aSCy Schubert struct active_scs_elem, list))) { 691*4b72b91aSCy Schubert dl_list_del(&scs_elem->list); 692*4b72b91aSCy Schubert os_free(scs_elem); 693*4b72b91aSCy Schubert } 694*4b72b91aSCy Schubert } 695*4b72b91aSCy Schubert 696*4b72b91aSCy Schubert 697*4b72b91aSCy Schubert void wpas_scs_deinit(struct wpa_supplicant *wpa_s) 698*4b72b91aSCy Schubert { 699*4b72b91aSCy Schubert free_up_scs_desc(&wpa_s->scs_robust_av_req); 700*4b72b91aSCy Schubert wpa_s->scs_dialog_token = 0; 701*4b72b91aSCy Schubert wpas_clear_active_scs_ids(wpa_s); 702*4b72b91aSCy Schubert eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); 703*4b72b91aSCy Schubert wpa_s->ongoing_scs_req = false; 704*4b72b91aSCy Schubert } 705*4b72b91aSCy Schubert 706*4b72b91aSCy Schubert 707*4b72b91aSCy Schubert static int write_ipv4_info(char *pos, int total_len, 708*4b72b91aSCy Schubert const struct ipv4_params *v4) 709*4b72b91aSCy Schubert { 710*4b72b91aSCy Schubert int res, rem_len; 711*4b72b91aSCy Schubert char addr[INET_ADDRSTRLEN]; 712*4b72b91aSCy Schubert 713*4b72b91aSCy Schubert rem_len = total_len; 714*4b72b91aSCy Schubert 715*4b72b91aSCy Schubert if (v4->param_mask & BIT(1)) { 716*4b72b91aSCy Schubert if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) { 717*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 718*4b72b91aSCy Schubert "QM: Failed to set IPv4 source address"); 719*4b72b91aSCy Schubert return -1; 720*4b72b91aSCy Schubert } 721*4b72b91aSCy Schubert 722*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " src_ip=%s", addr); 723*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 724*4b72b91aSCy Schubert return -1; 725*4b72b91aSCy Schubert 726*4b72b91aSCy Schubert pos += res; 727*4b72b91aSCy Schubert rem_len -= res; 728*4b72b91aSCy Schubert } 729*4b72b91aSCy Schubert 730*4b72b91aSCy Schubert if (v4->param_mask & BIT(2)) { 731*4b72b91aSCy Schubert if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) { 732*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 733*4b72b91aSCy Schubert "QM: Failed to set IPv4 destination address"); 734*4b72b91aSCy Schubert return -1; 735*4b72b91aSCy Schubert } 736*4b72b91aSCy Schubert 737*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " dst_ip=%s", addr); 738*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 739*4b72b91aSCy Schubert return -1; 740*4b72b91aSCy Schubert 741*4b72b91aSCy Schubert pos += res; 742*4b72b91aSCy Schubert rem_len -= res; 743*4b72b91aSCy Schubert } 744*4b72b91aSCy Schubert 745*4b72b91aSCy Schubert if (v4->param_mask & BIT(3)) { 746*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port); 747*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 748*4b72b91aSCy Schubert return -1; 749*4b72b91aSCy Schubert 750*4b72b91aSCy Schubert pos += res; 751*4b72b91aSCy Schubert rem_len -= res; 752*4b72b91aSCy Schubert } 753*4b72b91aSCy Schubert 754*4b72b91aSCy Schubert if (v4->param_mask & BIT(4)) { 755*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port); 756*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 757*4b72b91aSCy Schubert return -1; 758*4b72b91aSCy Schubert 759*4b72b91aSCy Schubert pos += res; 760*4b72b91aSCy Schubert rem_len -= res; 761*4b72b91aSCy Schubert } 762*4b72b91aSCy Schubert 763*4b72b91aSCy Schubert if (v4->param_mask & BIT(6)) { 764*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol); 765*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 766*4b72b91aSCy Schubert return -1; 767*4b72b91aSCy Schubert 768*4b72b91aSCy Schubert pos += res; 769*4b72b91aSCy Schubert rem_len -= res; 770*4b72b91aSCy Schubert } 771*4b72b91aSCy Schubert 772*4b72b91aSCy Schubert return total_len - rem_len; 773*4b72b91aSCy Schubert } 774*4b72b91aSCy Schubert 775*4b72b91aSCy Schubert 776*4b72b91aSCy Schubert static int write_ipv6_info(char *pos, int total_len, 777*4b72b91aSCy Schubert const struct ipv6_params *v6) 778*4b72b91aSCy Schubert { 779*4b72b91aSCy Schubert int res, rem_len; 780*4b72b91aSCy Schubert char addr[INET6_ADDRSTRLEN]; 781*4b72b91aSCy Schubert 782*4b72b91aSCy Schubert rem_len = total_len; 783*4b72b91aSCy Schubert 784*4b72b91aSCy Schubert if (v6->param_mask & BIT(1)) { 785*4b72b91aSCy Schubert if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) { 786*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 787*4b72b91aSCy Schubert "QM: Failed to set IPv6 source addr"); 788*4b72b91aSCy Schubert return -1; 789*4b72b91aSCy Schubert } 790*4b72b91aSCy Schubert 791*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " src_ip=%s", addr); 792*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 793*4b72b91aSCy Schubert return -1; 794*4b72b91aSCy Schubert 795*4b72b91aSCy Schubert pos += res; 796*4b72b91aSCy Schubert rem_len -= res; 797*4b72b91aSCy Schubert } 798*4b72b91aSCy Schubert 799*4b72b91aSCy Schubert if (v6->param_mask & BIT(2)) { 800*4b72b91aSCy Schubert if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) { 801*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 802*4b72b91aSCy Schubert "QM: Failed to set IPv6 destination addr"); 803*4b72b91aSCy Schubert return -1; 804*4b72b91aSCy Schubert } 805*4b72b91aSCy Schubert 806*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " dst_ip=%s", addr); 807*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 808*4b72b91aSCy Schubert return -1; 809*4b72b91aSCy Schubert 810*4b72b91aSCy Schubert pos += res; 811*4b72b91aSCy Schubert rem_len -= res; 812*4b72b91aSCy Schubert } 813*4b72b91aSCy Schubert 814*4b72b91aSCy Schubert if (v6->param_mask & BIT(3)) { 815*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port); 816*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 817*4b72b91aSCy Schubert return -1; 818*4b72b91aSCy Schubert 819*4b72b91aSCy Schubert pos += res; 820*4b72b91aSCy Schubert rem_len -= res; 821*4b72b91aSCy Schubert } 822*4b72b91aSCy Schubert 823*4b72b91aSCy Schubert if (v6->param_mask & BIT(4)) { 824*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port); 825*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 826*4b72b91aSCy Schubert return -1; 827*4b72b91aSCy Schubert 828*4b72b91aSCy Schubert pos += res; 829*4b72b91aSCy Schubert rem_len -= res; 830*4b72b91aSCy Schubert } 831*4b72b91aSCy Schubert 832*4b72b91aSCy Schubert if (v6->param_mask & BIT(6)) { 833*4b72b91aSCy Schubert res = os_snprintf(pos, rem_len, " protocol=%d", 834*4b72b91aSCy Schubert v6->next_header); 835*4b72b91aSCy Schubert if (os_snprintf_error(rem_len, res)) 836*4b72b91aSCy Schubert return -1; 837*4b72b91aSCy Schubert 838*4b72b91aSCy Schubert pos += res; 839*4b72b91aSCy Schubert rem_len -= res; 840*4b72b91aSCy Schubert } 841*4b72b91aSCy Schubert 842*4b72b91aSCy Schubert return total_len - rem_len; 843*4b72b91aSCy Schubert } 844*4b72b91aSCy Schubert 845*4b72b91aSCy Schubert 846*4b72b91aSCy Schubert struct dscp_policy_data { 847*4b72b91aSCy Schubert u8 policy_id; 848*4b72b91aSCy Schubert u8 req_type; 849*4b72b91aSCy Schubert u8 dscp; 850*4b72b91aSCy Schubert bool dscp_info; 851*4b72b91aSCy Schubert const u8 *frame_classifier; 852*4b72b91aSCy Schubert u8 frame_classifier_len; 853*4b72b91aSCy Schubert struct type4_params type4_param; 854*4b72b91aSCy Schubert const u8 *domain_name; 855*4b72b91aSCy Schubert u8 domain_name_len; 856*4b72b91aSCy Schubert u16 start_port; 857*4b72b91aSCy Schubert u16 end_port; 858*4b72b91aSCy Schubert bool port_range_info; 859*4b72b91aSCy Schubert }; 860*4b72b91aSCy Schubert 861*4b72b91aSCy Schubert 862*4b72b91aSCy Schubert static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) 863*4b72b91aSCy Schubert { 864*4b72b91aSCy Schubert u8 classifier_mask; 865*4b72b91aSCy Schubert const u8 *frame_classifier = policy->frame_classifier; 866*4b72b91aSCy Schubert struct type4_params *type4_param = &policy->type4_param; 867*4b72b91aSCy Schubert 868*4b72b91aSCy Schubert if (policy->frame_classifier_len < 18) { 869*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 870*4b72b91aSCy Schubert "QM: Received IPv4 frame classifier with insufficient length %d", 871*4b72b91aSCy Schubert policy->frame_classifier_len); 872*4b72b91aSCy Schubert return -1; 873*4b72b91aSCy Schubert } 874*4b72b91aSCy Schubert 875*4b72b91aSCy Schubert classifier_mask = frame_classifier[1]; 876*4b72b91aSCy Schubert 877*4b72b91aSCy Schubert /* Classifier Mask - bit 1 = Source IP Address */ 878*4b72b91aSCy Schubert if (classifier_mask & BIT(1)) { 879*4b72b91aSCy Schubert type4_param->ip_params.v4.param_mask |= BIT(1); 880*4b72b91aSCy Schubert os_memcpy(&type4_param->ip_params.v4.src_ip, 881*4b72b91aSCy Schubert &frame_classifier[3], 4); 882*4b72b91aSCy Schubert } 883*4b72b91aSCy Schubert 884*4b72b91aSCy Schubert /* Classifier Mask - bit 2 = Destination IP Address */ 885*4b72b91aSCy Schubert if (classifier_mask & BIT(2)) { 886*4b72b91aSCy Schubert if (policy->domain_name) { 887*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 888*4b72b91aSCy Schubert "QM: IPv4: Both domain name and destination IP address not expected"); 889*4b72b91aSCy Schubert return -1; 890*4b72b91aSCy Schubert } 891*4b72b91aSCy Schubert 892*4b72b91aSCy Schubert type4_param->ip_params.v4.param_mask |= BIT(2); 893*4b72b91aSCy Schubert os_memcpy(&type4_param->ip_params.v4.dst_ip, 894*4b72b91aSCy Schubert &frame_classifier[7], 4); 895*4b72b91aSCy Schubert } 896*4b72b91aSCy Schubert 897*4b72b91aSCy Schubert /* Classifier Mask - bit 3 = Source Port */ 898*4b72b91aSCy Schubert if (classifier_mask & BIT(3)) { 899*4b72b91aSCy Schubert type4_param->ip_params.v4.param_mask |= BIT(3); 900*4b72b91aSCy Schubert type4_param->ip_params.v4.src_port = 901*4b72b91aSCy Schubert WPA_GET_BE16(&frame_classifier[11]); 902*4b72b91aSCy Schubert } 903*4b72b91aSCy Schubert 904*4b72b91aSCy Schubert /* Classifier Mask - bit 4 = Destination Port */ 905*4b72b91aSCy Schubert if (classifier_mask & BIT(4)) { 906*4b72b91aSCy Schubert if (policy->port_range_info) { 907*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 908*4b72b91aSCy Schubert "QM: IPv4: Both port range and destination port not expected"); 909*4b72b91aSCy Schubert return -1; 910*4b72b91aSCy Schubert } 911*4b72b91aSCy Schubert 912*4b72b91aSCy Schubert type4_param->ip_params.v4.param_mask |= BIT(4); 913*4b72b91aSCy Schubert type4_param->ip_params.v4.dst_port = 914*4b72b91aSCy Schubert WPA_GET_BE16(&frame_classifier[13]); 915*4b72b91aSCy Schubert } 916*4b72b91aSCy Schubert 917*4b72b91aSCy Schubert /* Classifier Mask - bit 5 = DSCP (ignored) */ 918*4b72b91aSCy Schubert 919*4b72b91aSCy Schubert /* Classifier Mask - bit 6 = Protocol */ 920*4b72b91aSCy Schubert if (classifier_mask & BIT(6)) { 921*4b72b91aSCy Schubert type4_param->ip_params.v4.param_mask |= BIT(6); 922*4b72b91aSCy Schubert type4_param->ip_params.v4.protocol = frame_classifier[16]; 923*4b72b91aSCy Schubert } 924*4b72b91aSCy Schubert 925*4b72b91aSCy Schubert return 0; 926*4b72b91aSCy Schubert } 927*4b72b91aSCy Schubert 928*4b72b91aSCy Schubert 929*4b72b91aSCy Schubert static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) 930*4b72b91aSCy Schubert { 931*4b72b91aSCy Schubert u8 classifier_mask; 932*4b72b91aSCy Schubert const u8 *frame_classifier = policy->frame_classifier; 933*4b72b91aSCy Schubert struct type4_params *type4_param = &policy->type4_param; 934*4b72b91aSCy Schubert 935*4b72b91aSCy Schubert if (policy->frame_classifier_len < 44) { 936*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 937*4b72b91aSCy Schubert "QM: Received IPv6 frame classifier with insufficient length %d", 938*4b72b91aSCy Schubert policy->frame_classifier_len); 939*4b72b91aSCy Schubert return -1; 940*4b72b91aSCy Schubert } 941*4b72b91aSCy Schubert 942*4b72b91aSCy Schubert classifier_mask = frame_classifier[1]; 943*4b72b91aSCy Schubert 944*4b72b91aSCy Schubert /* Classifier Mask - bit 1 = Source IP Address */ 945*4b72b91aSCy Schubert if (classifier_mask & BIT(1)) { 946*4b72b91aSCy Schubert type4_param->ip_params.v6.param_mask |= BIT(1); 947*4b72b91aSCy Schubert os_memcpy(&type4_param->ip_params.v6.src_ip, 948*4b72b91aSCy Schubert &frame_classifier[3], 16); 949*4b72b91aSCy Schubert } 950*4b72b91aSCy Schubert 951*4b72b91aSCy Schubert /* Classifier Mask - bit 2 = Destination IP Address */ 952*4b72b91aSCy Schubert if (classifier_mask & BIT(2)) { 953*4b72b91aSCy Schubert if (policy->domain_name) { 954*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 955*4b72b91aSCy Schubert "QM: IPv6: Both domain name and destination IP address not expected"); 956*4b72b91aSCy Schubert return -1; 957*4b72b91aSCy Schubert } 958*4b72b91aSCy Schubert type4_param->ip_params.v6.param_mask |= BIT(2); 959*4b72b91aSCy Schubert os_memcpy(&type4_param->ip_params.v6.dst_ip, 960*4b72b91aSCy Schubert &frame_classifier[19], 16); 961*4b72b91aSCy Schubert } 962*4b72b91aSCy Schubert 963*4b72b91aSCy Schubert /* Classifier Mask - bit 3 = Source Port */ 964*4b72b91aSCy Schubert if (classifier_mask & BIT(3)) { 965*4b72b91aSCy Schubert type4_param->ip_params.v6.param_mask |= BIT(3); 966*4b72b91aSCy Schubert type4_param->ip_params.v6.src_port = 967*4b72b91aSCy Schubert WPA_GET_BE16(&frame_classifier[35]); 968*4b72b91aSCy Schubert } 969*4b72b91aSCy Schubert 970*4b72b91aSCy Schubert /* Classifier Mask - bit 4 = Destination Port */ 971*4b72b91aSCy Schubert if (classifier_mask & BIT(4)) { 972*4b72b91aSCy Schubert if (policy->port_range_info) { 973*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 974*4b72b91aSCy Schubert "IPv6: Both port range and destination port not expected"); 975*4b72b91aSCy Schubert return -1; 976*4b72b91aSCy Schubert } 977*4b72b91aSCy Schubert 978*4b72b91aSCy Schubert type4_param->ip_params.v6.param_mask |= BIT(4); 979*4b72b91aSCy Schubert type4_param->ip_params.v6.dst_port = 980*4b72b91aSCy Schubert WPA_GET_BE16(&frame_classifier[37]); 981*4b72b91aSCy Schubert } 982*4b72b91aSCy Schubert 983*4b72b91aSCy Schubert /* Classifier Mask - bit 5 = DSCP (ignored) */ 984*4b72b91aSCy Schubert 985*4b72b91aSCy Schubert /* Classifier Mask - bit 6 = Next Header */ 986*4b72b91aSCy Schubert if (classifier_mask & BIT(6)) { 987*4b72b91aSCy Schubert type4_param->ip_params.v6.param_mask |= BIT(6); 988*4b72b91aSCy Schubert type4_param->ip_params.v6.next_header = frame_classifier[40]; 989*4b72b91aSCy Schubert } 990*4b72b91aSCy Schubert 991*4b72b91aSCy Schubert return 0; 992*4b72b91aSCy Schubert } 993*4b72b91aSCy Schubert 994*4b72b91aSCy Schubert 995*4b72b91aSCy Schubert static int wpas_set_frame_classifier_params(struct dscp_policy_data *policy) 996*4b72b91aSCy Schubert { 997*4b72b91aSCy Schubert const u8 *frame_classifier = policy->frame_classifier; 998*4b72b91aSCy Schubert u8 frame_classifier_len = policy->frame_classifier_len; 999*4b72b91aSCy Schubert 1000*4b72b91aSCy Schubert if (frame_classifier_len < 3) { 1001*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1002*4b72b91aSCy Schubert "QM: Received frame classifier with insufficient length %d", 1003*4b72b91aSCy Schubert frame_classifier_len); 1004*4b72b91aSCy Schubert return -1; 1005*4b72b91aSCy Schubert } 1006*4b72b91aSCy Schubert 1007*4b72b91aSCy Schubert /* Only allowed Classifier Type: IP and higher layer parameters (4) */ 1008*4b72b91aSCy Schubert if (frame_classifier[0] != 4) { 1009*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1010*4b72b91aSCy Schubert "QM: Received frame classifier with invalid classifier type %d", 1011*4b72b91aSCy Schubert frame_classifier[0]); 1012*4b72b91aSCy Schubert return -1; 1013*4b72b91aSCy Schubert } 1014*4b72b91aSCy Schubert 1015*4b72b91aSCy Schubert /* Classifier Mask - bit 0 = Version */ 1016*4b72b91aSCy Schubert if (!(frame_classifier[1] & BIT(0))) { 1017*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1018*4b72b91aSCy Schubert "QM: Received frame classifier without IP version"); 1019*4b72b91aSCy Schubert return -1; 1020*4b72b91aSCy Schubert } 1021*4b72b91aSCy Schubert 1022*4b72b91aSCy Schubert /* Version (4 or 6) */ 1023*4b72b91aSCy Schubert if (frame_classifier[2] == 4) { 1024*4b72b91aSCy Schubert if (set_frame_classifier_type4_ipv4(policy)) { 1025*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1026*4b72b91aSCy Schubert "QM: Failed to set IPv4 parameters"); 1027*4b72b91aSCy Schubert return -1; 1028*4b72b91aSCy Schubert } 1029*4b72b91aSCy Schubert 1030*4b72b91aSCy Schubert policy->type4_param.ip_version = IPV4; 1031*4b72b91aSCy Schubert } else if (frame_classifier[2] == 6) { 1032*4b72b91aSCy Schubert if (set_frame_classifier_type4_ipv6(policy)) { 1033*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1034*4b72b91aSCy Schubert "QM: Failed to set IPv6 parameters"); 1035*4b72b91aSCy Schubert return -1; 1036*4b72b91aSCy Schubert } 1037*4b72b91aSCy Schubert 1038*4b72b91aSCy Schubert policy->type4_param.ip_version = IPV6; 1039*4b72b91aSCy Schubert } else { 1040*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1041*4b72b91aSCy Schubert "QM: Received unknown IP version %d", 1042*4b72b91aSCy Schubert frame_classifier[2]); 1043*4b72b91aSCy Schubert return -1; 1044*4b72b91aSCy Schubert } 1045*4b72b91aSCy Schubert 1046*4b72b91aSCy Schubert return 0; 1047*4b72b91aSCy Schubert } 1048*4b72b91aSCy Schubert 1049*4b72b91aSCy Schubert 1050*4b72b91aSCy Schubert static bool dscp_valid_domain_name(const char *str) 1051*4b72b91aSCy Schubert { 1052*4b72b91aSCy Schubert if (!str[0]) 1053*4b72b91aSCy Schubert return false; 1054*4b72b91aSCy Schubert 1055*4b72b91aSCy Schubert while (*str) { 1056*4b72b91aSCy Schubert if (is_ctrl_char(*str) || *str == ' ' || *str == '=') 1057*4b72b91aSCy Schubert return false; 1058*4b72b91aSCy Schubert str++; 1059*4b72b91aSCy Schubert } 1060*4b72b91aSCy Schubert 1061*4b72b91aSCy Schubert return true; 1062*4b72b91aSCy Schubert } 1063*4b72b91aSCy Schubert 1064*4b72b91aSCy Schubert 1065*4b72b91aSCy Schubert static void wpas_add_dscp_policy(struct wpa_supplicant *wpa_s, 1066*4b72b91aSCy Schubert struct dscp_policy_data *policy) 1067*4b72b91aSCy Schubert { 1068*4b72b91aSCy Schubert int ip_ver = 0, res; 1069*4b72b91aSCy Schubert char policy_str[1000], *pos; 1070*4b72b91aSCy Schubert int len; 1071*4b72b91aSCy Schubert 1072*4b72b91aSCy Schubert if (!policy->frame_classifier && !policy->domain_name && 1073*4b72b91aSCy Schubert !policy->port_range_info) { 1074*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1075*4b72b91aSCy Schubert "QM: Invalid DSCP policy - no attributes present"); 1076*4b72b91aSCy Schubert goto fail; 1077*4b72b91aSCy Schubert } 1078*4b72b91aSCy Schubert 1079*4b72b91aSCy Schubert policy_str[0] = '\0'; 1080*4b72b91aSCy Schubert pos = policy_str; 1081*4b72b91aSCy Schubert len = sizeof(policy_str); 1082*4b72b91aSCy Schubert 1083*4b72b91aSCy Schubert if (policy->frame_classifier) { 1084*4b72b91aSCy Schubert struct type4_params *type4 = &policy->type4_param; 1085*4b72b91aSCy Schubert 1086*4b72b91aSCy Schubert if (wpas_set_frame_classifier_params(policy)) { 1087*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1088*4b72b91aSCy Schubert "QM: Failed to set frame classifier parameters"); 1089*4b72b91aSCy Schubert goto fail; 1090*4b72b91aSCy Schubert } 1091*4b72b91aSCy Schubert 1092*4b72b91aSCy Schubert if (type4->ip_version == IPV4) 1093*4b72b91aSCy Schubert res = write_ipv4_info(pos, len, &type4->ip_params.v4); 1094*4b72b91aSCy Schubert else 1095*4b72b91aSCy Schubert res = write_ipv6_info(pos, len, &type4->ip_params.v6); 1096*4b72b91aSCy Schubert 1097*4b72b91aSCy Schubert if (res <= 0) { 1098*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1099*4b72b91aSCy Schubert "QM: Failed to write IP parameters"); 1100*4b72b91aSCy Schubert goto fail; 1101*4b72b91aSCy Schubert } 1102*4b72b91aSCy Schubert 1103*4b72b91aSCy Schubert ip_ver = type4->ip_version; 1104*4b72b91aSCy Schubert 1105*4b72b91aSCy Schubert pos += res; 1106*4b72b91aSCy Schubert len -= res; 1107*4b72b91aSCy Schubert } 1108*4b72b91aSCy Schubert 1109*4b72b91aSCy Schubert if (policy->port_range_info) { 1110*4b72b91aSCy Schubert res = os_snprintf(pos, len, " start_port=%u end_port=%u", 1111*4b72b91aSCy Schubert policy->start_port, policy->end_port); 1112*4b72b91aSCy Schubert if (os_snprintf_error(len, res)) { 1113*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1114*4b72b91aSCy Schubert "QM: Failed to write port range attributes for policy id = %d", 1115*4b72b91aSCy Schubert policy->policy_id); 1116*4b72b91aSCy Schubert goto fail; 1117*4b72b91aSCy Schubert } 1118*4b72b91aSCy Schubert 1119*4b72b91aSCy Schubert pos += res; 1120*4b72b91aSCy Schubert len -= res; 1121*4b72b91aSCy Schubert } 1122*4b72b91aSCy Schubert 1123*4b72b91aSCy Schubert if (policy->domain_name) { 1124*4b72b91aSCy Schubert char domain_name_str[250]; 1125*4b72b91aSCy Schubert 1126*4b72b91aSCy Schubert if (policy->domain_name_len >= sizeof(domain_name_str)) { 1127*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1128*4b72b91aSCy Schubert "QM: Domain name length higher than max expected"); 1129*4b72b91aSCy Schubert goto fail; 1130*4b72b91aSCy Schubert } 1131*4b72b91aSCy Schubert os_memcpy(domain_name_str, policy->domain_name, 1132*4b72b91aSCy Schubert policy->domain_name_len); 1133*4b72b91aSCy Schubert domain_name_str[policy->domain_name_len] = '\0'; 1134*4b72b91aSCy Schubert if (!dscp_valid_domain_name(domain_name_str)) { 1135*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: Invalid domain name string"); 1136*4b72b91aSCy Schubert goto fail; 1137*4b72b91aSCy Schubert } 1138*4b72b91aSCy Schubert res = os_snprintf(pos, len, " domain_name=%s", domain_name_str); 1139*4b72b91aSCy Schubert if (os_snprintf_error(len, res)) { 1140*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1141*4b72b91aSCy Schubert "QM: Failed to write domain name attribute for policy id = %d", 1142*4b72b91aSCy Schubert policy->policy_id); 1143*4b72b91aSCy Schubert goto fail; 1144*4b72b91aSCy Schubert } 1145*4b72b91aSCy Schubert } 1146*4b72b91aSCy Schubert 1147*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY 1148*4b72b91aSCy Schubert "add policy_id=%u dscp=%u ip_version=%d%s", 1149*4b72b91aSCy Schubert policy->policy_id, policy->dscp, ip_ver, policy_str); 1150*4b72b91aSCy Schubert return; 1151*4b72b91aSCy Schubert fail: 1152*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "reject policy_id=%u", 1153*4b72b91aSCy Schubert policy->policy_id); 1154*4b72b91aSCy Schubert } 1155*4b72b91aSCy Schubert 1156*4b72b91aSCy Schubert 1157*4b72b91aSCy Schubert void wpas_dscp_deinit(struct wpa_supplicant *wpa_s) 1158*4b72b91aSCy Schubert { 1159*4b72b91aSCy Schubert wpa_printf(MSG_DEBUG, "QM: Clear all active DSCP policies"); 1160*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "clear_all"); 1161*4b72b91aSCy Schubert wpa_s->dscp_req_dialog_token = 0; 1162*4b72b91aSCy Schubert wpa_s->dscp_query_dialog_token = 0; 1163*4b72b91aSCy Schubert wpa_s->connection_dscp = 0; 1164*4b72b91aSCy Schubert if (wpa_s->wait_for_dscp_req) { 1165*4b72b91aSCy Schubert wpa_s->wait_for_dscp_req = 0; 1166*4b72b91aSCy Schubert eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL); 1167*4b72b91aSCy Schubert } 1168*4b72b91aSCy Schubert } 1169*4b72b91aSCy Schubert 1170*4b72b91aSCy Schubert 1171*4b72b91aSCy Schubert static void wpas_fill_dscp_policy(struct dscp_policy_data *policy, u8 attr_id, 1172*4b72b91aSCy Schubert u8 attr_len, const u8 *attr_data) 1173*4b72b91aSCy Schubert { 1174*4b72b91aSCy Schubert switch (attr_id) { 1175*4b72b91aSCy Schubert case QM_ATTR_PORT_RANGE: 1176*4b72b91aSCy Schubert if (attr_len < 4) { 1177*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1178*4b72b91aSCy Schubert "QM: Received Port Range attribute with insufficient length %d", 1179*4b72b91aSCy Schubert attr_len); 1180*4b72b91aSCy Schubert break; 1181*4b72b91aSCy Schubert } 1182*4b72b91aSCy Schubert policy->start_port = WPA_GET_BE16(attr_data); 1183*4b72b91aSCy Schubert policy->end_port = WPA_GET_BE16(attr_data + 2); 1184*4b72b91aSCy Schubert policy->port_range_info = true; 1185*4b72b91aSCy Schubert break; 1186*4b72b91aSCy Schubert case QM_ATTR_DSCP_POLICY: 1187*4b72b91aSCy Schubert if (attr_len < 3) { 1188*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1189*4b72b91aSCy Schubert "QM: Received DSCP Policy attribute with insufficient length %d", 1190*4b72b91aSCy Schubert attr_len); 1191*4b72b91aSCy Schubert return; 1192*4b72b91aSCy Schubert } 1193*4b72b91aSCy Schubert policy->policy_id = attr_data[0]; 1194*4b72b91aSCy Schubert policy->req_type = attr_data[1]; 1195*4b72b91aSCy Schubert policy->dscp = attr_data[2]; 1196*4b72b91aSCy Schubert policy->dscp_info = true; 1197*4b72b91aSCy Schubert break; 1198*4b72b91aSCy Schubert case QM_ATTR_TCLAS: 1199*4b72b91aSCy Schubert if (attr_len < 1) { 1200*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1201*4b72b91aSCy Schubert "QM: Received TCLAS attribute with insufficient length %d", 1202*4b72b91aSCy Schubert attr_len); 1203*4b72b91aSCy Schubert return; 1204*4b72b91aSCy Schubert } 1205*4b72b91aSCy Schubert policy->frame_classifier = attr_data; 1206*4b72b91aSCy Schubert policy->frame_classifier_len = attr_len; 1207*4b72b91aSCy Schubert break; 1208*4b72b91aSCy Schubert case QM_ATTR_DOMAIN_NAME: 1209*4b72b91aSCy Schubert if (attr_len < 1) { 1210*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1211*4b72b91aSCy Schubert "QM: Received domain name attribute with insufficient length %d", 1212*4b72b91aSCy Schubert attr_len); 1213*4b72b91aSCy Schubert return; 1214*4b72b91aSCy Schubert } 1215*4b72b91aSCy Schubert policy->domain_name = attr_data; 1216*4b72b91aSCy Schubert policy->domain_name_len = attr_len; 1217*4b72b91aSCy Schubert break; 1218*4b72b91aSCy Schubert default: 1219*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: Received invalid QoS attribute %d", 1220*4b72b91aSCy Schubert attr_id); 1221*4b72b91aSCy Schubert break; 1222*4b72b91aSCy Schubert } 1223*4b72b91aSCy Schubert } 1224*4b72b91aSCy Schubert 1225*4b72b91aSCy Schubert 1226*4b72b91aSCy Schubert void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s, 1227*4b72b91aSCy Schubert const u8 *src, 1228*4b72b91aSCy Schubert const u8 *buf, size_t len) 1229*4b72b91aSCy Schubert { 1230*4b72b91aSCy Schubert int rem_len; 1231*4b72b91aSCy Schubert const u8 *qos_ie, *attr; 1232*4b72b91aSCy Schubert int more, reset; 1233*4b72b91aSCy Schubert 1234*4b72b91aSCy Schubert if (!wpa_s->enable_dscp_policy_capa) { 1235*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1236*4b72b91aSCy Schubert "QM: Ignore DSCP Policy frame since the capability is not enabled"); 1237*4b72b91aSCy Schubert return; 1238*4b72b91aSCy Schubert } 1239*4b72b91aSCy Schubert 1240*4b72b91aSCy Schubert if (!pmf_in_use(wpa_s, src)) { 1241*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1242*4b72b91aSCy Schubert "QM: Ignore DSCP Policy frame since PMF is not in use"); 1243*4b72b91aSCy Schubert return; 1244*4b72b91aSCy Schubert } 1245*4b72b91aSCy Schubert 1246*4b72b91aSCy Schubert if (!wpa_s->connection_dscp) { 1247*4b72b91aSCy Schubert wpa_printf(MSG_DEBUG, 1248*4b72b91aSCy Schubert "QM: DSCP Policy capability not enabled for the current association - ignore QoS Management Action frames"); 1249*4b72b91aSCy Schubert return; 1250*4b72b91aSCy Schubert } 1251*4b72b91aSCy Schubert 1252*4b72b91aSCy Schubert if (len < 1) 1253*4b72b91aSCy Schubert return; 1254*4b72b91aSCy Schubert 1255*4b72b91aSCy Schubert /* Handle only DSCP Policy Request frame */ 1256*4b72b91aSCy Schubert if (buf[0] != QM_DSCP_POLICY_REQ) { 1257*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: Received unexpected QoS action frame %d", 1258*4b72b91aSCy Schubert buf[0]); 1259*4b72b91aSCy Schubert return; 1260*4b72b91aSCy Schubert } 1261*4b72b91aSCy Schubert 1262*4b72b91aSCy Schubert if (len < 3) { 1263*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1264*4b72b91aSCy Schubert "Received QoS Management DSCP Policy Request frame with invalid length %zu", 1265*4b72b91aSCy Schubert len); 1266*4b72b91aSCy Schubert return; 1267*4b72b91aSCy Schubert } 1268*4b72b91aSCy Schubert 1269*4b72b91aSCy Schubert /* Clear wait_for_dscp_req on receiving first DSCP request from AP */ 1270*4b72b91aSCy Schubert if (wpa_s->wait_for_dscp_req) { 1271*4b72b91aSCy Schubert wpa_s->wait_for_dscp_req = 0; 1272*4b72b91aSCy Schubert eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL); 1273*4b72b91aSCy Schubert } 1274*4b72b91aSCy Schubert 1275*4b72b91aSCy Schubert wpa_s->dscp_req_dialog_token = buf[1]; 1276*4b72b91aSCy Schubert more = buf[2] & DSCP_POLICY_CTRL_MORE; 1277*4b72b91aSCy Schubert reset = buf[2] & DSCP_POLICY_CTRL_RESET; 1278*4b72b91aSCy Schubert 1279*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_start%s%s", 1280*4b72b91aSCy Schubert reset ? " clear_all" : "", more ? " more" : ""); 1281*4b72b91aSCy Schubert 1282*4b72b91aSCy Schubert qos_ie = buf + 3; 1283*4b72b91aSCy Schubert rem_len = len - 3; 1284*4b72b91aSCy Schubert while (rem_len > 2) { 1285*4b72b91aSCy Schubert struct dscp_policy_data policy; 1286*4b72b91aSCy Schubert int rem_attrs_len, ie_len; 1287*4b72b91aSCy Schubert 1288*4b72b91aSCy Schubert ie_len = 2 + qos_ie[1]; 1289*4b72b91aSCy Schubert if (rem_len < ie_len) 1290*4b72b91aSCy Schubert break; 1291*4b72b91aSCy Schubert 1292*4b72b91aSCy Schubert if (rem_len < 6 || qos_ie[0] != WLAN_EID_VENDOR_SPECIFIC || 1293*4b72b91aSCy Schubert qos_ie[1] < 4 || 1294*4b72b91aSCy Schubert WPA_GET_BE32(&qos_ie[2]) != QM_IE_VENDOR_TYPE) { 1295*4b72b91aSCy Schubert rem_len -= ie_len; 1296*4b72b91aSCy Schubert qos_ie += ie_len; 1297*4b72b91aSCy Schubert continue; 1298*4b72b91aSCy Schubert } 1299*4b72b91aSCy Schubert 1300*4b72b91aSCy Schubert os_memset(&policy, 0, sizeof(struct dscp_policy_data)); 1301*4b72b91aSCy Schubert attr = qos_ie + 6; 1302*4b72b91aSCy Schubert rem_attrs_len = qos_ie[1] - 4; 1303*4b72b91aSCy Schubert 1304*4b72b91aSCy Schubert while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) { 1305*4b72b91aSCy Schubert wpas_fill_dscp_policy(&policy, attr[0], attr[1], 1306*4b72b91aSCy Schubert &attr[2]); 1307*4b72b91aSCy Schubert rem_attrs_len -= 2 + attr[1]; 1308*4b72b91aSCy Schubert attr += 2 + attr[1]; 1309*4b72b91aSCy Schubert } 1310*4b72b91aSCy Schubert 1311*4b72b91aSCy Schubert rem_len -= ie_len; 1312*4b72b91aSCy Schubert qos_ie += ie_len; 1313*4b72b91aSCy Schubert 1314*4b72b91aSCy Schubert if (!policy.dscp_info) { 1315*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1316*4b72b91aSCy Schubert "QM: Received QoS IE without DSCP Policy attribute"); 1317*4b72b91aSCy Schubert continue; 1318*4b72b91aSCy Schubert } 1319*4b72b91aSCy Schubert 1320*4b72b91aSCy Schubert if (policy.req_type == DSCP_POLICY_REQ_ADD) 1321*4b72b91aSCy Schubert wpas_add_dscp_policy(wpa_s, &policy); 1322*4b72b91aSCy Schubert else if (policy.req_type == DSCP_POLICY_REQ_REMOVE) 1323*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY 1324*4b72b91aSCy Schubert "remove policy_id=%u", policy.policy_id); 1325*4b72b91aSCy Schubert else 1326*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY 1327*4b72b91aSCy Schubert "reject policy_id=%u", policy.policy_id); 1328*4b72b91aSCy Schubert } 1329*4b72b91aSCy Schubert 1330*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_end"); 1331*4b72b91aSCy Schubert } 1332*4b72b91aSCy Schubert 1333*4b72b91aSCy Schubert 1334*4b72b91aSCy Schubert int wpas_send_dscp_response(struct wpa_supplicant *wpa_s, 1335*4b72b91aSCy Schubert struct dscp_resp_data *resp_data) 1336*4b72b91aSCy Schubert { 1337*4b72b91aSCy Schubert struct wpabuf *buf = NULL; 1338*4b72b91aSCy Schubert size_t buf_len; 1339*4b72b91aSCy Schubert int ret = -1, i; 1340*4b72b91aSCy Schubert u8 resp_control = 0; 1341*4b72b91aSCy Schubert 1342*4b72b91aSCy Schubert if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) { 1343*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1344*4b72b91aSCy Schubert "QM: Failed to send DSCP response - not connected to AP"); 1345*4b72b91aSCy Schubert return -1; 1346*4b72b91aSCy Schubert } 1347*4b72b91aSCy Schubert 1348*4b72b91aSCy Schubert if (resp_data->solicited && !wpa_s->dscp_req_dialog_token) { 1349*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: No ongoing DSCP request"); 1350*4b72b91aSCy Schubert return -1; 1351*4b72b91aSCy Schubert } 1352*4b72b91aSCy Schubert 1353*4b72b91aSCy Schubert if (!wpa_s->connection_dscp) { 1354*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1355*4b72b91aSCy Schubert "QM: Failed to send DSCP response - DSCP capability not enabled for the current association"); 1356*4b72b91aSCy Schubert return -1; 1357*4b72b91aSCy Schubert 1358*4b72b91aSCy Schubert } 1359*4b72b91aSCy Schubert 1360*4b72b91aSCy Schubert buf_len = 1 + /* Category */ 1361*4b72b91aSCy Schubert 3 + /* OUI */ 1362*4b72b91aSCy Schubert 1 + /* OUI Type */ 1363*4b72b91aSCy Schubert 1 + /* OUI Subtype */ 1364*4b72b91aSCy Schubert 1 + /* Dialog Token */ 1365*4b72b91aSCy Schubert 1 + /* Response Control */ 1366*4b72b91aSCy Schubert 1 + /* Count */ 1367*4b72b91aSCy Schubert 2 * resp_data->num_policies; /* Status list */ 1368*4b72b91aSCy Schubert buf = wpabuf_alloc(buf_len); 1369*4b72b91aSCy Schubert if (!buf) { 1370*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1371*4b72b91aSCy Schubert "QM: Failed to allocate DSCP policy response"); 1372*4b72b91aSCy Schubert return -1; 1373*4b72b91aSCy Schubert } 1374*4b72b91aSCy Schubert 1375*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED); 1376*4b72b91aSCy Schubert wpabuf_put_be24(buf, OUI_WFA); 1377*4b72b91aSCy Schubert wpabuf_put_u8(buf, QM_ACTION_OUI_TYPE); 1378*4b72b91aSCy Schubert wpabuf_put_u8(buf, QM_DSCP_POLICY_RESP); 1379*4b72b91aSCy Schubert 1380*4b72b91aSCy Schubert wpabuf_put_u8(buf, resp_data->solicited ? 1381*4b72b91aSCy Schubert wpa_s->dscp_req_dialog_token : 0); 1382*4b72b91aSCy Schubert 1383*4b72b91aSCy Schubert if (resp_data->more) 1384*4b72b91aSCy Schubert resp_control |= DSCP_POLICY_CTRL_MORE; 1385*4b72b91aSCy Schubert if (resp_data->reset) 1386*4b72b91aSCy Schubert resp_control |= DSCP_POLICY_CTRL_RESET; 1387*4b72b91aSCy Schubert wpabuf_put_u8(buf, resp_control); 1388*4b72b91aSCy Schubert 1389*4b72b91aSCy Schubert wpabuf_put_u8(buf, resp_data->num_policies); 1390*4b72b91aSCy Schubert for (i = 0; i < resp_data->num_policies; i++) { 1391*4b72b91aSCy Schubert wpabuf_put_u8(buf, resp_data->policy[i].id); 1392*4b72b91aSCy Schubert wpabuf_put_u8(buf, resp_data->policy[i].status); 1393*4b72b91aSCy Schubert } 1394*4b72b91aSCy Schubert 1395*4b72b91aSCy Schubert wpa_hexdump_buf(MSG_MSGDUMP, "DSCP response frame: ", buf); 1396*4b72b91aSCy Schubert ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1397*4b72b91aSCy Schubert wpa_s->own_addr, wpa_s->bssid, 1398*4b72b91aSCy Schubert wpabuf_head(buf), wpabuf_len(buf), 0); 1399*4b72b91aSCy Schubert if (ret < 0) { 1400*4b72b91aSCy Schubert wpa_msg(wpa_s, MSG_INFO, "QM: Failed to send DSCP response"); 1401*4b72b91aSCy Schubert goto fail; 1402*4b72b91aSCy Schubert } 1403*4b72b91aSCy Schubert 1404*4b72b91aSCy Schubert /* 1405*4b72b91aSCy Schubert * Mark DSCP request complete whether response sent is solicited or 1406*4b72b91aSCy Schubert * unsolicited 1407*4b72b91aSCy Schubert */ 1408*4b72b91aSCy Schubert wpa_s->dscp_req_dialog_token = 0; 1409*4b72b91aSCy Schubert 1410*4b72b91aSCy Schubert fail: 1411*4b72b91aSCy Schubert wpabuf_free(buf); 1412*4b72b91aSCy Schubert return ret; 1413*4b72b91aSCy Schubert } 1414*4b72b91aSCy Schubert 1415*4b72b91aSCy Schubert 1416*4b72b91aSCy Schubert int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name, 1417*4b72b91aSCy Schubert size_t domain_name_length) 1418*4b72b91aSCy Schubert { 1419*4b72b91aSCy Schubert struct wpabuf *buf = NULL; 1420*4b72b91aSCy Schubert int ret, dscp_query_size; 1421*4b72b91aSCy Schubert 1422*4b72b91aSCy Schubert if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) 1423*4b72b91aSCy Schubert return -1; 1424*4b72b91aSCy Schubert 1425*4b72b91aSCy Schubert if (!wpa_s->connection_dscp) { 1426*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, 1427*4b72b91aSCy Schubert "QM: Failed to send DSCP query - DSCP capability not enabled for the current association"); 1428*4b72b91aSCy Schubert return -1; 1429*4b72b91aSCy Schubert } 1430*4b72b91aSCy Schubert 1431*4b72b91aSCy Schubert if (wpa_s->wait_for_dscp_req) { 1432*4b72b91aSCy Schubert wpa_printf(MSG_INFO, "QM: Wait until AP sends a DSCP request"); 1433*4b72b91aSCy Schubert return -1; 1434*4b72b91aSCy Schubert } 1435*4b72b91aSCy Schubert 1436*4b72b91aSCy Schubert #define DOMAIN_NAME_OFFSET (4 /* OUI */ + 1 /* Attr Id */ + 1 /* Attr len */) 1437*4b72b91aSCy Schubert 1438*4b72b91aSCy Schubert if (domain_name_length > 255 - DOMAIN_NAME_OFFSET) { 1439*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: Too long domain name"); 1440*4b72b91aSCy Schubert return -1; 1441*4b72b91aSCy Schubert } 1442*4b72b91aSCy Schubert 1443*4b72b91aSCy Schubert dscp_query_size = 1 + /* Category */ 1444*4b72b91aSCy Schubert 4 + /* OUI Type */ 1445*4b72b91aSCy Schubert 1 + /* OUI subtype */ 1446*4b72b91aSCy Schubert 1; /* Dialog Token */ 1447*4b72b91aSCy Schubert if (domain_name && domain_name_length) 1448*4b72b91aSCy Schubert dscp_query_size += 1 + /* Element ID */ 1449*4b72b91aSCy Schubert 1 + /* IE Length */ 1450*4b72b91aSCy Schubert DOMAIN_NAME_OFFSET + domain_name_length; 1451*4b72b91aSCy Schubert 1452*4b72b91aSCy Schubert buf = wpabuf_alloc(dscp_query_size); 1453*4b72b91aSCy Schubert if (!buf) { 1454*4b72b91aSCy Schubert wpa_printf(MSG_ERROR, "QM: Failed to allocate DSCP query"); 1455*4b72b91aSCy Schubert return -1; 1456*4b72b91aSCy Schubert } 1457*4b72b91aSCy Schubert 1458*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED); 1459*4b72b91aSCy Schubert wpabuf_put_be32(buf, QM_ACTION_VENDOR_TYPE); 1460*4b72b91aSCy Schubert wpabuf_put_u8(buf, QM_DSCP_POLICY_QUERY); 1461*4b72b91aSCy Schubert wpa_s->dscp_query_dialog_token++; 1462*4b72b91aSCy Schubert if (wpa_s->dscp_query_dialog_token == 0) 1463*4b72b91aSCy Schubert wpa_s->dscp_query_dialog_token++; 1464*4b72b91aSCy Schubert wpabuf_put_u8(buf, wpa_s->dscp_query_dialog_token); 1465*4b72b91aSCy Schubert 1466*4b72b91aSCy Schubert if (domain_name && domain_name_length) { 1467*4b72b91aSCy Schubert /* Domain Name attribute */ 1468*4b72b91aSCy Schubert wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 1469*4b72b91aSCy Schubert wpabuf_put_u8(buf, DOMAIN_NAME_OFFSET + domain_name_length); 1470*4b72b91aSCy Schubert wpabuf_put_be32(buf, QM_IE_VENDOR_TYPE); 1471*4b72b91aSCy Schubert wpabuf_put_u8(buf, QM_ATTR_DOMAIN_NAME); 1472*4b72b91aSCy Schubert wpabuf_put_u8(buf, domain_name_length); 1473*4b72b91aSCy Schubert wpabuf_put_data(buf, domain_name, domain_name_length); 1474*4b72b91aSCy Schubert } 1475*4b72b91aSCy Schubert #undef DOMAIN_NAME_OFFSET 1476*4b72b91aSCy Schubert 1477*4b72b91aSCy Schubert ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1478*4b72b91aSCy Schubert wpa_s->own_addr, wpa_s->bssid, 1479*4b72b91aSCy Schubert wpabuf_head(buf), wpabuf_len(buf), 0); 1480*4b72b91aSCy Schubert if (ret < 0) { 1481*4b72b91aSCy Schubert wpa_dbg(wpa_s, MSG_ERROR, "QM: Failed to send DSCP query"); 1482*4b72b91aSCy Schubert wpa_s->dscp_query_dialog_token--; 1483*4b72b91aSCy Schubert } 1484*4b72b91aSCy Schubert 1485*4b72b91aSCy Schubert wpabuf_free(buf); 1486*4b72b91aSCy Schubert return ret; 1487*4b72b91aSCy Schubert } 1488