diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 98cbf3e0a..05f15ff46 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1154,3 +1154,10 @@ associated AP. wpa_supplicant sends DSCP policy response based on the control interface command received from the user is as below: DSCP_RESP <[reset]>/<[solicited] [policy_id=1 status=0...]> [more] + +DSCP Query: +DSCP Policy Query enables a STA to query its associated AP for DSCP +policies applicable to the STA. Currently, this includes support to send +a wildcard DSCP query or a DSCP query with a single domain name +attribute. The command format for the DSCP query command is as follows: +DSCP_QUERY /> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 17f21e91a..8bdf5772f 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -11455,6 +11455,35 @@ fail: } +static int wpas_ctrl_iface_send_dscp_query(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + char *pos; + + /* + * format: + * Wildcard DSCP query + * + * + * DSCP query with a domain name attribute: + * [domain_name=] + */ + + if (os_strstr(cmd, "wildcard")) { + wpa_printf(MSG_DEBUG, "QM: Send wildcard DSCP policy query"); + return wpas_send_dscp_query(wpa_s, NULL, 0); + } + + pos = os_strstr(cmd, "domain_name="); + if (!pos || !os_strlen(pos + 12)) { + wpa_printf(MSG_ERROR, "QM: Domain name not preset"); + return -1; + } + + return wpas_send_dscp_query(wpa_s, pos + 12, os_strlen(pos + 12)); +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -12386,6 +12415,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DSCP_RESP ", 10) == 0) { if (wpas_ctrl_iface_send_dscp_resp(wpa_s, buf + 10)) reply_len = -1; + } else if (os_strncmp(buf, "DSCP_QUERY ", 11) == 0) { + if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11)) + 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 4eabf2448..770c8fcab 100644 --- a/wpa_supplicant/robust_av.c +++ b/wpa_supplicant/robust_av.c @@ -1159,6 +1159,7 @@ 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; + wpa_s->dscp_query_dialog_token = 0; wpa_s->connection_dscp = 0; if (wpa_s->wait_for_dscp_req) { wpa_s->wait_for_dscp_req = 0; @@ -1410,3 +1411,77 @@ fail: wpabuf_free(buf); return ret; } + + +int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name, + size_t domain_name_length) +{ + struct wpabuf *buf = NULL; + int ret, dscp_query_size; + + if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) + return -1; + + if (!wpa_s->connection_dscp) { + wpa_printf(MSG_ERROR, + "QM: Failed to send DSCP query - DSCP capability not enabled for the current association"); + return -1; + } + + if (wpa_s->wait_for_dscp_req) { + wpa_printf(MSG_INFO, "QM: Wait until AP sends a DSCP request"); + return -1; + } + +#define DOMAIN_NAME_OFFSET (4 /* OUI */ + 1 /* Attr Id */ + 1 /* Attr len */) + + if (domain_name_length > 255 - DOMAIN_NAME_OFFSET) { + wpa_printf(MSG_ERROR, "QM: Too long domain name"); + return -1; + } + + dscp_query_size = 1 + /* Category */ + 4 + /* OUI Type */ + 1 + /* OUI subtype */ + 1; /* Dialog Token */ + if (domain_name && domain_name_length) + dscp_query_size += 1 + /* Element ID */ + 1 + /* IE Length */ + DOMAIN_NAME_OFFSET + domain_name_length; + + buf = wpabuf_alloc(dscp_query_size); + if (!buf) { + wpa_printf(MSG_ERROR, "QM: Failed to allocate DSCP query"); + return -1; + } + + wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED); + wpabuf_put_be32(buf, QM_ACTION_VENDOR_TYPE); + wpabuf_put_u8(buf, QM_DSCP_POLICY_QUERY); + wpa_s->dscp_query_dialog_token++; + if (wpa_s->dscp_query_dialog_token == 0) + wpa_s->dscp_query_dialog_token++; + wpabuf_put_u8(buf, wpa_s->dscp_query_dialog_token); + + if (domain_name && domain_name_length) { + /* Domain Name attribute */ + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(buf, DOMAIN_NAME_OFFSET + domain_name_length); + wpabuf_put_be32(buf, QM_IE_VENDOR_TYPE); + wpabuf_put_u8(buf, QM_ATTR_DOMAIN_NAME); + wpabuf_put_u8(buf, domain_name_length); + wpabuf_put_data(buf, domain_name, domain_name_length); + } +#undef DOMAIN_NAME_OFFSET + + 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, "QM: Failed to send DSCP query"); + wpa_s->dscp_query_dialog_token--; + } + + wpabuf_free(buf); + return ret; +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 428dfe8e6..47d0cabbe 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1514,6 +1514,7 @@ struct wpa_supplicant { struct dl_list active_scs_ids; bool ongoing_scs_req; u8 dscp_req_dialog_token; + u8 dscp_query_dialog_token; unsigned int enable_dscp_policy_capa:1; unsigned int connection_dscp:1; unsigned int wait_for_dscp_req:1; @@ -1865,6 +1866,8 @@ int wpas_send_dscp_response(struct wpa_supplicant *wpa_s, struct dscp_resp_data *resp_data); void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len); +int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name, + size_t domain_name_length); int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher,