diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b12d34909..7a27abdb6 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4679,6 +4679,8 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) int enter; int intval = 0; char *pos; + int ret; + struct wpabuf *tfs_req = NULL; if (os_strncmp(cmd, "enter", 5) == 0) enter = 1; @@ -4691,7 +4693,33 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) if (pos) intval = atoi(pos + 10); - return ieee802_11_send_wnmsleep_req(wpa_s, enter ? 0 : 1, intval); + pos = os_strstr(cmd, " tfs_req="); + if (pos) { + char *end; + size_t len; + pos += 9; + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + tfs_req = wpabuf_alloc(len); + if (tfs_req == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) { + wpabuf_free(tfs_req); + return -1; + } + } + + ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? 0 : 1, intval, + tfs_req); + wpabuf_free(tfs_req); + + return ret; } #endif /* CONFIG_WNM */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 35ba8e466..492674669 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2150,7 +2150,7 @@ static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s, "(action=%d, intval=%d)", data->wnm.sleep_action, data->wnm.sleep_intval); ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action, - data->wnm.sleep_intval); + data->wnm.sleep_intval, NULL); break; } } diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index e81ef3134..bcd1d4a86 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -41,7 +41,7 @@ static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, /* MLME-SLEEPMODE.request */ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, - u8 action, u16 intval) + u8 action, u16 intval, struct wpabuf *tfs_req) { struct ieee80211_mgmt *mgmt; int res; @@ -53,6 +53,11 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : WNM_SLEEP_TFS_REQ_IE_NONE; + wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " + "action=%s to " MACSTR, + action == 0 ? "enter" : "exit", + MAC2STR(wpa_s->bssid)); + /* WNM-Sleep Mode IE */ wnmsleep_ie_len = sizeof(struct wnm_sleep_element); wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); @@ -63,19 +68,33 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, wnmsleep_ie->action_type = action; wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; wnmsleep_ie->intval = host_to_le16(intval); + wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", + (u8 *) wnmsleep_ie, wnmsleep_ie_len); /* TFS IE(s) */ - wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); - if (wnmtfs_ie == NULL) { - os_free(wnmsleep_ie); - return -1; - } - if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, - tfs_oper)) { - wnmtfs_ie_len = 0; - os_free(wnmtfs_ie); - wnmtfs_ie = NULL; + if (tfs_req) { + wnmtfs_ie_len = wpabuf_len(tfs_req); + wnmtfs_ie = os_malloc(wnmtfs_ie_len); + if (wnmtfs_ie == NULL) { + os_free(wnmsleep_ie); + return -1; + } + os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); + } else { + wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); + if (wnmtfs_ie == NULL) { + os_free(wnmsleep_ie); + return -1; + } + if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, + tfs_oper)) { + wnmtfs_ie_len = 0; + os_free(wnmtfs_ie); + wnmtfs_ie = NULL; + } } + wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", + (u8 *) wnmtfs_ie, wnmtfs_ie_len); mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); if (mgmt == NULL) { diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 96fe0d9c6..3f9d88b71 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -13,7 +13,7 @@ struct rx_action; struct wpa_supplicant; int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, - u8 action, u16 intval); + u8 action, u16 intval, struct wpabuf *tfs_req); void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, struct rx_action *action);