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