From 2033e318e67e82c15c24458706cdaa4ccd4ab528 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Tue, 9 Mar 2021 19:41:58 -0800 Subject: [PATCH] DSCP: Parsing and processing of DSCP Policy Request frames Add support to parse received DSCP Policy Request frames and send the request details as control interface events. Signed-off-by: Veerendranath Jakkam --- src/common/ieee802_11_defs.h | 29 ++ src/common/wpa_ctrl.h | 2 + src/drivers/driver_nl80211.c | 5 + wpa_supplicant/README | 58 +++ wpa_supplicant/events.c | 7 + wpa_supplicant/robust_av.c | 609 ++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant.c | 2 + wpa_supplicant/wpa_supplicant_i.h | 7 + 8 files changed, 719 insertions(+) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 2ed2d37b0..971e046e0 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1361,6 +1361,8 @@ struct ieee80211_ampe_ie { #define DPP_CC_OUI_TYPE 0x1e #define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f #define SAE_PK_OUI_TYPE 0x1f +#define QM_IE_VENDOR_TYPE 0x506f9a22 +#define QM_IE_OUI_TYPE 0x22 #define MULTI_AP_SUB_ELEM_TYPE 0x06 #define MULTI_AP_TEAR_DOWN BIT(4) @@ -2446,4 +2448,31 @@ enum mscs_description_subelem { */ #define FD_MAX_INTERVAL_6GHZ 20 /* TUs */ +/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */ +#define QM_ACTION_VENDOR_TYPE 0x506f9a1a +#define QM_ACTION_OUI_TYPE 0x1a + +/* QoS Management Action frame OUI subtypes */ +#define QM_DSCP_POLICY_QUERY 0 +#define QM_DSCP_POLICY_REQ 1 +#define QM_DSCP_POLICY_RESP 2 + +/* QoS Management attributes */ +enum qm_attr_id { + QM_ATTR_PORT_RANGE = 1, + QM_ATTR_DSCP_POLICY = 2, + QM_ATTR_TCLAS = 3, + QM_ATTR_DOMAIN_NAME = 4, +}; + +/* DSCP Policy attribute - Request Type */ +enum dscp_policy_request_type { + DSCP_POLICY_REQ_ADD = 0, /* ADD/UPDATE */ + DSCP_POLICY_REQ_REMOVE = 1, +}; + +/* Request/Response Control field of DSCP Policy Request/Response frame */ +#define DSCP_POLICY_CTRL_MORE BIT(0) +#define DSCP_POLICY_CTRL_RESET BIT(1) + #endif /* IEEE802_11_DEFS_H */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 2b8f04bec..2c7ec043d 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -163,6 +163,8 @@ extern "C" { #define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK " /** Result of SCS setup */ #define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT " +/* Event indicating DSCP policy */ +#define WPA_EVENT_DSCP_POLICY "CTRL-EVENT-DSCP-POLICY " /* WPS ER events */ #define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index f04934454..7ad72b54c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2520,6 +2520,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0) ret = -1; + /* Protected QoS Management Action frame */ + if (nl80211_register_action_frame(bss, (u8 *) "\x7e\x50\x6f\x9a\x1a", + 5) < 0) + ret = -1; + nl80211_mgmt_handle_register_eloop(bss); return ret; diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 391912e9b..825df057f 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1077,3 +1077,61 @@ ext:test4@wlan0:0:0:9.679895 OK <3>EXT-RADIO-WORK-START 7 <3>EXT-RADIO-WORK-TIMEOUT 7 + + +DSCP policy procedures +---------------------- + +DSCP policy procedures defined in WFA QoS Management-R2 program +facilitates AP devices to configure DSCP settings for specific uplink +data streams. + +An AP may transmit a DSCP Policy Request frame containing zero or more +QoS Management IEs to an associated STA which supports DSCP policy +procedures. Each QoS Management element in a DSCP Policy Request frame +represents one DSCP policy, and shall include one DSCP Policy attribute +including a DSCP Policy ID, Request type, and a DSCP value. + +wpa_supplicant sends control interface event messages consisting details +of DSCP policies requested by the AP through a DSCP Policy Request frame +to external programs. The format of the control interface event messages +is as shown below: + +- Control interface event message format to indicate DSCP request start + + <3>CTRL-EVENT-DSCP-POLICY request_start [clear_all] [more] + + clear_all - AP requested to clear all DSCP policies configured earlier + more - AP may request to configure more DSCP policies with new DSCP + request + +- Control interface event message format to add new policy + + <3>CTRL-EVENT-DSCP-POLICY add + [protocol] [source ip] [destination_ip]/[domain name] [source port] + [[ ]/destination port] + + ip_version = 0: Both IPv4 and IPv6 + = 4: IPv4 + = 6: IPv6 + protocol: Internet Protocol Numbers as per IETF RFCs + = 6: TCP + = 17: UDP + = 50: ESP + +- Control interface event message format to remove a particular policy, + identified by the policy_id attribute. + + <3>CTRL-EVENT-DSCP-POLICY remove + +- DSCP policy may get rejected due to invalid policy parameters. Ccontrol + interface event message format for rejected policy. + + <3>CTRL-EVENT-DSCP-POLICY reject + +- Control interface event message format to indicate end of DSCP request. + + <3>CTRL-EVENT-DSCP-POLICY request_end + +- External applications shall clear active DSCP policies upon receiving + "CTRL-EVENT-DISCONNECTED" or "CTRL-EVENT-DSCP-POLICY clear_all" events. diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 44f2c41f2..e9af7585b 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -4273,6 +4273,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, return; } + if (category == WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED && plen > 4 && + WPA_GET_BE32(payload) == QM_ACTION_VENDOR_TYPE) { + wpas_handle_qos_mgmt_recv_action(wpa_s, mgmt->sa, + payload + 4, plen - 4); + return; + } + wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, category, payload, plen, freq); if (wpa_s->ifmsh) diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c index a8b77d1d4..fdcb5bc9b 100644 --- a/wpa_supplicant/robust_av.c +++ b/wpa_supplicant/robust_av.c @@ -659,3 +659,612 @@ void wpas_scs_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(scs_request_timer, wpa_s, NULL); wpa_s->ongoing_scs_req = false; } + + +static int write_ipv4_info(char *pos, int total_len, + const struct ipv4_params *v4) +{ + int res, rem_len; + char addr[INET_ADDRSTRLEN]; + + rem_len = total_len; + + if (v4->param_mask & BIT(1)) { + if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv4 source address"); + return -1; + } + + res = os_snprintf(pos, rem_len, " src_ip=%s", addr); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v4->param_mask & BIT(2)) { + if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv4 destination address"); + return -1; + } + + res = os_snprintf(pos, rem_len, " dst_ip=%s", addr); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v4->param_mask & BIT(3)) { + res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v4->param_mask & BIT(4)) { + res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v4->param_mask & BIT(6)) { + res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + return total_len - rem_len; +} + + +static int write_ipv6_info(char *pos, int total_len, + const struct ipv6_params *v6) +{ + int res, rem_len; + char addr[INET6_ADDRSTRLEN]; + + rem_len = total_len; + + if (v6->param_mask & BIT(1)) { + if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv6 source addr"); + return -1; + } + + res = os_snprintf(pos, rem_len, " src_ip=%s", addr); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v6->param_mask & BIT(2)) { + if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv6 destination addr"); + return -1; + } + + res = os_snprintf(pos, rem_len, " dst_ip=%s", addr); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v6->param_mask & BIT(3)) { + res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v6->param_mask & BIT(4)) { + res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + if (v6->param_mask & BIT(6)) { + res = os_snprintf(pos, rem_len, " protocol=%d", + v6->next_header); + if (os_snprintf_error(rem_len, res)) + return -1; + + pos += res; + rem_len -= res; + } + + return total_len - rem_len; +} + + +struct dscp_policy_data { + u8 policy_id; + u8 req_type; + u8 dscp; + bool dscp_info; + const u8 *frame_classifier; + u8 frame_classifier_len; + struct type4_params type4_param; + const u8 *domain_name; + u8 domain_name_len; + u16 start_port; + u16 end_port; + bool port_range_info; +}; + + +static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) +{ + u8 classifier_mask; + const u8 *frame_classifier = policy->frame_classifier; + struct type4_params *type4_param = &policy->type4_param; + + if (policy->frame_classifier_len < 18) { + wpa_printf(MSG_ERROR, + "QM: Received IPv4 frame classifier with insufficient length %d", + policy->frame_classifier_len); + return -1; + } + + classifier_mask = frame_classifier[1]; + + /* Classifier Mask - bit 1 = Source IP Address */ + if (classifier_mask & BIT(1)) { + type4_param->ip_params.v4.param_mask |= BIT(1); + os_memcpy(&type4_param->ip_params.v4.src_ip, + &frame_classifier[3], 4); + } + + /* Classifier Mask - bit 2 = Destination IP Address */ + if (classifier_mask & BIT(2)) { + if (policy->domain_name) { + wpa_printf(MSG_ERROR, + "QM: IPv4: Both domain name and destination IP address not expected"); + return -1; + } + + type4_param->ip_params.v4.param_mask |= BIT(2); + os_memcpy(&type4_param->ip_params.v4.dst_ip, + &frame_classifier[7], 4); + } + + /* Classifier Mask - bit 3 = Source Port */ + if (classifier_mask & BIT(3)) { + type4_param->ip_params.v4.param_mask |= BIT(3); + type4_param->ip_params.v4.src_port = + WPA_GET_BE16(&frame_classifier[11]); + } + + /* Classifier Mask - bit 4 = Destination Port */ + if (classifier_mask & BIT(4)) { + if (policy->port_range_info) { + wpa_printf(MSG_ERROR, + "QM: IPv4: Both port range and destination port not expected"); + return -1; + } + + type4_param->ip_params.v4.param_mask |= BIT(4); + type4_param->ip_params.v4.dst_port = + WPA_GET_BE16(&frame_classifier[13]); + } + + /* Classifier Mask - bit 5 = DSCP (ignored) */ + + /* Classifier Mask - bit 6 = Protocol */ + if (classifier_mask & BIT(6)) { + type4_param->ip_params.v4.param_mask |= BIT(6); + type4_param->ip_params.v4.protocol = frame_classifier[16]; + } + + return 0; +} + + +static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) +{ + u8 classifier_mask; + const u8 *frame_classifier = policy->frame_classifier; + struct type4_params *type4_param = &policy->type4_param; + + if (policy->frame_classifier_len < 44) { + wpa_printf(MSG_ERROR, + "QM: Received IPv6 frame classifier with insufficient length %d", + policy->frame_classifier_len); + return -1; + } + + classifier_mask = frame_classifier[1]; + + /* Classifier Mask - bit 1 = Source IP Address */ + if (classifier_mask & BIT(1)) { + type4_param->ip_params.v6.param_mask |= BIT(1); + os_memcpy(&type4_param->ip_params.v6.src_ip, + &frame_classifier[3], 16); + } + + /* Classifier Mask - bit 2 = Destination IP Address */ + if (classifier_mask & BIT(2)) { + if (policy->domain_name) { + wpa_printf(MSG_ERROR, + "QM: IPv6: Both domain name and destination IP address not expected"); + return -1; + } + type4_param->ip_params.v6.param_mask |= BIT(2); + os_memcpy(&type4_param->ip_params.v6.dst_ip, + &frame_classifier[19], 16); + } + + /* Classifier Mask - bit 3 = Source Port */ + if (classifier_mask & BIT(3)) { + type4_param->ip_params.v6.param_mask |= BIT(3); + type4_param->ip_params.v6.src_port = + WPA_GET_BE16(&frame_classifier[35]); + } + + /* Classifier Mask - bit 4 = Destination Port */ + if (classifier_mask & BIT(4)) { + if (policy->port_range_info) { + wpa_printf(MSG_ERROR, + "IPv6: Both port range and destination port not expected"); + return -1; + } + + type4_param->ip_params.v6.param_mask |= BIT(4); + type4_param->ip_params.v6.dst_port = + WPA_GET_BE16(&frame_classifier[37]); + } + + /* Classifier Mask - bit 5 = DSCP (ignored) */ + + /* Classifier Mask - bit 6 = Next Header */ + if (classifier_mask & BIT(6)) { + type4_param->ip_params.v6.param_mask |= BIT(6); + type4_param->ip_params.v6.next_header = frame_classifier[40]; + } + + return 0; +} + + +static int wpas_set_frame_classifier_params(struct dscp_policy_data *policy) +{ + const u8 *frame_classifier = policy->frame_classifier; + u8 frame_classifier_len = policy->frame_classifier_len; + + if (frame_classifier_len < 3) { + wpa_printf(MSG_ERROR, + "QM: Received frame classifier with insufficient length %d", + frame_classifier_len); + return -1; + } + + /* Only allowed Classifier Type: IP and higher layer parameters (4) */ + if (frame_classifier[0] != 4) { + wpa_printf(MSG_ERROR, + "QM: Received frame classifier with invalid classifier type %d", + frame_classifier[0]); + return -1; + } + + /* Classifier Mask - bit 0 = Version */ + if (!(frame_classifier[1] & BIT(0))) { + wpa_printf(MSG_ERROR, + "QM: Received frame classifier without IP version"); + return -1; + } + + /* Version (4 or 6) */ + if (frame_classifier[2] == 4) { + if (set_frame_classifier_type4_ipv4(policy)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv4 parameters"); + return -1; + } + + policy->type4_param.ip_version = IPV4; + } else if (frame_classifier[2] == 6) { + if (set_frame_classifier_type4_ipv6(policy)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set IPv6 parameters"); + return -1; + } + + policy->type4_param.ip_version = IPV6; + } else { + wpa_printf(MSG_ERROR, + "QM: Received unknown IP version %d", + frame_classifier[2]); + return -1; + } + + return 0; +} + + +static bool dscp_valid_domain_name(const char *str) +{ + if (!str[0]) + return false; + + while (*str) { + if (is_ctrl_char(*str) || *str == ' ' || *str == '=') + return false; + str++; + } + + return true; +} + + +static void wpas_add_dscp_policy(struct wpa_supplicant *wpa_s, + struct dscp_policy_data *policy) +{ + int ip_ver = 0, res; + char policy_str[1000], *pos; + int len; + + if (!policy->frame_classifier && !policy->domain_name && + !policy->port_range_info) { + wpa_printf(MSG_ERROR, + "QM: Invalid DSCP policy - no attributes present"); + goto fail; + } + + policy_str[0] = '\0'; + pos = policy_str; + len = sizeof(policy_str); + + if (policy->frame_classifier) { + struct type4_params *type4 = &policy->type4_param; + + if (wpas_set_frame_classifier_params(policy)) { + wpa_printf(MSG_ERROR, + "QM: Failed to set frame classifier parameters"); + goto fail; + } + + if (type4->ip_version == IPV4) + res = write_ipv4_info(pos, len, &type4->ip_params.v4); + else + res = write_ipv6_info(pos, len, &type4->ip_params.v6); + + if (res <= 0) { + wpa_printf(MSG_ERROR, + "QM: Failed to write IP parameters"); + goto fail; + } + + ip_ver = type4->ip_version; + + pos += res; + len -= res; + } + + if (policy->port_range_info) { + res = os_snprintf(pos, len, " start_port=%u end_port=%u", + policy->start_port, policy->end_port); + if (os_snprintf_error(len, res)) { + wpa_printf(MSG_ERROR, + "QM: Failed to write port range attributes for policy id = %d", + policy->policy_id); + goto fail; + } + + pos += res; + len -= res; + } + + if (policy->domain_name) { + char domain_name_str[250]; + + if (policy->domain_name_len >= sizeof(domain_name_str)) { + wpa_printf(MSG_ERROR, + "QM: Domain name length higher than max expected"); + goto fail; + } + os_memcpy(domain_name_str, policy->domain_name, + policy->domain_name_len); + domain_name_str[policy->domain_name_len] = '\0'; + if (!dscp_valid_domain_name(domain_name_str)) { + wpa_printf(MSG_ERROR, "QM: Invalid domain name string"); + goto fail; + } + res = os_snprintf(pos, len, " domain_name=%s", domain_name_str); + if (os_snprintf_error(len, res)) { + wpa_printf(MSG_ERROR, + "QM: Failed to write domain name attribute for policy id = %d", + policy->policy_id); + goto fail; + } + } + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY + "add policy_id=%u dscp=%u ip_version=%d%s", + policy->policy_id, policy->dscp, ip_ver, policy_str); + return; +fail: + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "reject policy_id=%u", + policy->policy_id); +} + + +void wpas_dscp_deinit(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "QM: Clear all active DSCP policies"); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "clear_all"); + wpa_s->dscp_req_dialog_token = 0; +} + + +static void wpas_fill_dscp_policy(struct dscp_policy_data *policy, u8 attr_id, + u8 attr_len, const u8 *attr_data) +{ + switch (attr_id) { + case QM_ATTR_PORT_RANGE: + if (attr_len < 4) { + wpa_printf(MSG_ERROR, + "QM: Received Port Range attribute with insufficient length %d", + attr_len); + break; + } + policy->start_port = WPA_GET_BE16(attr_data); + policy->end_port = WPA_GET_BE16(attr_data + 2); + policy->port_range_info = true; + break; + case QM_ATTR_DSCP_POLICY: + if (attr_len < 3) { + wpa_printf(MSG_ERROR, + "QM: Received DSCP Policy attribute with insufficient length %d", + attr_len); + return; + } + policy->policy_id = attr_data[0]; + policy->req_type = attr_data[1]; + policy->dscp = attr_data[2]; + policy->dscp_info = true; + break; + case QM_ATTR_TCLAS: + if (attr_len < 1) { + wpa_printf(MSG_ERROR, + "QM: Received TCLAS attribute with insufficient length %d", + attr_len); + return; + } + policy->frame_classifier = attr_data; + policy->frame_classifier_len = attr_len; + break; + case QM_ATTR_DOMAIN_NAME: + if (attr_len < 1) { + wpa_printf(MSG_ERROR, + "QM: Received domain name attribute with insufficient length %d", + attr_len); + return; + } + policy->domain_name = attr_data; + policy->domain_name_len = attr_len; + break; + default: + wpa_printf(MSG_ERROR, "QM: Received invalid QoS attribute %d", + attr_id); + break; + } +} + + +void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *buf, size_t len) +{ + int rem_len; + const u8 *qos_ie, *attr; + int more, reset; + + if (!wpa_s->enable_dscp_policy_capa) { + wpa_printf(MSG_ERROR, + "QM: Ignore DSCP Policy frame since the capability is not enabled"); + return; + } + + if (!pmf_in_use(wpa_s, src)) { + wpa_printf(MSG_ERROR, + "QM: Ignore DSCP Policy frame since PMF is not in use"); + return; + } + + if (len < 1) + return; + + /* Handle only DSCP Policy Request frame */ + if (buf[0] != QM_DSCP_POLICY_REQ) { + wpa_printf(MSG_ERROR, "QM: Received unexpected QoS action frame %d", + buf[0]); + return; + } + + if (len < 3) { + wpa_printf(MSG_ERROR, + "Received QoS Management DSCP Policy Request frame with invalid length %zu", + len); + return; + } + + wpa_s->dscp_req_dialog_token = buf[1]; + more = buf[2] & DSCP_POLICY_CTRL_MORE; + reset = buf[2] & DSCP_POLICY_CTRL_RESET; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_start%s%s", + reset ? " clear_all" : "", more ? " more" : ""); + + qos_ie = buf + 3; + rem_len = len - 3; + while (rem_len > 2) { + struct dscp_policy_data policy; + int rem_attrs_len, ie_len; + + ie_len = 2 + qos_ie[1]; + if (rem_len < ie_len) + break; + + if (rem_len < 6 || qos_ie[0] != WLAN_EID_VENDOR_SPECIFIC || + qos_ie[1] < 4 || + WPA_GET_BE32(&qos_ie[2]) != QM_IE_VENDOR_TYPE) { + rem_len -= ie_len; + qos_ie += ie_len; + continue; + } + + os_memset(&policy, 0, sizeof(struct dscp_policy_data)); + attr = qos_ie + 6; + rem_attrs_len = qos_ie[1] - 4; + + while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) { + wpas_fill_dscp_policy(&policy, attr[0], attr[1], + &attr[2]); + rem_attrs_len -= 2 + attr[1]; + attr += 2 + attr[1]; + } + + rem_len -= ie_len; + qos_ie += ie_len; + + if (!policy.dscp_info) { + wpa_printf(MSG_ERROR, + "QM: Received QoS IE without DSCP Policy attribute"); + continue; + } + + if (policy.req_type == DSCP_POLICY_REQ_ADD) + wpas_add_dscp_policy(wpa_s, &policy); + else if (policy.req_type == DSCP_POLICY_REQ_REMOVE) + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY + "remove policy_id=%u", policy.policy_id); + else + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY + "reject policy_id=%u", policy.policy_id); + } + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_end"); +} diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 51c8da4a3..e0723a2b3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -744,6 +744,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpas_pasn_auth_stop(wpa_s); #endif /* CONFIG_PASN */ wpas_scs_deinit(wpa_s); + wpas_dscp_deinit(wpa_s); } @@ -3983,6 +3984,7 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s, wpas_notify_network_changed(wpa_s); wpas_scs_deinit(wpa_s); + wpas_dscp_deinit(wpa_s); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 6e54a2283..d6742e272 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -590,6 +590,7 @@ struct ipv4_params { u16 dst_port; u8 dscp; u8 protocol; + u8 param_mask; }; @@ -601,6 +602,7 @@ struct ipv6_params { u8 dscp; u8 next_header; u8 flow_label[3]; + u8 param_mask; }; @@ -1498,6 +1500,7 @@ struct wpa_supplicant { #endif /* CONFIG_TESTING_OPTIONS */ struct dl_list active_scs_ids; bool ongoing_scs_req; + u8 dscp_req_dialog_token; unsigned int enable_dscp_policy_capa:1; }; @@ -1839,6 +1842,10 @@ void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *buf, size_t len); void wpas_scs_deinit(struct wpa_supplicant *wpa_s); +void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *buf, size_t len); +void wpas_dscp_deinit(struct wpa_supplicant *wpa_s); int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher,