blob: 658103d48be5f4f828b45d9dd229cc67fbf6e087 [file] [log] [blame]
Hai Shalom899fcc72020-10-19 14:38:18 -07001/*
2 * wpa_supplicant - Robust AV procedures
3 * Copyright (c) 2020, The Linux Foundation
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
10#include "utils/common.h"
Hai Shalomc1a21442022-02-04 13:43:00 -080011#include "utils/eloop.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070012#include "common/wpa_ctrl.h"
13#include "common/ieee802_11_common.h"
14#include "wpa_supplicant_i.h"
15#include "driver_i.h"
16#include "bss.h"
Shivani Baranwal84940f82022-02-02 10:21:47 +053017#include "notify.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070018
19
Hai Shalomc1a21442022-02-04 13:43:00 -080020#define SCS_RESP_TIMEOUT 1
21#define DSCP_REQ_TIMEOUT 5
22
23
Hai Shalom899fcc72020-10-19 14:38:18 -070024void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
25 struct wpabuf *buf)
26{
27 u8 *len, *len1;
28
29 /* MSCS descriptor element */
30 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
31 len = wpabuf_put(buf, 1);
32 wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
33 wpabuf_put_u8(buf, robust_av->request_type);
34 wpabuf_put_u8(buf, robust_av->up_bitmap);
35 wpabuf_put_u8(buf, robust_av->up_limit);
36 wpabuf_put_le32(buf, robust_av->stream_timeout);
37
38 if (robust_av->request_type != SCS_REQ_REMOVE) {
39 /* TCLAS mask element */
40 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
41 len1 = wpabuf_put(buf, 1);
42 wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
43
44 /* Frame classifier */
45 wpabuf_put_data(buf, robust_av->frame_classifier,
46 robust_av->frame_classifier_len);
47 *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
48 }
49
50 *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
51}
52
53
Hai Shalomc1a21442022-02-04 13:43:00 -080054static int wpas_populate_type4_classifier(struct type4_params *type4_param,
55 struct wpabuf *buf)
56{
57 /* classifier parameters */
58 wpabuf_put_u8(buf, type4_param->classifier_mask);
59 if (type4_param->ip_version == IPV4) {
60 wpabuf_put_u8(buf, IPV4); /* IP version */
61 wpabuf_put_data(buf, &type4_param->ip_params.v4.src_ip.s_addr,
62 4);
63 wpabuf_put_data(buf, &type4_param->ip_params.v4.dst_ip.s_addr,
64 4);
65 wpabuf_put_be16(buf, type4_param->ip_params.v4.src_port);
66 wpabuf_put_be16(buf, type4_param->ip_params.v4.dst_port);
67 wpabuf_put_u8(buf, type4_param->ip_params.v4.dscp);
68 wpabuf_put_u8(buf, type4_param->ip_params.v4.protocol);
69 wpabuf_put_u8(buf, 0); /* Reserved octet */
70 } else {
71 wpabuf_put_u8(buf, IPV6);
72 wpabuf_put_data(buf, &type4_param->ip_params.v6.src_ip.s6_addr,
73 16);
74 wpabuf_put_data(buf, &type4_param->ip_params.v6.dst_ip.s6_addr,
75 16);
76 wpabuf_put_be16(buf, type4_param->ip_params.v6.src_port);
77 wpabuf_put_be16(buf, type4_param->ip_params.v6.dst_port);
78 wpabuf_put_u8(buf, type4_param->ip_params.v6.dscp);
79 wpabuf_put_u8(buf, type4_param->ip_params.v6.next_header);
80 wpabuf_put_data(buf, type4_param->ip_params.v6.flow_label, 3);
81 }
82
83 return 0;
84}
85
86
87static int wpas_populate_type10_classifier(struct type10_params *type10_param,
88 struct wpabuf *buf)
89{
90 /* classifier parameters */
91 wpabuf_put_u8(buf, type10_param->prot_instance);
92 wpabuf_put_u8(buf, type10_param->prot_number);
93 wpabuf_put_data(buf, type10_param->filter_value,
94 type10_param->filter_len);
95 wpabuf_put_data(buf, type10_param->filter_mask,
96 type10_param->filter_len);
97 return 0;
98}
99
100
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000101static bool tclas_elem_required(const struct qos_characteristics *qos_elem)
102{
103 if (!qos_elem || !qos_elem->available)
104 return true;
105
106 if (qos_elem->direction == SCS_DIRECTION_DOWN)
107 return true;
108
109 return false;
110}
111
112
Hai Shalomc1a21442022-02-04 13:43:00 -0800113static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000114 struct wpabuf *buf,
115 bool allow_scs_traffic_desc)
Hai Shalomc1a21442022-02-04 13:43:00 -0800116{
117 u8 *len, *len1;
118 struct tclas_element *tclas_elem;
119 unsigned int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000120 struct qos_characteristics *qos_elem;
121 u32 control_info = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -0800122
123 /* SCS Descriptor element */
124 wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR);
125 len = wpabuf_put(buf, 1);
126 wpabuf_put_u8(buf, desc_elem->scs_id);
127 wpabuf_put_u8(buf, desc_elem->request_type);
128 if (desc_elem->request_type == SCS_REQ_REMOVE)
129 goto end;
130
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000131 if (!tclas_elem_required(&desc_elem->qos_char_elem))
132 goto skip_tclas_elem;
133
Hai Shalomc1a21442022-02-04 13:43:00 -0800134 if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) {
135 wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY);
136 wpabuf_put_u8(buf, 1);
137 wpabuf_put_u8(buf, desc_elem->intra_access_priority);
138 }
139
140 tclas_elem = desc_elem->tclas_elems;
141
142 if (!tclas_elem)
143 return -1;
144
145 for (i = 0; i < desc_elem->num_tclas_elem; i++, tclas_elem++) {
146 int ret;
147
148 /* TCLAS element */
149 wpabuf_put_u8(buf, WLAN_EID_TCLAS);
150 len1 = wpabuf_put(buf, 1);
151 wpabuf_put_u8(buf, 255); /* User Priority: not compared */
152 /* Frame Classifier */
153 wpabuf_put_u8(buf, tclas_elem->classifier_type);
154 /* Frame classifier parameters */
155 switch (tclas_elem->classifier_type) {
156 case 4:
157 ret = wpas_populate_type4_classifier(
158 &tclas_elem->frame_classifier.type4_param,
159 buf);
160 break;
161 case 10:
162 ret = wpas_populate_type10_classifier(
163 &tclas_elem->frame_classifier.type10_param,
164 buf);
165 break;
166 default:
167 return -1;
168 }
169
170 if (ret == -1) {
171 wpa_printf(MSG_ERROR,
172 "Failed to populate frame classifier");
173 return -1;
174 }
175
176 *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
177 }
178
179 if (desc_elem->num_tclas_elem > 1) {
180 /* TCLAS Processing element */
181 wpabuf_put_u8(buf, WLAN_EID_TCLAS_PROCESSING);
182 wpabuf_put_u8(buf, 1);
183 wpabuf_put_u8(buf, desc_elem->tclas_processing);
184 }
185
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000186skip_tclas_elem:
187 if (allow_scs_traffic_desc && desc_elem->qos_char_elem.available) {
188 qos_elem = &desc_elem->qos_char_elem;
189 /* Element ID, Length, and Element ID Extension */
190 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
191 len1 = wpabuf_put(buf, 1);
192 wpabuf_put_u8(buf, WLAN_EID_EXT_QOS_CHARACTERISTICS);
193
194 /* Remove invalid mask bits */
195
196 /* Medium Time is applicable only for direct link */
197 if ((qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME) &&
198 qos_elem->direction != SCS_DIRECTION_DIRECT)
199 qos_elem->mask &= ~SCS_QOS_BIT_MEDIUM_TIME;
200
201 /* Service Start Time LinkID is valid only when Service Start
202 * Time is present.
203 */
204 if ((qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID) &&
205 !(qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME))
206 qos_elem->mask &=
207 ~SCS_QOS_BIT_SERVICE_START_TIME_LINKID;
208
209 /* IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element,
210 * Figure 9-1001av (Control Info field format)
211 */
212 control_info = ((u32) qos_elem->direction <<
213 EHT_QOS_CONTROL_INFO_DIRECTION_OFFSET);
214 control_info |= ((u32) desc_elem->intra_access_priority <<
215 EHT_QOS_CONTROL_INFO_TID_OFFSET);
216 control_info |= ((u32) desc_elem->intra_access_priority <<
217 EHT_QOS_CONTROL_INFO_USER_PRIORITY_OFFSET);
218 control_info |= ((u32) qos_elem->mask <<
219 EHT_QOS_CONTROL_INFO_PRESENCE_MASK_OFFSET);
220
221 /* Control Info */
222 wpabuf_put_le32(buf, control_info);
223 /* Minimum Service Interval */
224 wpabuf_put_le32(buf, qos_elem->min_si);
225 /* Maximum Service Interval */
226 wpabuf_put_le32(buf, qos_elem->max_si);
227 /* Minimum Data Rate */
228 wpabuf_put_le24(buf, qos_elem->min_data_rate);
229 /* Delay Bound */
230 wpabuf_put_le24(buf, qos_elem->delay_bound);
231
232 /* Maximum MSDU Size */
233 if (qos_elem->mask & SCS_QOS_BIT_MAX_MSDU_SIZE)
234 wpabuf_put_le16(buf, qos_elem->max_msdu_size);
235 /* Start Service Time */
236 if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME)
237 wpabuf_put_le32(buf, qos_elem->service_start_time);
238 /* Service Start Time LinkID */
239 if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID)
240 wpabuf_put_u8(buf,
241 qos_elem->service_start_time_link_id);
242 /* Mean Data Rate */
243 if (qos_elem->mask & SCS_QOS_BIT_MEAN_DATA_RATE)
244 wpabuf_put_le24(buf, qos_elem->mean_data_rate);
245 /* Delayed Bounded Burst Size */
246 if (qos_elem->mask & SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE)
247 wpabuf_put_le32(buf, qos_elem->burst_size);
248 /* MSDU Lifetime */
249 if (qos_elem->mask & SCS_QOS_BIT_MSDU_LIFETIME)
250 wpabuf_put_le16(buf, qos_elem->msdu_lifetime);
251 /* MSDU Delivery Info */
252 if (qos_elem->mask & SCS_QOS_BIT_MSDU_DELIVERY_INFO)
253 wpabuf_put_u8(buf, qos_elem->msdu_delivery_info);
254 /* Medium Time */
255 if (qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME)
256 wpabuf_put_le16(buf, qos_elem->medium_time);
257
258 *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
259 }
260
Hai Shalomc1a21442022-02-04 13:43:00 -0800261end:
262 *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
263 return 0;
264}
265
266
Hai Shalom899fcc72020-10-19 14:38:18 -0700267int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
268{
269 struct wpabuf *buf;
Hai Shalom899fcc72020-10-19 14:38:18 -0700270 size_t buf_len;
271 int ret;
272
273 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
274 return 0;
275
Hai Shalom60840252021-02-19 19:02:11 -0800276 if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS)) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700277 wpa_dbg(wpa_s, MSG_INFO,
278 "AP does not support MSCS - could not send MSCS Req");
279 return -1;
280 }
281
282 if (!wpa_s->mscs_setup_done &&
283 wpa_s->robust_av.request_type != SCS_REQ_ADD) {
284 wpa_msg(wpa_s, MSG_INFO,
285 "MSCS: Failed to send MSCS Request: request type invalid");
286 return -1;
287 }
288
289 buf_len = 3 + /* Action frame header */
290 3 + /* MSCS descriptor IE header */
291 1 + /* Request type */
292 2 + /* User priority control */
293 4 + /* Stream timeout */
294 3 + /* TCLAS Mask IE header */
295 wpa_s->robust_av.frame_classifier_len;
296
297 buf = wpabuf_alloc(buf_len);
298 if (!buf) {
299 wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
300 return -1;
301 }
302
303 wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
304 wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
305 wpa_s->robust_av.dialog_token++;
306 wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
307
308 /* MSCS descriptor element */
309 wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
310
311 wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", buf);
312 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
313 wpa_s->own_addr, wpa_s->bssid,
314 wpabuf_head(buf), wpabuf_len(buf), 0);
315 if (ret < 0)
316 wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
317
318 wpabuf_free(buf);
319 return ret;
320}
321
322
Hai Shalomc1a21442022-02-04 13:43:00 -0800323static size_t tclas_elem_len(const struct tclas_element *elem)
324{
325 size_t buf_len = 0;
326
327 buf_len += 2 + /* TCLAS element header */
328 1 + /* User Priority */
329 1 ; /* Classifier Type */
330
331 if (elem->classifier_type == 4) {
332 enum ip_version ip_ver;
333
334 buf_len += 1 + /* Classifier mask */
335 1 + /* IP version */
336 1 + /* user priority */
337 2 + /* src_port */
338 2 + /* dst_port */
339 1 ; /* dscp */
340 ip_ver = elem->frame_classifier.type4_param.ip_version;
341 if (ip_ver == IPV4) {
342 buf_len += 4 + /* src_ip */
343 4 + /* dst_ip */
344 1 + /* protocol */
345 1 ; /* Reserved */
346 } else if (ip_ver == IPV6) {
347 buf_len += 16 + /* src_ip */
348 16 + /* dst_ip */
349 1 + /* next_header */
350 3 ; /* flow_label */
351 } else {
352 wpa_printf(MSG_ERROR, "%s: Incorrect IP version %d",
353 __func__, ip_ver);
354 return 0;
355 }
356 } else if (elem->classifier_type == 10) {
357 buf_len += 1 + /* protocol instance */
358 1 + /* protocol number */
359 2 * elem->frame_classifier.type10_param.filter_len;
360 } else {
361 wpa_printf(MSG_ERROR, "%s: Incorrect classifier type %u",
362 __func__, elem->classifier_type);
363 return 0;
364 }
365
366 return buf_len;
367}
368
369
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000370static size_t qos_char_len(const struct qos_characteristics *qos_elem)
371{
372 size_t buf_len = 0;
373
374 buf_len += 1 + /* Element ID */
375 1 + /* Length */
376 1 + /* Element ID Extension */
377 4 + /* Control Info */
378 4 + /* Minimum Service Interval */
379 4 + /* Maximum Service Interval */
380 3 + /* Minimum Data Rate */
381 3; /* Delay Bound */
382
383 if (qos_elem->mask & SCS_QOS_BIT_MAX_MSDU_SIZE)
384 buf_len += 2; /* Maximum MSDU Size */
385
386 if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME) {
387 buf_len += 4; /* Service Start Time */
388 if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID)
389 buf_len++; /* Service Start Time LinkID */
390 }
391
392 if (qos_elem->mask & SCS_QOS_BIT_MEAN_DATA_RATE)
393 buf_len += 3; /* Mean Data Rate */
394
395 if (qos_elem->mask & SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE)
396 buf_len += 4; /* Delayed Bounded Burst Size */
397
398 if (qos_elem->mask & SCS_QOS_BIT_MSDU_LIFETIME)
399 buf_len += 2; /* MSDU Lifetime */
400
401 if (qos_elem->mask & SCS_QOS_BIT_MSDU_DELIVERY_INFO)
402 buf_len++; /* MSDU Delivery Info */
403
404 if (qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME &&
405 qos_elem->direction == SCS_DIRECTION_DIRECT)
406 buf_len += 2; /* Medium Time */
407
408 return buf_len;
409}
410
411
Hai Shalomc1a21442022-02-04 13:43:00 -0800412static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000413 unsigned int num_scs_desc,
414 bool allow_scs_traffic_desc)
Hai Shalomc1a21442022-02-04 13:43:00 -0800415{
416 struct wpabuf *buf;
417 size_t buf_len = 0;
418 unsigned int i, j;
419
420 buf_len = 3; /* Action frame header */
421
422 for (i = 0; i < num_scs_desc; i++, desc_elem++) {
423 struct tclas_element *tclas_elem;
424
425 buf_len += 2 + /* SCS descriptor IE header */
426 1 + /* SCSID */
427 1 ; /* Request type */
428
429 if (desc_elem->request_type == SCS_REQ_REMOVE)
430 continue;
431
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000432 if (allow_scs_traffic_desc &&
433 desc_elem->qos_char_elem.available)
434 buf_len += qos_char_len(&desc_elem->qos_char_elem);
435
436 if (!tclas_elem_required(&desc_elem->qos_char_elem))
437 continue;
438
Hai Shalomc1a21442022-02-04 13:43:00 -0800439 if (desc_elem->intra_access_priority || desc_elem->scs_up_avail)
440 buf_len += 3;
441
442 tclas_elem = desc_elem->tclas_elems;
443 if (!tclas_elem) {
444 wpa_printf(MSG_ERROR, "%s: TCLAS element null",
445 __func__);
446 return NULL;
447 }
448
449 for (j = 0; j < desc_elem->num_tclas_elem; j++, tclas_elem++) {
450 size_t elen;
451
452 elen = tclas_elem_len(tclas_elem);
453 if (elen == 0)
454 return NULL;
455 buf_len += elen;
456 }
457
458 if (desc_elem->num_tclas_elem > 1) {
459 buf_len += 1 + /* TCLAS Processing eid */
460 1 + /* length */
461 1 ; /* processing */
462 }
463 }
464
465 buf = wpabuf_alloc(buf_len);
466 if (!buf) {
467 wpa_printf(MSG_ERROR, "Failed to allocate SCS req");
468 return NULL;
469 }
470
471 return buf;
472}
473
474
475static void scs_request_timer(void *eloop_ctx, void *timeout_ctx)
476{
477 struct wpa_supplicant *wpa_s = eloop_ctx;
478 struct active_scs_elem *scs_desc, *prev;
479
480 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
481 return;
482
483 /* Once timeout is over, remove all SCS descriptors with no response */
484 dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
485 struct active_scs_elem, list) {
486 u8 bssid[ETH_ALEN] = { 0 };
487 const u8 *src;
488
489 if (scs_desc->status == SCS_DESC_SUCCESS)
490 continue;
491
492 if (wpa_s->current_bss)
493 src = wpa_s->current_bss->bssid;
494 else
495 src = bssid;
496
497 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
498 " SCSID=%u status_code=timedout", MAC2STR(src),
499 scs_desc->scs_id);
500
501 dl_list_del(&scs_desc->list);
502 wpa_printf(MSG_INFO, "%s: SCSID %d removed after timeout",
503 __func__, scs_desc->scs_id);
504 os_free(scs_desc);
505 }
506
507 eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
508 wpa_s->ongoing_scs_req = false;
509}
510
511
512int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
513{
514 struct wpabuf *buf = NULL;
515 struct scs_desc_elem *desc_elem = NULL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000516 const struct ieee80211_eht_capabilities *eht;
517 const u8 *eht_ie;
Hai Shalomc1a21442022-02-04 13:43:00 -0800518 int ret = -1;
519 unsigned int i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000520 bool allow_scs_traffic_desc = false;
Hai Shalomc1a21442022-02-04 13:43:00 -0800521
522 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
523 return -1;
524
525 if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_SCS)) {
526 wpa_dbg(wpa_s, MSG_INFO,
527 "AP does not support SCS - could not send SCS Request");
528 return -1;
529 }
530
531 desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
532 if (!desc_elem)
533 return -1;
534
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000535 if (wpa_is_non_eht_scs_traffic_desc_supported(wpa_s->current_bss))
536 allow_scs_traffic_desc = true;
537
538 /* Allow SCS Traffic descriptor support for EHT connection */
539 eht_ie = wpa_bss_get_ie_ext(wpa_s->current_bss,
540 WLAN_EID_EXT_EHT_CAPABILITIES);
541 if (wpa_s->connection_eht && eht_ie &&
542 eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN) {
543 eht = (const struct ieee80211_eht_capabilities *) &eht_ie[3];
544 if (eht->mac_cap & EHT_MACCAP_SCS_TRAFFIC_DESC)
545 allow_scs_traffic_desc = true;
546 }
547
548 if (!allow_scs_traffic_desc && desc_elem->qos_char_elem.available) {
549 wpa_dbg(wpa_s, MSG_INFO,
550 "Connection does not support EHT/non-EHT SCS Traffic Description - could not send SCS Request with QoS Characteristics");
551 return -1;
552 }
553
Hai Shalomc1a21442022-02-04 13:43:00 -0800554 buf = allocate_scs_buf(desc_elem,
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000555 wpa_s->scs_robust_av_req.num_scs_desc,
556 allow_scs_traffic_desc);
Hai Shalomc1a21442022-02-04 13:43:00 -0800557 if (!buf)
558 return -1;
559
560 wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
561 wpabuf_put_u8(buf, ROBUST_AV_SCS_REQ);
562 wpa_s->scs_dialog_token++;
563 if (wpa_s->scs_dialog_token == 0)
564 wpa_s->scs_dialog_token++;
565 wpabuf_put_u8(buf, wpa_s->scs_dialog_token);
566
567 for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
568 i++, desc_elem++) {
569 /* SCS Descriptor element */
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000570 if (wpas_populate_scs_descriptor_ie(desc_elem, buf,
571 allow_scs_traffic_desc) < 0)
Hai Shalomc1a21442022-02-04 13:43:00 -0800572 goto end;
573 }
574
575 wpa_hexdump_buf(MSG_DEBUG, "SCS Request", buf);
576 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
577 wpa_s->own_addr, wpa_s->bssid,
578 wpabuf_head(buf), wpabuf_len(buf), 0);
579 if (ret < 0) {
580 wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request");
581 wpa_s->scs_dialog_token--;
582 goto end;
583 }
584
585 desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
586 for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
587 i++, desc_elem++) {
588 struct active_scs_elem *active_scs_elem;
589
590 if (desc_elem->request_type != SCS_REQ_ADD)
591 continue;
592
593 active_scs_elem = os_malloc(sizeof(struct active_scs_elem));
594 if (!active_scs_elem)
595 break;
596 active_scs_elem->scs_id = desc_elem->scs_id;
597 active_scs_elem->status = SCS_DESC_SENT;
598 dl_list_add(&wpa_s->active_scs_ids, &active_scs_elem->list);
599 }
600
601 /*
602 * Register a timeout after which this request will be removed from
603 * the cache.
604 */
605 eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s,
606 NULL);
607 wpa_s->ongoing_scs_req = true;
608
609end:
610 wpabuf_free(buf);
611 free_up_scs_desc(&wpa_s->scs_robust_av_req);
612
613 return ret;
614}
615
616
617void free_up_tclas_elem(struct scs_desc_elem *elem)
618{
619 struct tclas_element *tclas_elems = elem->tclas_elems;
620 unsigned int num_tclas_elem = elem->num_tclas_elem;
621 struct tclas_element *tclas_data;
622 unsigned int j;
623
624 elem->tclas_elems = NULL;
625 elem->num_tclas_elem = 0;
626
627 if (!tclas_elems)
628 return;
629
630 tclas_data = tclas_elems;
631 for (j = 0; j < num_tclas_elem; j++, tclas_data++) {
632 if (tclas_data->classifier_type != 10)
633 continue;
634
635 os_free(tclas_data->frame_classifier.type10_param.filter_value);
636 os_free(tclas_data->frame_classifier.type10_param.filter_mask);
637 }
638
639 os_free(tclas_elems);
640}
641
642
643void free_up_scs_desc(struct scs_robust_av_data *data)
644{
645 struct scs_desc_elem *desc_elems = data->scs_desc_elems;
646 unsigned int num_scs_desc = data->num_scs_desc;
647 struct scs_desc_elem *desc_data;
648 unsigned int i;
649
650 data->scs_desc_elems = NULL;
651 data->num_scs_desc = 0;
652
653 if (!desc_elems)
654 return;
655
656 desc_data = desc_elems;
657 for (i = 0; i < num_scs_desc; i++, desc_data++) {
658 if (desc_data->request_type == SCS_REQ_REMOVE ||
659 !desc_data->tclas_elems)
660 continue;
661
662 free_up_tclas_elem(desc_data);
663 }
664 os_free(desc_elems);
665}
666
667
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000668/* Element ID Extension(1) + Request Type(1) + User Priority Control(2) +
669 * Stream Timeout(4) */
670#define MSCS_DESCRIPTOR_FIXED_LEN 8
671
672static void wpas_parse_mscs_resp(struct wpa_supplicant *wpa_s,
673 u16 status, const u8 *bssid,
674 const u8 *mscs_desc_ie)
675{
676 struct robust_av_data robust_av;
677 const u8 *pos;
678
679 /* The MSCS Descriptor element is optional in the MSCS Response frame */
680 if (!mscs_desc_ie)
681 goto event_mscs_result;
682
683 if (mscs_desc_ie[1] < MSCS_DESCRIPTOR_FIXED_LEN) {
684 wpa_printf(MSG_INFO,
685 "MSCS: Drop received frame: invalid MSCS Descriptor element length: %d",
686 mscs_desc_ie[1]);
687 return;
688 }
689
690 os_memset(&robust_av, 0, sizeof(struct robust_av_data));
691
692 /* Skip Element ID, Length, and Element ID Extension */
693 pos = &mscs_desc_ie[3];
694
695 robust_av.request_type = *pos++;
696
697 switch (robust_av.request_type) {
698 case SCS_REQ_CHANGE:
699 /*
700 * Inform the suggested set of parameters that could be accepted
701 * by the AP in response to a subsequent request by the station.
702 */
703 robust_av.up_bitmap = *pos++;
704 robust_av.up_limit = *pos++ & 0x07;
705 robust_av.stream_timeout = WPA_GET_LE32(pos);
706 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
707 " status_code=%u change up_bitmap=%u up_limit=%u stream_timeout=%u",
708 MAC2STR(bssid), status, robust_av.up_bitmap,
709 robust_av.up_limit, robust_av.stream_timeout);
710 wpa_s->mscs_setup_done = false;
711 return;
712 case SCS_REQ_ADD:
713 /*
714 * This type is used in (Re)Association Response frame MSCS
715 * Descriptor element if no change is required.
716 */
717 break;
718 default:
719 wpa_printf(MSG_INFO,
720 "MSCS: Drop received frame with unknown Request Type: %u",
721 robust_av.request_type);
722 return;
723 }
724
725event_mscs_result:
726 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
727 " status_code=%u", MAC2STR(bssid), status);
728 wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
729}
730
731
Hai Shalom899fcc72020-10-19 14:38:18 -0700732void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
733 const u8 *src, const u8 *buf, size_t len)
734{
735 u8 dialog_token;
736 u16 status_code;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000737 const u8 *mscs_desc_ie;
Hai Shalom899fcc72020-10-19 14:38:18 -0700738
739 if (len < 3)
740 return;
741
742 dialog_token = *buf++;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000743 len--;
744
745 /* AP sets dialog token to 0 for unsolicited response */
746 if (!dialog_token && !wpa_s->mscs_setup_done) {
747 wpa_printf(MSG_INFO,
748 "MSCS: Drop unsolicited received frame: inactive");
749 return;
750 }
751
752 if (dialog_token && dialog_token != wpa_s->robust_av.dialog_token) {
Hai Shalom899fcc72020-10-19 14:38:18 -0700753 wpa_printf(MSG_INFO,
754 "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
755 dialog_token, wpa_s->robust_av.dialog_token);
756 return;
757 }
758
Hai Shalomc1a21442022-02-04 13:43:00 -0800759 status_code = WPA_GET_LE16(buf);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000760 buf += 2;
761 len -= 2;
762
763 mscs_desc_ie = get_ie_ext(buf, len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
764 wpas_parse_mscs_resp(wpa_s, status_code, src, mscs_desc_ie);
Hai Shalom899fcc72020-10-19 14:38:18 -0700765}
766
767
768void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
769 const u8 *ies, size_t ies_len)
770{
771 const u8 *mscs_desc_ie, *mscs_status;
772 u16 status;
773
774 /* Process optional MSCS Status subelement when MSCS IE is in
775 * (Re)Association Response frame */
776 if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
777 return;
778
779 mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000780 if (!mscs_desc_ie || mscs_desc_ie[1] <= MSCS_DESCRIPTOR_FIXED_LEN)
Hai Shalom899fcc72020-10-19 14:38:18 -0700781 return;
782
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000783 /* Subelements start after element header and fixed fields */
784 mscs_status = get_ie(&mscs_desc_ie[2 + MSCS_DESCRIPTOR_FIXED_LEN],
785 mscs_desc_ie[1] - MSCS_DESCRIPTOR_FIXED_LEN,
Hai Shalom899fcc72020-10-19 14:38:18 -0700786 MCSC_SUBELEM_STATUS);
787 if (!mscs_status || mscs_status[1] < 2)
788 return;
789
790 status = WPA_GET_LE16(mscs_status + 2);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000791
792 wpas_parse_mscs_resp(wpa_s, status, bssid, mscs_desc_ie);
Hai Shalom899fcc72020-10-19 14:38:18 -0700793}
Hai Shalomc1a21442022-02-04 13:43:00 -0800794
795
796static void wpas_wait_for_dscp_req_timer(void *eloop_ctx, void *timeout_ctx)
797{
798 struct wpa_supplicant *wpa_s = eloop_ctx;
799
800 /* Once timeout is over, reset wait flag and allow sending DSCP query */
801 wpa_printf(MSG_DEBUG,
802 "QM: Wait time over for sending DSCP request - allow DSCP query");
803 wpa_s->wait_for_dscp_req = 0;
804 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait end");
805}
806
807
808void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s,
809 const u8 *ies, size_t ies_len)
810{
811 const u8 *wfa_capa;
812
813 wpa_s->connection_dscp = 0;
814 if (wpa_s->wait_for_dscp_req)
815 eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
816
817 if (!ies || ies_len == 0 || !wpa_s->enable_dscp_policy_capa)
818 return;
819
820 wfa_capa = get_vendor_ie(ies, ies_len, WFA_CAPA_IE_VENDOR_TYPE);
821 if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 ||
822 !(wfa_capa[7] & WFA_CAPA_QM_DSCP_POLICY))
823 return; /* AP does not enable QM DSCP Policy */
824
825 wpa_s->connection_dscp = 1;
826 wpa_s->wait_for_dscp_req = !!(wfa_capa[7] &
827 WFA_CAPA_QM_UNSOLIC_DSCP);
828 if (!wpa_s->wait_for_dscp_req)
829 return;
830
831 /* Register a timeout after which dscp query can be sent to AP. */
832 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait start");
833 eloop_register_timeout(DSCP_REQ_TIMEOUT, 0,
834 wpas_wait_for_dscp_req_timer, wpa_s, NULL);
835}
836
837
838void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,
839 const u8 *src, const u8 *buf,
840 size_t len)
841{
842 u8 dialog_token;
Swarn Singhc450e7b2023-03-28 17:36:22 +0530843 unsigned int i, count, num_active_scs, j = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -0800844 struct active_scs_elem *scs_desc, *prev;
Swarn Singhc450e7b2023-03-28 17:36:22 +0530845 int *scs_resp[2];
Hai Shalomc1a21442022-02-04 13:43:00 -0800846
847 if (len < 2)
848 return;
849 if (!wpa_s->ongoing_scs_req) {
850 wpa_printf(MSG_INFO,
851 "SCS: Drop received response due to no ongoing request");
852 return;
853 }
854
855 dialog_token = *buf++;
856 len--;
857 if (dialog_token != wpa_s->scs_dialog_token) {
858 wpa_printf(MSG_INFO,
859 "SCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
860 dialog_token, wpa_s->scs_dialog_token);
861 return;
862 }
863
864 /* This Count field does not exist in the IEEE Std 802.11-2020
865 * definition of the SCS Response frame. However, it was accepted to
866 * be added into REVme per REVme/D0.0 CC35 CID 49 (edits in document
867 * 11-21-0688-07). */
868 count = *buf++;
869 len--;
870 if (count == 0 || count * 3 > len) {
871 wpa_printf(MSG_INFO,
872 "SCS: Drop received frame due to invalid count: %u (remaining %zu octets)",
873 count, len);
874 return;
875 }
876
Swarn Singhc450e7b2023-03-28 17:36:22 +0530877 num_active_scs = dl_list_len(&wpa_s->active_scs_ids);
878 if (num_active_scs < count) {
879 wpa_printf(MSG_ERROR, "Unexpected number of SCS responses."
880 " Expected < %d, received %d", num_active_scs, count);
881 return;
882 }
883
884 scs_resp[0] = (int *) os_zalloc(num_active_scs);
885 if (!scs_resp[0]) {
886 wpa_printf(MSG_ERROR, "Failed to allocate memory for scs_resp");
887 return;
888 }
889
890 scs_resp[1] = (int *) os_zalloc(num_active_scs);
891 if (!scs_resp[1]) {
892 os_free(scs_resp[0]);
893 wpa_printf(MSG_ERROR, "Failed to allocate memory for scs_resp");
894 return;
895 }
896
Hai Shalomc1a21442022-02-04 13:43:00 -0800897 for (i = 0; i < count; i++) {
898 u8 id;
899 u16 status;
900 bool scs_desc_found = false;
901
902 id = *buf++;
903 status = WPA_GET_LE16(buf);
904 buf += 2;
905 len -= 3;
906
907 dl_list_for_each(scs_desc, &wpa_s->active_scs_ids,
908 struct active_scs_elem, list) {
909 if (id == scs_desc->scs_id) {
910 scs_desc_found = true;
911 break;
912 }
913 }
914
915 if (!scs_desc_found) {
916 wpa_printf(MSG_INFO, "SCS: SCS ID invalid %u", id);
917 continue;
918 }
919
920 if (status != WLAN_STATUS_SUCCESS) {
921 dl_list_del(&scs_desc->list);
922 os_free(scs_desc);
923 } else if (status == WLAN_STATUS_SUCCESS) {
924 scs_desc->status = SCS_DESC_SUCCESS;
925 }
926
927 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
928 " SCSID=%u status_code=%u", MAC2STR(src), id, status);
Swarn Singhc450e7b2023-03-28 17:36:22 +0530929 scs_resp[0][j] = id;
930 scs_resp[1][j++] = status;
Hai Shalomc1a21442022-02-04 13:43:00 -0800931 }
932
933 eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
934 wpa_s->ongoing_scs_req = false;
935
936 dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
937 struct active_scs_elem, list) {
938 if (scs_desc->status != SCS_DESC_SUCCESS) {
939 wpa_msg(wpa_s, MSG_INFO,
940 WPA_EVENT_SCS_RESULT "bssid=" MACSTR
941 " SCSID=%u status_code=response_not_received",
942 MAC2STR(src), scs_desc->scs_id);
Swarn Singhc450e7b2023-03-28 17:36:22 +0530943 if (j < num_active_scs) {
944 scs_resp[0][j] = scs_desc->scs_id;
945 scs_resp[1][j++] = -1; /* TIMEOUT indicator for AIDL */
946 }
Hai Shalomc1a21442022-02-04 13:43:00 -0800947 dl_list_del(&scs_desc->list);
948 os_free(scs_desc);
949 }
950 }
Swarn Singhc450e7b2023-03-28 17:36:22 +0530951 wpas_notify_qos_policy_scs_response(wpa_s, j, scs_resp);
952 os_free(scs_resp[0]);
953 os_free(scs_resp[1]);
Hai Shalomc1a21442022-02-04 13:43:00 -0800954}
955
956
957static void wpas_clear_active_scs_ids(struct wpa_supplicant *wpa_s)
958{
959 struct active_scs_elem *scs_elem;
960
961 while ((scs_elem = dl_list_first(&wpa_s->active_scs_ids,
962 struct active_scs_elem, list))) {
963 dl_list_del(&scs_elem->list);
964 os_free(scs_elem);
965 }
966}
967
968
969void wpas_scs_deinit(struct wpa_supplicant *wpa_s)
970{
971 free_up_scs_desc(&wpa_s->scs_robust_av_req);
972 wpa_s->scs_dialog_token = 0;
973 wpas_clear_active_scs_ids(wpa_s);
974 eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
975 wpa_s->ongoing_scs_req = false;
976}
977
978
979static int write_ipv4_info(char *pos, int total_len,
Sunil Ravi89eba102022-09-13 21:04:37 -0700980 const struct ipv4_params *v4,
981 u8 classifier_mask)
Hai Shalomc1a21442022-02-04 13:43:00 -0800982{
983 int res, rem_len;
984 char addr[INET_ADDRSTRLEN];
985
986 rem_len = total_len;
987
Sunil Ravi89eba102022-09-13 21:04:37 -0700988 if (classifier_mask & BIT(1)) {
Hai Shalomc1a21442022-02-04 13:43:00 -0800989 if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) {
990 wpa_printf(MSG_ERROR,
991 "QM: Failed to set IPv4 source address");
992 return -1;
993 }
994
995 res = os_snprintf(pos, rem_len, " src_ip=%s", addr);
996 if (os_snprintf_error(rem_len, res))
997 return -1;
998
999 pos += res;
1000 rem_len -= res;
1001 }
1002
Sunil Ravi89eba102022-09-13 21:04:37 -07001003 if (classifier_mask & BIT(2)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001004 if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) {
1005 wpa_printf(MSG_ERROR,
1006 "QM: Failed to set IPv4 destination address");
1007 return -1;
1008 }
1009
1010 res = os_snprintf(pos, rem_len, " dst_ip=%s", addr);
1011 if (os_snprintf_error(rem_len, res))
1012 return -1;
1013
1014 pos += res;
1015 rem_len -= res;
1016 }
1017
Sunil Ravi89eba102022-09-13 21:04:37 -07001018 if (classifier_mask & BIT(3)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001019 res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port);
1020 if (os_snprintf_error(rem_len, res))
1021 return -1;
1022
1023 pos += res;
1024 rem_len -= res;
1025 }
1026
Sunil Ravi89eba102022-09-13 21:04:37 -07001027 if (classifier_mask & BIT(4)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001028 res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port);
1029 if (os_snprintf_error(rem_len, res))
1030 return -1;
1031
1032 pos += res;
1033 rem_len -= res;
1034 }
1035
Sunil Ravi89eba102022-09-13 21:04:37 -07001036 if (classifier_mask & BIT(6)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001037 res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol);
1038 if (os_snprintf_error(rem_len, res))
1039 return -1;
1040
1041 pos += res;
1042 rem_len -= res;
1043 }
1044
1045 return total_len - rem_len;
1046}
1047
1048
1049static int write_ipv6_info(char *pos, int total_len,
Sunil Ravi89eba102022-09-13 21:04:37 -07001050 const struct ipv6_params *v6,
1051 u8 classifier_mask)
Hai Shalomc1a21442022-02-04 13:43:00 -08001052{
1053 int res, rem_len;
1054 char addr[INET6_ADDRSTRLEN];
1055
1056 rem_len = total_len;
1057
Sunil Ravi89eba102022-09-13 21:04:37 -07001058 if (classifier_mask & BIT(1)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001059 if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) {
1060 wpa_printf(MSG_ERROR,
1061 "QM: Failed to set IPv6 source addr");
1062 return -1;
1063 }
1064
1065 res = os_snprintf(pos, rem_len, " src_ip=%s", addr);
1066 if (os_snprintf_error(rem_len, res))
1067 return -1;
1068
1069 pos += res;
1070 rem_len -= res;
1071 }
1072
Sunil Ravi89eba102022-09-13 21:04:37 -07001073 if (classifier_mask & BIT(2)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001074 if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) {
1075 wpa_printf(MSG_ERROR,
1076 "QM: Failed to set IPv6 destination addr");
1077 return -1;
1078 }
1079
1080 res = os_snprintf(pos, rem_len, " dst_ip=%s", addr);
1081 if (os_snprintf_error(rem_len, res))
1082 return -1;
1083
1084 pos += res;
1085 rem_len -= res;
1086 }
1087
Sunil Ravi89eba102022-09-13 21:04:37 -07001088 if (classifier_mask & BIT(3)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001089 res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port);
1090 if (os_snprintf_error(rem_len, res))
1091 return -1;
1092
1093 pos += res;
1094 rem_len -= res;
1095 }
1096
Sunil Ravi89eba102022-09-13 21:04:37 -07001097 if (classifier_mask & BIT(4)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001098 res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port);
1099 if (os_snprintf_error(rem_len, res))
1100 return -1;
1101
1102 pos += res;
1103 rem_len -= res;
1104 }
1105
Sunil Ravi89eba102022-09-13 21:04:37 -07001106 if (classifier_mask & BIT(6)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001107 res = os_snprintf(pos, rem_len, " protocol=%d",
1108 v6->next_header);
1109 if (os_snprintf_error(rem_len, res))
1110 return -1;
1111
1112 pos += res;
1113 rem_len -= res;
1114 }
1115
1116 return total_len - rem_len;
1117}
1118
1119
Hai Shalomc1a21442022-02-04 13:43:00 -08001120static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy)
1121{
1122 u8 classifier_mask;
1123 const u8 *frame_classifier = policy->frame_classifier;
1124 struct type4_params *type4_param = &policy->type4_param;
1125
1126 if (policy->frame_classifier_len < 18) {
1127 wpa_printf(MSG_ERROR,
1128 "QM: Received IPv4 frame classifier with insufficient length %d",
1129 policy->frame_classifier_len);
1130 return -1;
1131 }
1132
1133 classifier_mask = frame_classifier[1];
1134
1135 /* Classifier Mask - bit 1 = Source IP Address */
1136 if (classifier_mask & BIT(1)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001137 type4_param->classifier_mask |= BIT(1);
Hai Shalomc1a21442022-02-04 13:43:00 -08001138 os_memcpy(&type4_param->ip_params.v4.src_ip,
1139 &frame_classifier[3], 4);
1140 }
1141
1142 /* Classifier Mask - bit 2 = Destination IP Address */
1143 if (classifier_mask & BIT(2)) {
1144 if (policy->domain_name) {
1145 wpa_printf(MSG_ERROR,
1146 "QM: IPv4: Both domain name and destination IP address not expected");
1147 return -1;
1148 }
1149
Sunil Ravi89eba102022-09-13 21:04:37 -07001150 type4_param->classifier_mask |= BIT(2);
Hai Shalomc1a21442022-02-04 13:43:00 -08001151 os_memcpy(&type4_param->ip_params.v4.dst_ip,
1152 &frame_classifier[7], 4);
1153 }
1154
1155 /* Classifier Mask - bit 3 = Source Port */
1156 if (classifier_mask & BIT(3)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001157 type4_param->classifier_mask |= BIT(3);
Hai Shalomc1a21442022-02-04 13:43:00 -08001158 type4_param->ip_params.v4.src_port =
1159 WPA_GET_BE16(&frame_classifier[11]);
1160 }
1161
1162 /* Classifier Mask - bit 4 = Destination Port */
1163 if (classifier_mask & BIT(4)) {
1164 if (policy->port_range_info) {
1165 wpa_printf(MSG_ERROR,
1166 "QM: IPv4: Both port range and destination port not expected");
1167 return -1;
1168 }
1169
Sunil Ravi89eba102022-09-13 21:04:37 -07001170 type4_param->classifier_mask |= BIT(4);
Hai Shalomc1a21442022-02-04 13:43:00 -08001171 type4_param->ip_params.v4.dst_port =
1172 WPA_GET_BE16(&frame_classifier[13]);
1173 }
1174
1175 /* Classifier Mask - bit 5 = DSCP (ignored) */
1176
1177 /* Classifier Mask - bit 6 = Protocol */
1178 if (classifier_mask & BIT(6)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001179 type4_param->classifier_mask |= BIT(6);
Hai Shalomc1a21442022-02-04 13:43:00 -08001180 type4_param->ip_params.v4.protocol = frame_classifier[16];
1181 }
1182
1183 return 0;
1184}
1185
1186
1187static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy)
1188{
1189 u8 classifier_mask;
1190 const u8 *frame_classifier = policy->frame_classifier;
1191 struct type4_params *type4_param = &policy->type4_param;
1192
1193 if (policy->frame_classifier_len < 44) {
1194 wpa_printf(MSG_ERROR,
1195 "QM: Received IPv6 frame classifier with insufficient length %d",
1196 policy->frame_classifier_len);
1197 return -1;
1198 }
1199
1200 classifier_mask = frame_classifier[1];
1201
1202 /* Classifier Mask - bit 1 = Source IP Address */
1203 if (classifier_mask & BIT(1)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001204 type4_param->classifier_mask |= BIT(1);
Hai Shalomc1a21442022-02-04 13:43:00 -08001205 os_memcpy(&type4_param->ip_params.v6.src_ip,
1206 &frame_classifier[3], 16);
1207 }
1208
1209 /* Classifier Mask - bit 2 = Destination IP Address */
1210 if (classifier_mask & BIT(2)) {
1211 if (policy->domain_name) {
1212 wpa_printf(MSG_ERROR,
1213 "QM: IPv6: Both domain name and destination IP address not expected");
1214 return -1;
1215 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001216 type4_param->classifier_mask |= BIT(2);
Hai Shalomc1a21442022-02-04 13:43:00 -08001217 os_memcpy(&type4_param->ip_params.v6.dst_ip,
1218 &frame_classifier[19], 16);
1219 }
1220
1221 /* Classifier Mask - bit 3 = Source Port */
1222 if (classifier_mask & BIT(3)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001223 type4_param->classifier_mask |= BIT(3);
Hai Shalomc1a21442022-02-04 13:43:00 -08001224 type4_param->ip_params.v6.src_port =
1225 WPA_GET_BE16(&frame_classifier[35]);
1226 }
1227
1228 /* Classifier Mask - bit 4 = Destination Port */
1229 if (classifier_mask & BIT(4)) {
1230 if (policy->port_range_info) {
1231 wpa_printf(MSG_ERROR,
1232 "IPv6: Both port range and destination port not expected");
1233 return -1;
1234 }
1235
Sunil Ravi89eba102022-09-13 21:04:37 -07001236 type4_param->classifier_mask |= BIT(4);
Hai Shalomc1a21442022-02-04 13:43:00 -08001237 type4_param->ip_params.v6.dst_port =
1238 WPA_GET_BE16(&frame_classifier[37]);
1239 }
1240
1241 /* Classifier Mask - bit 5 = DSCP (ignored) */
1242
1243 /* Classifier Mask - bit 6 = Next Header */
1244 if (classifier_mask & BIT(6)) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001245 type4_param->classifier_mask |= BIT(6);
Hai Shalomc1a21442022-02-04 13:43:00 -08001246 type4_param->ip_params.v6.next_header = frame_classifier[40];
1247 }
1248
1249 return 0;
1250}
1251
1252
1253static int wpas_set_frame_classifier_params(struct dscp_policy_data *policy)
1254{
1255 const u8 *frame_classifier = policy->frame_classifier;
1256 u8 frame_classifier_len = policy->frame_classifier_len;
1257
1258 if (frame_classifier_len < 3) {
1259 wpa_printf(MSG_ERROR,
1260 "QM: Received frame classifier with insufficient length %d",
1261 frame_classifier_len);
1262 return -1;
1263 }
1264
1265 /* Only allowed Classifier Type: IP and higher layer parameters (4) */
1266 if (frame_classifier[0] != 4) {
1267 wpa_printf(MSG_ERROR,
1268 "QM: Received frame classifier with invalid classifier type %d",
1269 frame_classifier[0]);
1270 return -1;
1271 }
1272
1273 /* Classifier Mask - bit 0 = Version */
1274 if (!(frame_classifier[1] & BIT(0))) {
1275 wpa_printf(MSG_ERROR,
1276 "QM: Received frame classifier without IP version");
1277 return -1;
1278 }
1279
1280 /* Version (4 or 6) */
1281 if (frame_classifier[2] == 4) {
1282 if (set_frame_classifier_type4_ipv4(policy)) {
1283 wpa_printf(MSG_ERROR,
1284 "QM: Failed to set IPv4 parameters");
1285 return -1;
1286 }
1287
1288 policy->type4_param.ip_version = IPV4;
1289 } else if (frame_classifier[2] == 6) {
1290 if (set_frame_classifier_type4_ipv6(policy)) {
1291 wpa_printf(MSG_ERROR,
1292 "QM: Failed to set IPv6 parameters");
1293 return -1;
1294 }
1295
1296 policy->type4_param.ip_version = IPV6;
1297 } else {
1298 wpa_printf(MSG_ERROR,
1299 "QM: Received unknown IP version %d",
1300 frame_classifier[2]);
1301 return -1;
1302 }
1303
1304 return 0;
1305}
1306
1307
1308static bool dscp_valid_domain_name(const char *str)
1309{
1310 if (!str[0])
1311 return false;
1312
1313 while (*str) {
1314 if (is_ctrl_char(*str) || *str == ' ' || *str == '=')
1315 return false;
1316 str++;
1317 }
1318
1319 return true;
1320}
1321
1322
Shivani Baranwal84940f82022-02-02 10:21:47 +05301323static int wpas_add_dscp_policy(struct wpa_supplicant *wpa_s,
Hai Shalomc1a21442022-02-04 13:43:00 -08001324 struct dscp_policy_data *policy)
1325{
1326 int ip_ver = 0, res;
1327 char policy_str[1000], *pos;
1328 int len;
1329
1330 if (!policy->frame_classifier && !policy->domain_name &&
1331 !policy->port_range_info) {
1332 wpa_printf(MSG_ERROR,
1333 "QM: Invalid DSCP policy - no attributes present");
1334 goto fail;
1335 }
1336
1337 policy_str[0] = '\0';
1338 pos = policy_str;
1339 len = sizeof(policy_str);
1340
1341 if (policy->frame_classifier) {
1342 struct type4_params *type4 = &policy->type4_param;
1343
1344 if (wpas_set_frame_classifier_params(policy)) {
1345 wpa_printf(MSG_ERROR,
1346 "QM: Failed to set frame classifier parameters");
1347 goto fail;
1348 }
1349
1350 if (type4->ip_version == IPV4)
Sunil Ravi89eba102022-09-13 21:04:37 -07001351 res = write_ipv4_info(pos, len, &type4->ip_params.v4,
1352 type4->classifier_mask);
Hai Shalomc1a21442022-02-04 13:43:00 -08001353 else
Sunil Ravi89eba102022-09-13 21:04:37 -07001354 res = write_ipv6_info(pos, len, &type4->ip_params.v6,
1355 type4->classifier_mask);
Hai Shalomc1a21442022-02-04 13:43:00 -08001356
1357 if (res <= 0) {
1358 wpa_printf(MSG_ERROR,
1359 "QM: Failed to write IP parameters");
1360 goto fail;
1361 }
1362
1363 ip_ver = type4->ip_version;
1364
1365 pos += res;
1366 len -= res;
1367 }
1368
1369 if (policy->port_range_info) {
1370 res = os_snprintf(pos, len, " start_port=%u end_port=%u",
1371 policy->start_port, policy->end_port);
1372 if (os_snprintf_error(len, res)) {
1373 wpa_printf(MSG_ERROR,
1374 "QM: Failed to write port range attributes for policy id = %d",
1375 policy->policy_id);
1376 goto fail;
1377 }
1378
1379 pos += res;
1380 len -= res;
1381 }
1382
1383 if (policy->domain_name) {
1384 char domain_name_str[250];
1385
1386 if (policy->domain_name_len >= sizeof(domain_name_str)) {
1387 wpa_printf(MSG_ERROR,
1388 "QM: Domain name length higher than max expected");
1389 goto fail;
1390 }
1391 os_memcpy(domain_name_str, policy->domain_name,
1392 policy->domain_name_len);
1393 domain_name_str[policy->domain_name_len] = '\0';
1394 if (!dscp_valid_domain_name(domain_name_str)) {
1395 wpa_printf(MSG_ERROR, "QM: Invalid domain name string");
1396 goto fail;
1397 }
1398 res = os_snprintf(pos, len, " domain_name=%s", domain_name_str);
1399 if (os_snprintf_error(len, res)) {
1400 wpa_printf(MSG_ERROR,
1401 "QM: Failed to write domain name attribute for policy id = %d",
1402 policy->policy_id);
1403 goto fail;
1404 }
1405 }
1406
1407 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
1408 "add policy_id=%u dscp=%u ip_version=%d%s",
1409 policy->policy_id, policy->dscp, ip_ver, policy_str);
Shivani Baranwal84940f82022-02-02 10:21:47 +05301410 return 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08001411fail:
1412 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "reject policy_id=%u",
1413 policy->policy_id);
Shivani Baranwal84940f82022-02-02 10:21:47 +05301414 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08001415}
1416
1417
1418void wpas_dscp_deinit(struct wpa_supplicant *wpa_s)
1419{
1420 wpa_printf(MSG_DEBUG, "QM: Clear all active DSCP policies");
1421 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "clear_all");
1422 wpa_s->dscp_req_dialog_token = 0;
1423 wpa_s->dscp_query_dialog_token = 0;
1424 wpa_s->connection_dscp = 0;
1425 if (wpa_s->wait_for_dscp_req) {
1426 wpa_s->wait_for_dscp_req = 0;
1427 eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
1428 }
1429}
1430
1431
1432static void wpas_fill_dscp_policy(struct dscp_policy_data *policy, u8 attr_id,
1433 u8 attr_len, const u8 *attr_data)
1434{
1435 switch (attr_id) {
1436 case QM_ATTR_PORT_RANGE:
1437 if (attr_len < 4) {
1438 wpa_printf(MSG_ERROR,
1439 "QM: Received Port Range attribute with insufficient length %d",
1440 attr_len);
1441 break;
1442 }
1443 policy->start_port = WPA_GET_BE16(attr_data);
1444 policy->end_port = WPA_GET_BE16(attr_data + 2);
1445 policy->port_range_info = true;
1446 break;
1447 case QM_ATTR_DSCP_POLICY:
1448 if (attr_len < 3) {
1449 wpa_printf(MSG_ERROR,
1450 "QM: Received DSCP Policy attribute with insufficient length %d",
1451 attr_len);
1452 return;
1453 }
1454 policy->policy_id = attr_data[0];
1455 policy->req_type = attr_data[1];
1456 policy->dscp = attr_data[2];
1457 policy->dscp_info = true;
1458 break;
1459 case QM_ATTR_TCLAS:
1460 if (attr_len < 1) {
1461 wpa_printf(MSG_ERROR,
1462 "QM: Received TCLAS attribute with insufficient length %d",
1463 attr_len);
1464 return;
1465 }
1466 policy->frame_classifier = attr_data;
1467 policy->frame_classifier_len = attr_len;
1468 break;
1469 case QM_ATTR_DOMAIN_NAME:
1470 if (attr_len < 1) {
1471 wpa_printf(MSG_ERROR,
1472 "QM: Received domain name attribute with insufficient length %d",
1473 attr_len);
1474 return;
1475 }
1476 policy->domain_name = attr_data;
1477 policy->domain_name_len = attr_len;
1478 break;
1479 default:
1480 wpa_printf(MSG_ERROR, "QM: Received invalid QoS attribute %d",
1481 attr_id);
1482 break;
1483 }
1484}
1485
1486
1487void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s,
1488 const u8 *src,
1489 const u8 *buf, size_t len)
1490{
1491 int rem_len;
1492 const u8 *qos_ie, *attr;
1493 int more, reset;
1494
Shivani Baranwal84940f82022-02-02 10:21:47 +05301495 struct dscp_policy_data *policies = NULL, *policies_temp;
1496 int num_dscp_policies = 0;
1497
Hai Shalomc1a21442022-02-04 13:43:00 -08001498 if (!wpa_s->enable_dscp_policy_capa) {
1499 wpa_printf(MSG_ERROR,
1500 "QM: Ignore DSCP Policy frame since the capability is not enabled");
1501 return;
1502 }
1503
1504 if (!pmf_in_use(wpa_s, src)) {
1505 wpa_printf(MSG_ERROR,
1506 "QM: Ignore DSCP Policy frame since PMF is not in use");
1507 return;
1508 }
1509
1510 if (!wpa_s->connection_dscp) {
1511 wpa_printf(MSG_DEBUG,
1512 "QM: DSCP Policy capability not enabled for the current association - ignore QoS Management Action frames");
1513 return;
1514 }
1515
1516 if (len < 1)
1517 return;
1518
1519 /* Handle only DSCP Policy Request frame */
1520 if (buf[0] != QM_DSCP_POLICY_REQ) {
1521 wpa_printf(MSG_ERROR, "QM: Received unexpected QoS action frame %d",
1522 buf[0]);
1523 return;
1524 }
1525
1526 if (len < 3) {
1527 wpa_printf(MSG_ERROR,
1528 "Received QoS Management DSCP Policy Request frame with invalid length %zu",
1529 len);
1530 return;
1531 }
1532
1533 /* Clear wait_for_dscp_req on receiving first DSCP request from AP */
1534 if (wpa_s->wait_for_dscp_req) {
1535 wpa_s->wait_for_dscp_req = 0;
1536 eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
1537 }
1538
1539 wpa_s->dscp_req_dialog_token = buf[1];
1540 more = buf[2] & DSCP_POLICY_CTRL_MORE;
1541 reset = buf[2] & DSCP_POLICY_CTRL_RESET;
1542
Shivani Baranwal84940f82022-02-02 10:21:47 +05301543 if (reset)
1544 wpas_notify_qos_policy_reset(wpa_s);
1545
Hai Shalomc1a21442022-02-04 13:43:00 -08001546 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_start%s%s",
1547 reset ? " clear_all" : "", more ? " more" : "");
1548
1549 qos_ie = buf + 3;
1550 rem_len = len - 3;
1551 while (rem_len > 2) {
1552 struct dscp_policy_data policy;
Shivani Baranwal84940f82022-02-02 10:21:47 +05301553 int res = 0;
Hai Shalomc1a21442022-02-04 13:43:00 -08001554 int rem_attrs_len, ie_len;
1555
1556 ie_len = 2 + qos_ie[1];
1557 if (rem_len < ie_len)
1558 break;
1559
1560 if (rem_len < 6 || qos_ie[0] != WLAN_EID_VENDOR_SPECIFIC ||
1561 qos_ie[1] < 4 ||
1562 WPA_GET_BE32(&qos_ie[2]) != QM_IE_VENDOR_TYPE) {
1563 rem_len -= ie_len;
1564 qos_ie += ie_len;
1565 continue;
1566 }
1567
1568 os_memset(&policy, 0, sizeof(struct dscp_policy_data));
1569 attr = qos_ie + 6;
1570 rem_attrs_len = qos_ie[1] - 4;
1571
Sunil8cd6f4d2022-06-28 18:40:46 +00001572 while (rem_attrs_len > 2) {
1573 u8 attr_id, attr_len;
1574
1575 attr_id = *attr++;
1576 attr_len = *attr++;
1577 rem_attrs_len -= 2;
1578 if (attr_len > rem_attrs_len)
1579 break;
1580 wpas_fill_dscp_policy(&policy, attr_id, attr_len, attr);
1581 rem_attrs_len -= attr_len;
1582 attr += attr_len;
Hai Shalomc1a21442022-02-04 13:43:00 -08001583 }
1584
1585 rem_len -= ie_len;
1586 qos_ie += ie_len;
1587
1588 if (!policy.dscp_info) {
1589 wpa_printf(MSG_ERROR,
1590 "QM: Received QoS IE without DSCP Policy attribute");
1591 continue;
1592 }
1593
1594 if (policy.req_type == DSCP_POLICY_REQ_ADD)
Shivani Baranwal84940f82022-02-02 10:21:47 +05301595 res = wpas_add_dscp_policy(wpa_s, &policy);
Hai Shalomc1a21442022-02-04 13:43:00 -08001596 else if (policy.req_type == DSCP_POLICY_REQ_REMOVE)
1597 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
1598 "remove policy_id=%u", policy.policy_id);
Shivani Baranwal84940f82022-02-02 10:21:47 +05301599 else {
Hai Shalomc1a21442022-02-04 13:43:00 -08001600 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
1601 "reject policy_id=%u", policy.policy_id);
Shivani Baranwal84940f82022-02-02 10:21:47 +05301602 res = -1;
1603 }
1604
1605 if (res)
1606 continue;
1607
1608 policies_temp = os_realloc(policies,
1609 (num_dscp_policies + 1) *
1610 sizeof(struct dscp_policy_data));
1611 if (!policies_temp)
1612 goto fail;
1613
1614 policies = policies_temp;
1615 policies[num_dscp_policies] = policy;
1616 num_dscp_policies++;
Hai Shalomc1a21442022-02-04 13:43:00 -08001617 }
1618
Shivani Baranwal84940f82022-02-02 10:21:47 +05301619 wpas_notify_qos_policy_request(wpa_s, policies, num_dscp_policies);
1620
Hai Shalomc1a21442022-02-04 13:43:00 -08001621 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_end");
Shivani Baranwal84940f82022-02-02 10:21:47 +05301622
1623fail:
1624 os_free(policies);
1625 return;
Hai Shalomc1a21442022-02-04 13:43:00 -08001626}
1627
1628
1629int wpas_send_dscp_response(struct wpa_supplicant *wpa_s,
1630 struct dscp_resp_data *resp_data)
1631{
1632 struct wpabuf *buf = NULL;
1633 size_t buf_len;
1634 int ret = -1, i;
1635 u8 resp_control = 0;
1636
1637 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
1638 wpa_printf(MSG_ERROR,
1639 "QM: Failed to send DSCP response - not connected to AP");
1640 return -1;
1641 }
1642
1643 if (resp_data->solicited && !wpa_s->dscp_req_dialog_token) {
1644 wpa_printf(MSG_ERROR, "QM: No ongoing DSCP request");
1645 return -1;
1646 }
1647
1648 if (!wpa_s->connection_dscp) {
1649 wpa_printf(MSG_ERROR,
1650 "QM: Failed to send DSCP response - DSCP capability not enabled for the current association");
1651 return -1;
1652
1653 }
1654
1655 buf_len = 1 + /* Category */
1656 3 + /* OUI */
1657 1 + /* OUI Type */
1658 1 + /* OUI Subtype */
1659 1 + /* Dialog Token */
1660 1 + /* Response Control */
1661 1 + /* Count */
1662 2 * resp_data->num_policies; /* Status list */
1663 buf = wpabuf_alloc(buf_len);
1664 if (!buf) {
1665 wpa_printf(MSG_ERROR,
1666 "QM: Failed to allocate DSCP policy response");
1667 return -1;
1668 }
1669
1670 wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
1671 wpabuf_put_be24(buf, OUI_WFA);
1672 wpabuf_put_u8(buf, QM_ACTION_OUI_TYPE);
1673 wpabuf_put_u8(buf, QM_DSCP_POLICY_RESP);
1674
1675 wpabuf_put_u8(buf, resp_data->solicited ?
1676 wpa_s->dscp_req_dialog_token : 0);
1677
1678 if (resp_data->more)
1679 resp_control |= DSCP_POLICY_CTRL_MORE;
1680 if (resp_data->reset)
1681 resp_control |= DSCP_POLICY_CTRL_RESET;
1682 wpabuf_put_u8(buf, resp_control);
1683
1684 wpabuf_put_u8(buf, resp_data->num_policies);
1685 for (i = 0; i < resp_data->num_policies; i++) {
1686 wpabuf_put_u8(buf, resp_data->policy[i].id);
1687 wpabuf_put_u8(buf, resp_data->policy[i].status);
1688 }
1689
1690 wpa_hexdump_buf(MSG_MSGDUMP, "DSCP response frame: ", buf);
1691 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
1692 wpa_s->own_addr, wpa_s->bssid,
1693 wpabuf_head(buf), wpabuf_len(buf), 0);
1694 if (ret < 0) {
1695 wpa_msg(wpa_s, MSG_INFO, "QM: Failed to send DSCP response");
1696 goto fail;
1697 }
1698
1699 /*
1700 * Mark DSCP request complete whether response sent is solicited or
1701 * unsolicited
1702 */
1703 wpa_s->dscp_req_dialog_token = 0;
1704
1705fail:
1706 wpabuf_free(buf);
1707 return ret;
1708}
1709
1710
1711int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name,
1712 size_t domain_name_length)
1713{
1714 struct wpabuf *buf = NULL;
1715 int ret, dscp_query_size;
1716
1717 if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
1718 return -1;
1719
1720 if (!wpa_s->connection_dscp) {
1721 wpa_printf(MSG_ERROR,
1722 "QM: Failed to send DSCP query - DSCP capability not enabled for the current association");
1723 return -1;
1724 }
1725
1726 if (wpa_s->wait_for_dscp_req) {
1727 wpa_printf(MSG_INFO, "QM: Wait until AP sends a DSCP request");
1728 return -1;
1729 }
1730
1731#define DOMAIN_NAME_OFFSET (4 /* OUI */ + 1 /* Attr Id */ + 1 /* Attr len */)
1732
1733 if (domain_name_length > 255 - DOMAIN_NAME_OFFSET) {
1734 wpa_printf(MSG_ERROR, "QM: Too long domain name");
1735 return -1;
1736 }
1737
1738 dscp_query_size = 1 + /* Category */
1739 4 + /* OUI Type */
1740 1 + /* OUI subtype */
1741 1; /* Dialog Token */
1742 if (domain_name && domain_name_length)
1743 dscp_query_size += 1 + /* Element ID */
1744 1 + /* IE Length */
1745 DOMAIN_NAME_OFFSET + domain_name_length;
1746
1747 buf = wpabuf_alloc(dscp_query_size);
1748 if (!buf) {
1749 wpa_printf(MSG_ERROR, "QM: Failed to allocate DSCP query");
1750 return -1;
1751 }
1752
1753 wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
1754 wpabuf_put_be32(buf, QM_ACTION_VENDOR_TYPE);
1755 wpabuf_put_u8(buf, QM_DSCP_POLICY_QUERY);
1756 wpa_s->dscp_query_dialog_token++;
1757 if (wpa_s->dscp_query_dialog_token == 0)
1758 wpa_s->dscp_query_dialog_token++;
1759 wpabuf_put_u8(buf, wpa_s->dscp_query_dialog_token);
1760
1761 if (domain_name && domain_name_length) {
1762 /* Domain Name attribute */
1763 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
1764 wpabuf_put_u8(buf, DOMAIN_NAME_OFFSET + domain_name_length);
1765 wpabuf_put_be32(buf, QM_IE_VENDOR_TYPE);
1766 wpabuf_put_u8(buf, QM_ATTR_DOMAIN_NAME);
1767 wpabuf_put_u8(buf, domain_name_length);
1768 wpabuf_put_data(buf, domain_name, domain_name_length);
1769 }
1770#undef DOMAIN_NAME_OFFSET
1771
1772 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
1773 wpa_s->own_addr, wpa_s->bssid,
1774 wpabuf_head(buf), wpabuf_len(buf), 0);
1775 if (ret < 0) {
1776 wpa_dbg(wpa_s, MSG_ERROR, "QM: Failed to send DSCP query");
1777 wpa_s->dscp_query_dialog_token--;
1778 }
1779
1780 wpabuf_free(buf);
1781 return ret;
1782}