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 <vjakkam@codeaurora.org>
This commit is contained in:
parent
fe2a44485e
commit
2033e318e6
8 changed files with 719 additions and 0 deletions
|
@ -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 */
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <policy_id> <dscp_value> <ip_version=0|4|6>
|
||||
[protocol] [source ip] [destination_ip]/[domain name] [source port]
|
||||
[[<start_port> <end_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 <policy_id>
|
||||
|
||||
- DSCP policy may get rejected due to invalid policy parameters. Ccontrol
|
||||
interface event message format for rejected policy.
|
||||
|
||||
<3>CTRL-EVENT-DSCP-POLICY reject <policy_id>
|
||||
|
||||
- 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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue