SCS: Sending of SCS Request frames

Add support to parse SCS control interface command and form the SCS
Request frame to be sent to SCS enabled AP.

Signed-off-by: Vinita S. Maloo <vmaloo@codeaurora.org>
This commit is contained in:
Vinita S. Maloo 2021-01-19 19:17:01 +05:30 committed by Jouni Malinen
parent 445dbe2cdb
commit c005283c48
4 changed files with 866 additions and 0 deletions

View file

@ -10887,6 +10887,456 @@ static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
static int set_type4_frame_classifier(const char *cmd,
struct type4_params *param)
{
const char *pos, *end;
u8 classifier_mask = 0;
int ret;
char addr[INET6_ADDRSTRLEN];
size_t alen;
if (os_strstr(cmd, "ip_version=ipv4")) {
param->ip_version = IPV4;
} else if (os_strstr(cmd, "ip_version=ipv6")) {
param->ip_version = IPV6;
} else {
wpa_printf(MSG_ERROR, "IP version missing/invalid");
return -1;
}
classifier_mask |= BIT(0);
pos = os_strstr(cmd, "src_ip=");
if (pos) {
pos += 7;
end = os_strchr(pos, ' ');
if (!end)
end = pos + os_strlen(pos);
alen = end - pos;
if (alen >= INET6_ADDRSTRLEN)
return -1;
os_memcpy(addr, pos, alen);
addr[alen] = '\0';
if (param->ip_version == IPV4)
ret = inet_pton(AF_INET, addr,
&param->ip_params.v4.src_ip);
else
ret = inet_pton(AF_INET6, addr,
&param->ip_params.v6.src_ip);
if (ret != 1) {
wpa_printf(MSG_ERROR,
"Error converting src IP address to binary ret=%d",
ret);
return -1;
}
classifier_mask |= BIT(1);
}
pos = os_strstr(cmd, "dst_ip=");
if (pos) {
pos += 7;
end = os_strchr(pos, ' ');
if (!end)
end = pos + os_strlen(pos);
alen = end - pos;
if (alen >= INET6_ADDRSTRLEN)
return -1;
os_memcpy(addr, pos, alen);
addr[alen] = '\0';
if (param->ip_version == IPV4)
ret = inet_pton(AF_INET, addr,
&param->ip_params.v4.dst_ip);
else
ret = inet_pton(AF_INET6, addr,
&param->ip_params.v6.dst_ip);
if (ret != 1) {
wpa_printf(MSG_ERROR,
"Error converting dst IP address to binary ret=%d",
ret);
return -1;
}
classifier_mask |= BIT(2);
}
pos = os_strstr(cmd, "src_port=");
if (pos && atoi(pos + 9) > 0) {
if (param->ip_version == IPV4)
param->ip_params.v4.src_port = atoi(pos + 9);
else
param->ip_params.v6.src_port = atoi(pos + 9);
classifier_mask |= BIT(3);
}
pos = os_strstr(cmd, "dst_port=");
if (pos && atoi(pos + 9) > 0) {
if (param->ip_version == IPV4)
param->ip_params.v4.dst_port = atoi(pos + 9);
else
param->ip_params.v6.dst_port = atoi(pos + 9);
classifier_mask |= BIT(4);
}
pos = os_strstr(cmd, "dscp=");
if (pos && atoi(pos + 5) > 0) {
if (param->ip_version == IPV4)
param->ip_params.v4.dscp = atoi(pos + 5);
else
param->ip_params.v6.dscp = atoi(pos + 5);
classifier_mask |= BIT(5);
}
if (param->ip_version == IPV4) {
pos = os_strstr(cmd, "protocol=");
if (pos) {
if (os_strstr(pos, "udp")) {
param->ip_params.v4.protocol = 17;
} else if (os_strstr(pos, "tcp")) {
param->ip_params.v4.protocol = 6;
} else if (os_strstr(pos, "esp")) {
param->ip_params.v4.protocol = 50;
} else {
wpa_printf(MSG_ERROR, "Invalid protocol");
return -1;
}
classifier_mask |= BIT(6);
}
} else {
pos = os_strstr(cmd, "next_header=");
if (pos) {
if (os_strstr(pos, "udp")) {
param->ip_params.v6.next_header = 17;
} else if (os_strstr(pos, "tcp")) {
param->ip_params.v6.next_header = 6;
} else if (os_strstr(pos, "esp")) {
param->ip_params.v6.next_header = 50;
} else {
wpa_printf(MSG_ERROR, "Invalid next header");
return -1;
}
classifier_mask |= BIT(6);
}
pos = os_strstr(cmd, "flow_label=");
if (pos) {
pos += 11;
end = os_strchr(pos, ' ');
if (!end)
end = pos + os_strlen(pos);
if (end - pos != 6 ||
hexstr2bin(pos, param->ip_params.v6.flow_label,
3) ||
param->ip_params.v6.flow_label[0] > 0x0F) {
wpa_printf(MSG_ERROR, "Invalid flow label");
return -1;
}
classifier_mask |= BIT(7);
}
}
param->classifier_mask = classifier_mask;
return 0;
}
static int set_type10_frame_classifier(const char *cmd,
struct type10_params *param)
{
const char *pos, *end;
size_t filter_len;
pos = os_strstr(cmd, "prot_instance=");
if (!pos) {
wpa_printf(MSG_ERROR, "Protocol instance missing");
return -1;
}
param->prot_instance = atoi(pos + 14);
pos = os_strstr(cmd, "prot_number=");
if (!pos) {
wpa_printf(MSG_ERROR, "Protocol number missing");
return -1;
}
if (os_strstr(pos, "udp")) {
param->prot_number = 17;
} else if (os_strstr(pos, "tcp")) {
param->prot_number = 6;
} else if (os_strstr(pos, "esp")) {
param->prot_number = 50;
} else {
wpa_printf(MSG_ERROR, "Invalid protocol number");
return -1;
}
pos = os_strstr(cmd, "filter_value=");
if (!pos) {
wpa_printf(MSG_ERROR,
"Classifier parameter filter_value missing");
return -1;
}
pos += 13;
end = os_strchr(pos, ' ');
if (!end)
end = pos + os_strlen(pos);
filter_len = (end - pos) / 2;
param->filter_value = os_malloc(filter_len);
if (!param->filter_value)
return -1;
if (hexstr2bin(pos, param->filter_value, filter_len)) {
wpa_printf(MSG_ERROR, "Invalid filter_value %s", pos);
goto free;
}
pos = os_strstr(cmd, "filter_mask=");
if (!pos) {
wpa_printf(MSG_ERROR,
"Classifier parameter filter_mask missing");
goto free;
}
pos += 12;
end = os_strchr(pos, ' ');
if (!end)
end = pos + os_strlen(pos);
if (filter_len != (size_t) (end - pos) / 2) {
wpa_printf(MSG_ERROR,
"Filter mask length mismatch expected=%zu received=%zu",
filter_len, (size_t) (end - pos) / 2);
goto free;
}
param->filter_mask = os_malloc(filter_len);
if (!param->filter_mask)
goto free;
if (hexstr2bin(pos, param->filter_mask, filter_len)) {
wpa_printf(MSG_ERROR, "Invalid filter mask %s", pos);
os_free(param->filter_mask);
param->filter_mask = NULL;
goto free;
}
param->filter_len = filter_len;
return 0;
free:
os_free(param->filter_value);
param->filter_value = NULL;
return -1;
}
static int scs_parse_type4(struct tclas_element *elem, const char *pos)
{
struct type4_params type4_param = { 0 };
if (set_type4_frame_classifier(pos, &type4_param) == -1) {
wpa_printf(MSG_ERROR, "Failed to set frame_classifier 4");
return -1;
}
os_memcpy(&elem->frame_classifier.type4_param,
&type4_param, sizeof(struct type4_params));
return 0;
}
static int scs_parse_type10(struct tclas_element *elem, const char *pos)
{
struct type10_params type10_param = { 0 };
if (set_type10_frame_classifier(pos, &type10_param) == -1) {
wpa_printf(MSG_ERROR, "Failed to set frame_classifier 10");
return -1;
}
os_memcpy(&elem->frame_classifier.type10_param,
&type10_param, sizeof(struct type10_params));
return 0;
}
static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
char *cmd)
{
char *pos1, *pos;
struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
struct scs_desc_elem desc_elem = { 0 };
int val;
unsigned int num_scs_desc = 0;
/**
* format:
* [scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>]
* [classifier_type=<4|10>]
* [classifier params based on classifier type]
* [tclas_processing=<0|1>] [scs_id=<decimal number>] ...
*/
pos1 = os_strstr(cmd, "scs_id=");
if (!pos1) {
wpa_printf(MSG_ERROR, "SCSID not present");
return -1;
}
free_up_scs_desc(scs_data);
while (pos1) {
struct scs_desc_elem *n1;
char *next_scs_desc;
unsigned int num_tclas_elem = 0;
desc_elem.scs_id = atoi(pos1 + 7);
pos1 += 7;
next_scs_desc = os_strstr(pos1, "scs_id=");
if (next_scs_desc) {
char temp[20];
os_snprintf(temp, sizeof(temp), "scs_id=%d ",
desc_elem.scs_id);
if (os_strstr(next_scs_desc, temp)) {
wpa_printf(MSG_ERROR,
"Multiple SCS descriptors configured with same SCSID(=%d)",
desc_elem.scs_id);
goto free_scs_desc;
}
pos1[next_scs_desc - pos1 - 1] = '\0';
}
if (os_strstr(pos1, "add ")) {
desc_elem.request_type = SCS_REQ_ADD;
} else if (os_strstr(pos1, "remove")) {
desc_elem.request_type = SCS_REQ_REMOVE;
goto scs_desc_end;
} else if (os_strstr(pos1, "change ")) {
desc_elem.request_type = SCS_REQ_CHANGE;
} else {
wpa_printf(MSG_ERROR, "SCS Request type invalid");
goto free_scs_desc;
}
pos1 = os_strstr(pos1, "scs_up=");
if (!pos1) {
wpa_printf(MSG_ERROR,
"Intra-Access user priority not present");
goto free_scs_desc;
}
val = atoi(pos1 + 7);
if (val < 0 || val > 7) {
wpa_printf(MSG_ERROR,
"Intra-Access user priority invalid %d",
val);
goto free_scs_desc;
}
desc_elem.intra_access_priority = val;
desc_elem.scs_up_avail = true;
pos = os_strstr(pos1, "classifier_type=");
if (!pos) {
wpa_printf(MSG_ERROR, "classifier type empty");
goto free_scs_desc;
}
while (pos) {
struct tclas_element elem = { 0 }, *n;
char *next_tclas_elem;
val = atoi(pos + 16);
if (val != 4 && val != 10) {
wpa_printf(MSG_ERROR,
"classifier type invalid %d", val);
goto free_scs_desc;
}
elem.classifier_type = val;
pos += 16;
next_tclas_elem = os_strstr(pos, "classifier_type=");
if (next_tclas_elem) {
pos1 = next_tclas_elem;
pos[next_tclas_elem - pos - 1] = '\0';
}
switch (val) {
case 4:
if (scs_parse_type4(&elem, pos) < 0)
goto free_scs_desc;
break;
case 10:
if (scs_parse_type10(&elem, pos) < 0)
goto free_scs_desc;
break;
}
n = os_realloc(desc_elem.tclas_elems,
(num_tclas_elem + 1) * sizeof(elem));
if (!n)
goto free_scs_desc;
desc_elem.tclas_elems = n;
os_memcpy((u8 *) desc_elem.tclas_elems +
num_tclas_elem * sizeof(elem),
&elem, sizeof(elem));
num_tclas_elem++;
desc_elem.num_tclas_elem = num_tclas_elem;
pos = next_tclas_elem;
}
if (desc_elem.num_tclas_elem > 1) {
pos1 = os_strstr(pos1, "tclas_processing=");
if (!pos1) {
wpa_printf(MSG_ERROR, "tclas_processing empty");
goto free_scs_desc;
}
val = atoi(pos1 + 17);
if (val != 0 && val != 1) {
wpa_printf(MSG_ERROR,
"tclas_processing invalid");
goto free_scs_desc;
}
desc_elem.tclas_processing = val;
}
scs_desc_end:
n1 = os_realloc(scs_data->scs_desc_elems, (num_scs_desc + 1) *
sizeof(struct scs_desc_elem));
if (!n1)
goto free_scs_desc;
scs_data->scs_desc_elems = n1;
os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_desc *
sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
num_scs_desc++;
scs_data->num_scs_desc = num_scs_desc;
pos1 = next_scs_desc;
os_memset(&desc_elem, 0, sizeof(desc_elem));
}
return wpas_send_scs_req(wpa_s);
free_scs_desc:
free_up_tclas_elem(&desc_elem);
free_up_scs_desc(scs_data);
return -1;
}
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len) char *buf, size_t *resp_len)
{ {
@ -11812,6 +12262,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0) if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0)
reply_len = -1; reply_len = -1;
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
} else if (os_strncmp(buf, "SCS ", 4) == 0) {
if (wpas_ctrl_iface_configure_scs(wpa_s, buf + 4))
reply_len = -1;
} else { } else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16); os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16; reply_len = 16;

