static int wmm_ac_send_delts(struct wpa_supplicant *wpa_s, const struct wmm_tspec_element *tspec, const u8 *address) { struct wpabuf *buf; int ret; /* category + action code + dialog token + status + sizeof(tspec) */ buf = wpabuf_alloc(4 + sizeof(*tspec)); if (!buf) return -1; wpa_printf(MSG_DEBUG, "Sending DELTS to " MACSTR, MAC2STR(address)); /* category + action code + dialog token + status + sizeof(tspec) */ wpabuf_put_u8(buf, WLAN_ACTION_WMM); wpabuf_put_u8(buf, WMM_ACTION_CODE_DELTS); wpabuf_put_u8(buf, 0); /* Dialog Token (not used) */ wpabuf_put_u8(buf, 0); /* Status Code (not used) */ wpabuf_put_data(buf, tspec, sizeof(*tspec)); ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, address, wpa_s->own_addr, wpa_s->bssid, wpabuf_head(buf), wpabuf_len(buf), 0); if (ret) wpa_printf(MSG_WARNING, "Failed to send DELTS frame"); wpabuf_free(buf); return ret; }
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, u8 query_reason) { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t len; int ret; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " MACSTR " query_reason=%u", MAC2STR(wpa_s->bssid), query_reason); mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; mgmt->u.action.u.bss_tm_query.dialog_token = 1; mgmt->u.action.u.bss_tm_query.query_reason = query_reason; pos = mgmt->u.action.u.bss_tm_query.variable; len = pos - (u8 *) &mgmt->u.action.category; ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); return ret; }
static int wmm_ac_send_addts_request(struct wpa_supplicant *wpa_s, const struct wmm_ac_addts_request *req) { struct wpabuf *buf; int ret; wpa_printf(MSG_DEBUG, "Sending ADDTS Request to " MACSTR, MAC2STR(req->address)); /* category + action code + dialog token + status + sizeof(tspec) */ buf = wpabuf_alloc(4 + sizeof(req->tspec)); if (!buf) { wpa_printf(MSG_ERROR, "WMM AC: Allocation error"); return -1; } wpabuf_put_u8(buf, WLAN_ACTION_WMM); wpabuf_put_u8(buf, WMM_ACTION_CODE_ADDTS_REQ); wpabuf_put_u8(buf, req->dialog_token); wpabuf_put_u8(buf, 0); /* status code */ wpabuf_put_data(buf, &req->tspec, sizeof(req->tspec)); ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, req->address, wpa_s->own_addr, wpa_s->bssid, wpabuf_head(buf), wpabuf_len(buf), 0); if (ret) { wpa_printf(MSG_WARNING, "WMM AC: Failed to send ADDTS Request"); } wpabuf_free(buf); return ret; }
static void wnm_send_bss_transition_mgmt_resp( struct wpa_supplicant *wpa_s, u8 dialog_token, enum bss_trans_mgmt_status_code status, u8 delay, const u8 *target_bssid) { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t len; int res; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " "to " MACSTR " dialog_token=%u status=%u delay=%d", MAC2STR(wpa_s->bssid), dialog_token, status, delay); if (!wpa_s->current_bss) { wpa_printf(MSG_DEBUG, "WNM: Current BSS not known - drop response"); return; } mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; mgmt->u.action.u.bss_tm_resp.status_code = status; mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; pos = mgmt->u.action.u.bss_tm_resp.variable; if (target_bssid) { os_memcpy(pos, target_bssid, ETH_ALEN); pos += ETH_ALEN; } else if (status == WNM_BSS_TM_ACCEPT) { /* * P802.11-REVmc clarifies that the Target BSSID field is always * present when status code is zero, so use a fake value here if * no BSSID is yet known. */ os_memset(pos, 0, ETH_ALEN); pos += ETH_ALEN; } len = pos - (u8 *) &mgmt->u.action.category; res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); if (res < 0) { wpa_printf(MSG_DEBUG, "WNM: Failed to send BSS Transition Management Response"); } }
static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s, const u8 *chan_list, u8 num_channels, u8 num_intol) { struct ieee80211_2040_bss_coex_ie *bc_ie; struct ieee80211_2040_intol_chan_report *ic_report; struct wpabuf *buf; wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR " (num_channels=%u num_intol=%u)", MAC2STR(wpa_s->bssid), num_channels, num_intol); wpa_hexdump(MSG_DEBUG, "SME: 20/40 BSS Intolerant Channels", chan_list, num_channels); buf = wpabuf_alloc(2 + /* action.category + action_code */ sizeof(struct ieee80211_2040_bss_coex_ie) + sizeof(struct ieee80211_2040_intol_chan_report) + num_channels); if (buf == NULL) return; wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX); bc_ie = wpabuf_put(buf, sizeof(*bc_ie)); bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE; bc_ie->length = 1; if (num_intol) bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ; if (num_channels > 0) { ic_report = wpabuf_put(buf, sizeof(*ic_report)); ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT; ic_report->length = num_channels + 1; ic_report->op_class = 0; os_memcpy(wpabuf_put(buf, num_channels), chan_list, num_channels); } if (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) < 0) { wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send 20/40 BSS Coexistence frame"); } wpabuf_free(buf); }
static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s, const u8 *trans_id) { u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN]; wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to " MACSTR, MAC2STR(wpa_s->bssid)); wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID", trans_id, WLAN_SA_QUERY_TR_ID_LEN); req[0] = WLAN_ACTION_SA_QUERY; req[1] = WLAN_SA_QUERY_REQUEST; os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN); if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, req, sizeof(req), 0) < 0) wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query " "Request"); }
static int wpa_supplicant_send_ft_action(void *ctx, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len) { struct wpa_supplicant *wpa_s = ctx; int ret; u8 *data, *pos; size_t data_len; if (action != 1) { wpa_printf(MSG_ERROR, "Unsupported send_ft_action action %d", action); return -1; } /* * Action frame payload: * Category[1] = 6 (Fast BSS Transition) * Action[1] = 1 (Fast BSS Transition Request) * STA Address * Target AP Address * FT IEs */ data_len = 2 + 2 * ETH_ALEN + ies_len; data = os_malloc(data_len); if (data == NULL) return -1; pos = data; *pos++ = 0x06; /* FT Action category */ *pos++ = action; os_memcpy(pos, wpa_s->own_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, target_ap, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, ies, ies_len); ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, data, data_len, 0); os_free(data); return ret; }
static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s, const u8 *data, size_t len) { struct wpabuf *buf; int res; /* * Send WNM-Notification Request frame only in case of a change in * non-preferred channels list during association, if the AP supports * MBO. */ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss || !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) return; buf = wpabuf_alloc(4 + len); if (!buf) return; wpabuf_put_u8(buf, WLAN_ACTION_WNM); wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ); wpa_s->mbo_wnm_token++; if (wpa_s->mbo_wnm_token == 0) wpa_s->mbo_wnm_token++; wpabuf_put_u8(buf, wpa_s->mbo_wnm_token); wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */ wpabuf_put_data(buf, data, len); res = 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 (res < 0) wpa_printf(MSG_DEBUG, "Failed to send WNM-Notification Request frame with non-preferred channel list"); wpabuf_free(buf); }
static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_supplicant *iface; int res; int without_roc; without_roc = wpa_s->pending_action_without_roc; wpa_s->pending_action_without_roc = 0; wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback (without_roc=%d pending_action_tx=%p pending_action_tx_done=%d)", without_roc, wpa_s->pending_action_tx, !!wpa_s->pending_action_tx_done); if (wpa_s->pending_action_tx == NULL || wpa_s->pending_action_tx_done) return; /* * This call is likely going to be on the P2P device instance if the * driver uses a separate interface for that purpose. However, some * Action frames are actually sent within a P2P Group and when that is * the case, we need to follow power saving (e.g., GO buffering the * frame for a client in PS mode or a client following the advertised * NoA from its GO). To make that easier for the driver, select the * correct group interface here. */ iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src); if (wpa_s->off_channel_freq != wpa_s->pending_action_freq && wpa_s->pending_action_freq != 0 && wpa_s->pending_action_freq != iface->assoc_freq) { wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX " "waiting for another freq=%u (off_channel_freq=%u " "assoc_freq=%u)", wpa_s->pending_action_freq, wpa_s->off_channel_freq, iface->assoc_freq); if (without_roc && wpa_s->off_channel_freq == 0) { unsigned int duration = 200; /* * We may get here if wpas_send_action() found us to be * on the correct channel, but remain-on-channel cancel * event was received before getting here. */ wpa_printf(MSG_DEBUG, "Off-channel: Schedule " "remain-on-channel to send Action frame"); #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->extra_roc_dur) { wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u", duration, duration + wpa_s->extra_roc_dur); duration += wpa_s->extra_roc_dur; } #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_drv_remain_on_channel( wpa_s, wpa_s->pending_action_freq, duration) < 0) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to " "request driver to remain on " "channel (%u MHz) for Action Frame " "TX", wpa_s->pending_action_freq); } else { wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = wpa_s->pending_action_freq; } } return; } wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to " MACSTR " using interface %s", MAC2STR(wpa_s->pending_action_dst), iface->ifname); res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), wpa_s->pending_action_no_cck); if (res) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the " "pending Action frame"); /* * Use fake TX status event to allow state machines to * continue. */ offchannel_send_action_tx_status( wpa_s, wpa_s->pending_action_dst, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), OFFCHANNEL_SEND_ACTION_FAILED); } }
/** * offchannel_send_action - Request off-channel Action frame TX * @wpa_s: Pointer to wpa_supplicant data * @freq: The frequency in MHz indicating the channel on which the frame is to * transmitted or 0 for the current channel (only if associated) * @dst: Action frame destination MAC address * @src: Action frame source MAC address * @bssid: Action frame BSSID * @buf: Frame to transmit starting from the Category field * @len: Length of @buf in bytes * @wait_time: Wait time for response in milliseconds * @tx_cb: Callback function for indicating TX status or %NULL for now callback * @no_cck: Whether CCK rates are to be disallowed for TX rate selection * Returns: 0 on success or -1 on failure * * This function is used to request an Action frame to be transmitted on the * current operating channel or on another channel (off-channel). The actual * frame transmission will be delayed until the driver is ready on the specified * channel. The @wait_time parameter can be used to request the driver to remain * awake on the channel to wait for a response. */ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time, void (*tx_cb)(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result), int no_cck) { wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst=" MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d", freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), (int) len); wpa_s->pending_action_tx_status_cb = tx_cb; if (wpa_s->pending_action_tx) { wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action " "frame TX to " MACSTR, MAC2STR(wpa_s->pending_action_dst)); wpabuf_free(wpa_s->pending_action_tx); } wpa_s->pending_action_tx_done = 0; wpa_s->pending_action_tx = wpabuf_alloc(len); if (wpa_s->pending_action_tx == NULL) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action " "frame TX buffer (len=%llu)", (unsigned long long) len); return -1; } wpabuf_put_data(wpa_s->pending_action_tx, buf, len); os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN); os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN); os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN); wpa_s->pending_action_freq = freq; wpa_s->pending_action_no_cck = no_cck; if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) { struct wpa_supplicant *iface; int ret; iface = wpas_get_tx_interface(wpa_s, src); wpa_s->action_tx_wait_time = wait_time; ret = wpa_drv_send_action( iface, wpa_s->pending_action_freq, wait_time, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), wpa_s->pending_action_no_cck); if (ret == 0) wpa_s->pending_action_tx_done = 1; return ret; } if (freq) { struct wpa_supplicant *tx_iface; tx_iface = wpas_get_tx_interface(wpa_s, src); if (tx_iface->assoc_freq == freq) { wpa_printf(MSG_DEBUG, "Off-channel: Already on " "requested channel (TX interface operating " "channel)"); freq = 0; } } if (wpa_s->off_channel_freq == freq || freq == 0) { wpa_printf(MSG_DEBUG, "Off-channel: Already on requested " "channel; send Action frame immediately"); /* TODO: Would there ever be need to extend the current * duration on the channel? */ wpa_s->pending_action_without_roc = 1; eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL); eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL); return 0; } wpa_s->pending_action_without_roc = 0; if (wpa_s->roc_waiting_drv_freq == freq) { wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for " "driver to get to frequency %u MHz; continue " "waiting to send the Action frame", freq); return 0; } wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be " "transmitted once the driver gets to the requested " "channel"); if (wait_time > wpa_s->max_remain_on_chan) wait_time = wpa_s->max_remain_on_chan; else if (wait_time == 0) wait_time = 20; #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->extra_roc_dur) { wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u", wait_time, wait_time + wpa_s->extra_roc_dur); wait_time += wpa_s->extra_roc_dur; } #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver " "to remain on channel (%u MHz) for Action " "Frame TX", freq); return -1; } wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = freq; return 0; }
/* MLME-SLEEPMODE.request */ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req) { struct ieee80211_mgmt *mgmt; int res; size_t len; struct wnm_sleep_element *wnmsleep_ie; u8 *wnmtfs_ie; u8 wnmsleep_ie_len; u16 wnmtfs_ie_len; /* possibly multiple IE(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)); if (wnmsleep_ie == NULL) return -1; wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; wnmsleep_ie->len = wnmsleep_ie_len - 2; 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) */ 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) { wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " "WNM-Sleep Request action frame"); os_free(wnmsleep_ie); os_free(wnmtfs_ie); return -1; } os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, wnmsleep_ie_len); /* copy TFS IE here */ if (wnmtfs_ie_len > 0) { os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); } len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + wnmtfs_ie_len; res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); if (res < 0) wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " "(action=%d, intval=%d)", action, intval); else wpa_s->wnmsleep_used = 1; os_free(wnmsleep_ie); os_free(wnmtfs_ie); os_free(mgmt); return res; }