diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 8a6a829b6..a0805e343 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -10887,6 +10887,456 @@ static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s, #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, + ¶m->ip_params.v4.src_ip); + else + ret = inet_pton(AF_INET6, addr, + ¶m->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, + ¶m->ip_params.v4.dst_ip); + else + ret = inet_pton(AF_INET6, addr, + ¶m->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=] [scs_up=<0-7>] + * [classifier_type=<4|10>] + * [classifier params based on classifier type] + * [tclas_processing=<0|1>] [scs_id=] ... + */ + 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 *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) reply_len = -1; #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 { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c index 39d282f08..598bbdedf 100644 --- a/wpa_supplicant/robust_av.c +++ b/wpa_supplicant/robust_av.c @@ -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) { 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, const u8 *src, const u8 *buf, size_t len) { diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 066b624c1..a855b1f24 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -743,6 +743,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) #ifdef CONFIG_PASN wpas_pasn_auth_stop(wpa_s); #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 */ break; case 6: /* Bits 48-55 */ + *pos |= 0x40; /* Bit 54 - SCS */ break; case 7: /* Bits 56-63 */ 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); if (old_ssid != wpa_s->current_ssid) 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); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 60acb53c5..3417cc11f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -576,6 +576,80 @@ struct wpas_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 * @@ -1402,6 +1476,8 @@ struct wpa_supplicant { struct wpas_pasn pasn; struct wpa_radio_work *pasn_auth_work; #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); void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, 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, const u8 *bssid, int akmp, int cipher,