View file

@ -45,6 +45,126 @@ void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
} }
static int wpas_populate_type4_classifier(struct type4_params *type4_param,
struct wpabuf *buf)
{
/* classifier parameters */
wpabuf_put_u8(buf, type4_param->classifier_mask);
if (type4_param->ip_version == IPV4) {
wpabuf_put_u8(buf, IPV4); /* IP version */
wpabuf_put_data(buf, &type4_param->ip_params.v4.src_ip.s_addr,
4);
wpabuf_put_data(buf, &type4_param->ip_params.v4.dst_ip.s_addr,
4);
wpabuf_put_be16(buf, type4_param->ip_params.v4.src_port);
wpabuf_put_be16(buf, type4_param->ip_params.v4.dst_port);
wpabuf_put_u8(buf, type4_param->ip_params.v4.dscp);
wpabuf_put_u8(buf, type4_param->ip_params.v4.protocol);
wpabuf_put_u8(buf, 0); /* Reserved octet */
} else {
wpabuf_put_u8(buf, IPV6);
wpabuf_put_data(buf, &type4_param->ip_params.v6.src_ip.s6_addr,
16);
wpabuf_put_data(buf, &type4_param->ip_params.v6.dst_ip.s6_addr,
16);
wpabuf_put_be16(buf, type4_param->ip_params.v6.src_port);
wpabuf_put_be16(buf, type4_param->ip_params.v6.dst_port);
wpabuf_put_u8(buf, type4_param->ip_params.v6.dscp);
wpabuf_put_u8(buf, type4_param->ip_params.v6.next_header);
wpabuf_put_data(buf, type4_param->ip_params.v6.flow_label, 3);
}
return 0;
}
static int wpas_populate_type10_classifier(struct type10_params *type10_param,
struct wpabuf *buf)
{
/* classifier parameters */
wpabuf_put_u8(buf, type10_param->prot_instance);
wpabuf_put_u8(buf, type10_param->prot_number);
wpabuf_put_data(buf, type10_param->filter_value,
type10_param->filter_len);
wpabuf_put_data(buf, type10_param->filter_mask,
type10_param->filter_len);
return 0;
}
static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
struct wpabuf *buf)
{
u8 *len, *len1;
struct tclas_element *tclas_elem;
unsigned int i;
/* SCS Descriptor element */
wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR);
len = wpabuf_put(buf, 1);
wpabuf_put_u8(buf, desc_elem->scs_id);
wpabuf_put_u8(buf, desc_elem->request_type);
if (desc_elem->request_type == SCS_REQ_REMOVE)
goto end;
if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) {
wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY);
wpabuf_put_u8(buf, 1);
wpabuf_put_u8(buf, desc_elem->intra_access_priority);
}
tclas_elem = desc_elem->tclas_elems;
if (!tclas_elem)
return -1;
for (i = 0; i < desc_elem->num_tclas_elem; i++, tclas_elem++) {
int ret;
/* TCLAS element */
wpabuf_put_u8(buf, WLAN_EID_TCLAS);
len1 = wpabuf_put(buf, 1);
wpabuf_put_u8(buf, 255); /* User Priority: not compared */
/* Frame Classifier */
wpabuf_put_u8(buf, tclas_elem->classifier_type);
/* Frame classifier parameters */
switch (tclas_elem->classifier_type) {
case 4:
ret = wpas_populate_type4_classifier(
&tclas_elem->frame_classifier.type4_param,
buf);
break;
case 10:
ret = wpas_populate_type10_classifier(
&tclas_elem->frame_classifier.type10_param,
buf);
break;
default:
return -1;
}
if (ret == -1) {
wpa_printf(MSG_ERROR,
"Failed to populate frame classifier");
return -1;
}
*len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
}
if (desc_elem->num_tclas_elem > 1) {
/* TCLAS Processing element */
wpabuf_put_u8(buf, WLAN_EID_TCLAS_PROCESSING);
wpabuf_put_u8(buf, 1);
wpabuf_put_u8(buf, desc_elem->tclas_processing);
}
end:
*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
return 0;
}
int wpas_send_mscs_req(struct wpa_supplicant *wpa_s) int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
{ {
struct wpabuf *buf; struct wpabuf *buf;
@ -101,6 +221,214 @@ int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
} }
static size_t tclas_elem_len(const struct tclas_element *elem)
{
size_t buf_len = 0;
buf_len += 2 + /* TCLAS element header */
1 + /* User Priority */
1 ; /* Classifier Type */
if (elem->classifier_type == 4) {
enum ip_version ip_ver;
buf_len += 1 + /* Classifier mask */
1 + /* IP version */
1 + /* user priority */
2 + /* src_port */
2 + /* dst_port */
1 ; /* dscp */
ip_ver = elem->frame_classifier.type4_param.ip_version;
if (ip_ver == IPV4) {
buf_len += 4 + /* src_ip */
4 + /* dst_ip */
1 + /* protocol */
1 ; /* Reserved */
} else if (ip_ver == IPV6) {
buf_len += 16 + /* src_ip */
16 + /* dst_ip */
1 + /* next_header */
3 ; /* flow_label */
} else {
wpa_printf(MSG_ERROR, "%s: Incorrect IP version %d",
__func__, ip_ver);
return 0;
}
} else if (elem->classifier_type == 10) {
buf_len += 1 + /* protocol instance */
1 + /* protocol number */
2 * elem->frame_classifier.type10_param.filter_len;
} else {
wpa_printf(MSG_ERROR, "%s: Incorrect classifier type %u",
__func__, elem->classifier_type);
return 0;
}
return buf_len;
}
static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
unsigned int num_scs_desc)
{
struct wpabuf *buf;
size_t buf_len = 0;
unsigned int i, j;
buf_len = 3; /* Action frame header */
for (i = 0; i < num_scs_desc; i++, desc_elem++) {
struct tclas_element *tclas_elem;
buf_len += 2 + /* SCS descriptor IE header */
1 + /* SCSID */
1 ; /* Request type */
if (desc_elem->request_type == SCS_REQ_REMOVE)
continue;
if (desc_elem->intra_access_priority || desc_elem->scs_up_avail)
buf_len += 3;
tclas_elem = desc_elem->tclas_elems;
if (!tclas_elem) {
wpa_printf(MSG_ERROR, "%s: TCLAS element null",
__func__);
return NULL;
}
for (j = 0; j < desc_elem->num_tclas_elem; j++, tclas_elem++) {
size_t elen;
elen = tclas_elem_len(tclas_elem);
if (elen == 0)
return NULL;
buf_len += elen;
}
if (desc_elem->num_tclas_elem > 1) {
buf_len += 1 + /* TCLAS Processing eid */
1 + /* length */
1 ; /* processing */
}
}
buf = wpabuf_alloc(buf_len);
if (!buf) {
wpa_printf(MSG_ERROR, "Failed to allocate SCS req");
return NULL;
}
return buf;
}
int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
{
struct wpabuf *buf = NULL;
struct scs_desc_elem *desc_elem = NULL;
int ret = -1;
unsigned int i;
if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
return -1;
if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_SCS)) {
wpa_dbg(wpa_s, MSG_INFO,
"AP does not support SCS - could not send SCS Request");
return -1;
}
desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
if (!desc_elem)
return -1;
buf = allocate_scs_buf(desc_elem,
wpa_s->scs_robust_av_req.num_scs_desc);
if (!buf)
return -1;
wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
wpabuf_put_u8(buf, ROBUST_AV_SCS_REQ);
wpa_s->scs_dialog_token++;
if (wpa_s->scs_dialog_token == 0)
wpa_s->scs_dialog_token++;
wpabuf_put_u8(buf, wpa_s->scs_dialog_token);
for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
i++, desc_elem++) {
/* SCS Descriptor element */
if (wpas_populate_scs_descriptor_ie(desc_elem, buf) < 0)
goto end;
}
wpa_hexdump_buf(MSG_DEBUG, "SCS Request", buf);
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
wpabuf_head(buf), wpabuf_len(buf), 0);
if (ret < 0) {
wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request");
wpa_s->scs_dialog_token--;
}
end:
wpabuf_free(buf);
free_up_scs_desc(&wpa_s->scs_robust_av_req);
return ret;
}
void free_up_tclas_elem(struct scs_desc_elem *elem)
{
struct tclas_element *tclas_elems = elem->tclas_elems;
unsigned int num_tclas_elem = elem->num_tclas_elem;
struct tclas_element *tclas_data;
unsigned int j;
elem->tclas_elems = NULL;
elem->num_tclas_elem = 0;
if (!tclas_elems)
return;
tclas_data = tclas_elems;
for (j = 0; j < num_tclas_elem; j++, tclas_data++) {
if (tclas_data->classifier_type != 10)
continue;
os_free(tclas_data->frame_classifier.type10_param.filter_value);
os_free(tclas_data->frame_classifier.type10_param.filter_mask);
}
os_free(tclas_elems);
}
void free_up_scs_desc(struct scs_robust_av_data *data)
{
struct scs_desc_elem *desc_elems = data->scs_desc_elems;
unsigned int num_scs_desc = data->num_scs_desc;
struct scs_desc_elem *desc_data;
unsigned int i;
data->scs_desc_elems = NULL;
data->num_scs_desc = 0;
if (!desc_elems)
return;
desc_data = desc_elems;
for (i = 0; i < num_scs_desc; i++, desc_data++) {
if (desc_data->request_type == SCS_REQ_REMOVE ||
!desc_data->tclas_elems)
continue;
free_up_tclas_elem(desc_data);
}
os_free(desc_elems);
}
void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s, void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
const u8 *src, const u8 *buf, size_t len) const u8 *src, const u8 *buf, size_t len)
{ {

View file

@ -743,6 +743,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_PASN #ifdef CONFIG_PASN
wpas_pasn_auth_stop(wpa_s); wpas_pasn_auth_stop(wpa_s);
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
free_up_scs_desc(&wpa_s->scs_robust_av_req);
wpa_s->scs_dialog_token = 0;
} }
@ -1915,6 +1917,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
#endif /* CONFIG_MBO */ #endif /* CONFIG_MBO */
break; break;
case 6: /* Bits 48-55 */ case 6: /* Bits 48-55 */
*pos |= 0x40; /* Bit 54 - SCS */
break; break;
case 7: /* Bits 56-63 */ case 7: /* Bits 56-63 */
break; break;
@ -3963,6 +3966,9 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid) if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s); wpas_notify_network_changed(wpa_s);
free_up_scs_desc(&wpa_s->scs_robust_av_req);
wpa_s->scs_dialog_token = 0;
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
} }

View file

@ -576,6 +576,80 @@ struct wpas_pasn {
}; };
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
enum ip_version {
IPV4 = 4,
IPV6 = 6,
};
struct ipv4_params {
struct in_addr src_ip;
struct in_addr dst_ip;
u16 src_port;
u16 dst_port;
u8 dscp;
u8 protocol;
};
struct ipv6_params {
struct in6_addr src_ip;
struct in6_addr dst_ip;
u16 src_port;
u16 dst_port;
u8 dscp;
u8 next_header;
u8 flow_label[3];
};
struct type4_params {
u8 classifier_mask;
enum ip_version ip_version;
union {
struct ipv4_params v4;
struct ipv6_params v6;
} ip_params;
};
struct type10_params {
u8 prot_instance;
u8 prot_number;
u8 *filter_value;
u8 *filter_mask;
size_t filter_len;
};
struct tclas_element {
u8 user_priority;
u8 classifier_type;
union {
struct type4_params type4_param;
struct type10_params type10_param;
} frame_classifier;
};
struct scs_desc_elem {
u8 scs_id;
enum scs_request_type request_type;
u8 intra_access_priority;
bool scs_up_avail;
struct tclas_element *tclas_elems;
unsigned int num_tclas_elem;
u8 tclas_processing;
};
struct scs_robust_av_data {
struct scs_desc_elem *scs_desc_elems;
unsigned int num_scs_desc;
};
/** /**
* struct wpa_supplicant - Internal data for wpa_supplicant interface * struct wpa_supplicant - Internal data for wpa_supplicant interface
* *
@ -1402,6 +1476,8 @@ struct wpa_supplicant {
struct wpas_pasn pasn; struct wpas_pasn pasn;
struct wpa_radio_work *pasn_auth_work; struct wpa_radio_work *pasn_auth_work;
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
struct scs_robust_av_data scs_robust_av_req;
u8 scs_dialog_token;
}; };
@ -1734,6 +1810,9 @@ void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
size_t len); size_t len);
void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ies, size_t ies_len); const u8 *ies, size_t ies_len);
int wpas_send_scs_req(struct wpa_supplicant *wpa_s);
void free_up_tclas_elem(struct scs_desc_elem *elem);
void free_up_scs_desc(struct scs_robust_av_data *data);
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
const u8 *bssid, int akmp, int cipher, const u8 *bssid, int akmp, int cipher,