Home | History | Annotate | Line # | Download | only in wpa_supplicant
wnm_sta.c revision 1.1.1.1.8.2
      1  1.1.1.1.8.2  tls /*
      2  1.1.1.1.8.2  tls  * wpa_supplicant - WNM
      3  1.1.1.1.8.2  tls  * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
      4  1.1.1.1.8.2  tls  *
      5  1.1.1.1.8.2  tls  * This software may be distributed under the terms of the BSD license.
      6  1.1.1.1.8.2  tls  * See README for more details.
      7  1.1.1.1.8.2  tls  */
      8  1.1.1.1.8.2  tls 
      9  1.1.1.1.8.2  tls #include "utils/includes.h"
     10  1.1.1.1.8.2  tls 
     11  1.1.1.1.8.2  tls #include "utils/common.h"
     12  1.1.1.1.8.2  tls #include "common/ieee802_11_defs.h"
     13  1.1.1.1.8.2  tls #include "rsn_supp/wpa.h"
     14  1.1.1.1.8.2  tls #include "wpa_supplicant_i.h"
     15  1.1.1.1.8.2  tls #include "driver_i.h"
     16  1.1.1.1.8.2  tls #include "scan.h"
     17  1.1.1.1.8.2  tls 
     18  1.1.1.1.8.2  tls #define MAX_TFS_IE_LEN  1024
     19  1.1.1.1.8.2  tls 
     20  1.1.1.1.8.2  tls 
     21  1.1.1.1.8.2  tls /* get the TFS IE from driver */
     22  1.1.1.1.8.2  tls static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
     23  1.1.1.1.8.2  tls 				   u16 *buf_len, enum wnm_oper oper)
     24  1.1.1.1.8.2  tls {
     25  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
     26  1.1.1.1.8.2  tls 
     27  1.1.1.1.8.2  tls 	return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
     28  1.1.1.1.8.2  tls }
     29  1.1.1.1.8.2  tls 
     30  1.1.1.1.8.2  tls 
     31  1.1.1.1.8.2  tls /* set the TFS IE to driver */
     32  1.1.1.1.8.2  tls static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
     33  1.1.1.1.8.2  tls 				   const u8 *addr, u8 *buf, u16 *buf_len,
     34  1.1.1.1.8.2  tls 				   enum wnm_oper oper)
     35  1.1.1.1.8.2  tls {
     36  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
     37  1.1.1.1.8.2  tls 
     38  1.1.1.1.8.2  tls 	return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
     39  1.1.1.1.8.2  tls }
     40  1.1.1.1.8.2  tls 
     41  1.1.1.1.8.2  tls 
     42  1.1.1.1.8.2  tls /* MLME-SLEEPMODE.request */
     43  1.1.1.1.8.2  tls int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
     44  1.1.1.1.8.2  tls 				 u8 action, u16 intval, struct wpabuf *tfs_req)
     45  1.1.1.1.8.2  tls {
     46  1.1.1.1.8.2  tls 	struct ieee80211_mgmt *mgmt;
     47  1.1.1.1.8.2  tls 	int res;
     48  1.1.1.1.8.2  tls 	size_t len;
     49  1.1.1.1.8.2  tls 	struct wnm_sleep_element *wnmsleep_ie;
     50  1.1.1.1.8.2  tls 	u8 *wnmtfs_ie;
     51  1.1.1.1.8.2  tls 	u8 wnmsleep_ie_len;
     52  1.1.1.1.8.2  tls 	u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
     53  1.1.1.1.8.2  tls 	enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
     54  1.1.1.1.8.2  tls 		WNM_SLEEP_TFS_REQ_IE_NONE;
     55  1.1.1.1.8.2  tls 
     56  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
     57  1.1.1.1.8.2  tls 		   "action=%s to " MACSTR,
     58  1.1.1.1.8.2  tls 		   action == 0 ? "enter" : "exit",
     59  1.1.1.1.8.2  tls 		   MAC2STR(wpa_s->bssid));
     60  1.1.1.1.8.2  tls 
     61  1.1.1.1.8.2  tls 	/* WNM-Sleep Mode IE */
     62  1.1.1.1.8.2  tls 	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
     63  1.1.1.1.8.2  tls 	wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
     64  1.1.1.1.8.2  tls 	if (wnmsleep_ie == NULL)
     65  1.1.1.1.8.2  tls 		return -1;
     66  1.1.1.1.8.2  tls 	wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
     67  1.1.1.1.8.2  tls 	wnmsleep_ie->len = wnmsleep_ie_len - 2;
     68  1.1.1.1.8.2  tls 	wnmsleep_ie->action_type = action;
     69  1.1.1.1.8.2  tls 	wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
     70  1.1.1.1.8.2  tls 	wnmsleep_ie->intval = host_to_le16(intval);
     71  1.1.1.1.8.2  tls 	wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
     72  1.1.1.1.8.2  tls 		    (u8 *) wnmsleep_ie, wnmsleep_ie_len);
     73  1.1.1.1.8.2  tls 
     74  1.1.1.1.8.2  tls 	/* TFS IE(s) */
     75  1.1.1.1.8.2  tls 	if (tfs_req) {
     76  1.1.1.1.8.2  tls 		wnmtfs_ie_len = wpabuf_len(tfs_req);
     77  1.1.1.1.8.2  tls 		wnmtfs_ie = os_malloc(wnmtfs_ie_len);
     78  1.1.1.1.8.2  tls 		if (wnmtfs_ie == NULL) {
     79  1.1.1.1.8.2  tls 			os_free(wnmsleep_ie);
     80  1.1.1.1.8.2  tls 			return -1;
     81  1.1.1.1.8.2  tls 		}
     82  1.1.1.1.8.2  tls 		os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
     83  1.1.1.1.8.2  tls 	} else {
     84  1.1.1.1.8.2  tls 		wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
     85  1.1.1.1.8.2  tls 		if (wnmtfs_ie == NULL) {
     86  1.1.1.1.8.2  tls 			os_free(wnmsleep_ie);
     87  1.1.1.1.8.2  tls 			return -1;
     88  1.1.1.1.8.2  tls 		}
     89  1.1.1.1.8.2  tls 		if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
     90  1.1.1.1.8.2  tls 					    tfs_oper)) {
     91  1.1.1.1.8.2  tls 			wnmtfs_ie_len = 0;
     92  1.1.1.1.8.2  tls 			os_free(wnmtfs_ie);
     93  1.1.1.1.8.2  tls 			wnmtfs_ie = NULL;
     94  1.1.1.1.8.2  tls 		}
     95  1.1.1.1.8.2  tls 	}
     96  1.1.1.1.8.2  tls 	wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
     97  1.1.1.1.8.2  tls 		    (u8 *) wnmtfs_ie, wnmtfs_ie_len);
     98  1.1.1.1.8.2  tls 
     99  1.1.1.1.8.2  tls 	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
    100  1.1.1.1.8.2  tls 	if (mgmt == NULL) {
    101  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
    102  1.1.1.1.8.2  tls 			   "WNM-Sleep Request action frame");
    103  1.1.1.1.8.2  tls 		os_free(wnmsleep_ie);
    104  1.1.1.1.8.2  tls 		os_free(wnmtfs_ie);
    105  1.1.1.1.8.2  tls 		return -1;
    106  1.1.1.1.8.2  tls 	}
    107  1.1.1.1.8.2  tls 
    108  1.1.1.1.8.2  tls 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
    109  1.1.1.1.8.2  tls 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
    110  1.1.1.1.8.2  tls 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
    111  1.1.1.1.8.2  tls 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    112  1.1.1.1.8.2  tls 					   WLAN_FC_STYPE_ACTION);
    113  1.1.1.1.8.2  tls 	mgmt->u.action.category = WLAN_ACTION_WNM;
    114  1.1.1.1.8.2  tls 	mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
    115  1.1.1.1.8.2  tls 	mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
    116  1.1.1.1.8.2  tls 	os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
    117  1.1.1.1.8.2  tls 		  wnmsleep_ie_len);
    118  1.1.1.1.8.2  tls 	/* copy TFS IE here */
    119  1.1.1.1.8.2  tls 	if (wnmtfs_ie_len > 0) {
    120  1.1.1.1.8.2  tls 		os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
    121  1.1.1.1.8.2  tls 			  wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
    122  1.1.1.1.8.2  tls 	}
    123  1.1.1.1.8.2  tls 
    124  1.1.1.1.8.2  tls 	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
    125  1.1.1.1.8.2  tls 		wnmtfs_ie_len;
    126  1.1.1.1.8.2  tls 
    127  1.1.1.1.8.2  tls 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
    128  1.1.1.1.8.2  tls 				  wpa_s->own_addr, wpa_s->bssid,
    129  1.1.1.1.8.2  tls 				  &mgmt->u.action.category, len, 0);
    130  1.1.1.1.8.2  tls 	if (res < 0)
    131  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
    132  1.1.1.1.8.2  tls 			   "(action=%d, intval=%d)", action, intval);
    133  1.1.1.1.8.2  tls 
    134  1.1.1.1.8.2  tls 	os_free(wnmsleep_ie);
    135  1.1.1.1.8.2  tls 	os_free(wnmtfs_ie);
    136  1.1.1.1.8.2  tls 	os_free(mgmt);
    137  1.1.1.1.8.2  tls 
    138  1.1.1.1.8.2  tls 	return res;
    139  1.1.1.1.8.2  tls }
    140  1.1.1.1.8.2  tls 
    141  1.1.1.1.8.2  tls 
    142  1.1.1.1.8.2  tls static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
    143  1.1.1.1.8.2  tls 					 u8 *tfsresp_ie_start,
    144  1.1.1.1.8.2  tls 					 u8 *tfsresp_ie_end)
    145  1.1.1.1.8.2  tls {
    146  1.1.1.1.8.2  tls 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
    147  1.1.1.1.8.2  tls 			 wpa_s->bssid, NULL, NULL);
    148  1.1.1.1.8.2  tls 	/* remove GTK/IGTK ?? */
    149  1.1.1.1.8.2  tls 
    150  1.1.1.1.8.2  tls 	/* set the TFS Resp IE(s) */
    151  1.1.1.1.8.2  tls 	if (tfsresp_ie_start && tfsresp_ie_end &&
    152  1.1.1.1.8.2  tls 	    tfsresp_ie_end - tfsresp_ie_start >= 0) {
    153  1.1.1.1.8.2  tls 		u16 tfsresp_ie_len;
    154  1.1.1.1.8.2  tls 		tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
    155  1.1.1.1.8.2  tls 			tfsresp_ie_start;
    156  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
    157  1.1.1.1.8.2  tls 		/* pass the TFS Resp IE(s) to driver for processing */
    158  1.1.1.1.8.2  tls 		if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
    159  1.1.1.1.8.2  tls 					    tfsresp_ie_start,
    160  1.1.1.1.8.2  tls 					    &tfsresp_ie_len,
    161  1.1.1.1.8.2  tls 					    WNM_SLEEP_TFS_RESP_IE_SET))
    162  1.1.1.1.8.2  tls 			wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
    163  1.1.1.1.8.2  tls 	}
    164  1.1.1.1.8.2  tls }
    165  1.1.1.1.8.2  tls 
    166  1.1.1.1.8.2  tls 
    167  1.1.1.1.8.2  tls static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
    168  1.1.1.1.8.2  tls 					const u8 *frm, u16 key_len_total)
    169  1.1.1.1.8.2  tls {
    170  1.1.1.1.8.2  tls 	u8 *ptr, *end;
    171  1.1.1.1.8.2  tls 	u8 gtk_len;
    172  1.1.1.1.8.2  tls 
    173  1.1.1.1.8.2  tls 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,  wpa_s->bssid,
    174  1.1.1.1.8.2  tls 			 NULL, NULL);
    175  1.1.1.1.8.2  tls 
    176  1.1.1.1.8.2  tls 	/* Install GTK/IGTK */
    177  1.1.1.1.8.2  tls 
    178  1.1.1.1.8.2  tls 	/* point to key data field */
    179  1.1.1.1.8.2  tls 	ptr = (u8 *) frm + 1 + 1 + 2;
    180  1.1.1.1.8.2  tls 	end = ptr + key_len_total;
    181  1.1.1.1.8.2  tls 	wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
    182  1.1.1.1.8.2  tls 
    183  1.1.1.1.8.2  tls 	while (ptr + 1 < end) {
    184  1.1.1.1.8.2  tls 		if (ptr + 2 + ptr[1] > end) {
    185  1.1.1.1.8.2  tls 			wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
    186  1.1.1.1.8.2  tls 				   "length");
    187  1.1.1.1.8.2  tls 			if (end > ptr) {
    188  1.1.1.1.8.2  tls 				wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
    189  1.1.1.1.8.2  tls 					    ptr, end - ptr);
    190  1.1.1.1.8.2  tls 			}
    191  1.1.1.1.8.2  tls 			break;
    192  1.1.1.1.8.2  tls 		}
    193  1.1.1.1.8.2  tls 		if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
    194  1.1.1.1.8.2  tls 			if (ptr[1] < 11 + 5) {
    195  1.1.1.1.8.2  tls 				wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
    196  1.1.1.1.8.2  tls 					   "subelem");
    197  1.1.1.1.8.2  tls 				break;
    198  1.1.1.1.8.2  tls 			}
    199  1.1.1.1.8.2  tls 			gtk_len = *(ptr + 4);
    200  1.1.1.1.8.2  tls 			if (ptr[1] < 11 + gtk_len ||
    201  1.1.1.1.8.2  tls 			    gtk_len < 5 || gtk_len > 32) {
    202  1.1.1.1.8.2  tls 				wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
    203  1.1.1.1.8.2  tls 					   "subelem");
    204  1.1.1.1.8.2  tls 				break;
    205  1.1.1.1.8.2  tls 			}
    206  1.1.1.1.8.2  tls 			wpa_wnmsleep_install_key(
    207  1.1.1.1.8.2  tls 				wpa_s->wpa,
    208  1.1.1.1.8.2  tls 				WNM_SLEEP_SUBELEM_GTK,
    209  1.1.1.1.8.2  tls 				ptr);
    210  1.1.1.1.8.2  tls 			ptr += 13 + gtk_len;
    211  1.1.1.1.8.2  tls #ifdef CONFIG_IEEE80211W
    212  1.1.1.1.8.2  tls 		} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
    213  1.1.1.1.8.2  tls 			if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
    214  1.1.1.1.8.2  tls 				wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
    215  1.1.1.1.8.2  tls 					   "subelem");
    216  1.1.1.1.8.2  tls 				break;
    217  1.1.1.1.8.2  tls 			}
    218  1.1.1.1.8.2  tls 			wpa_wnmsleep_install_key(wpa_s->wpa,
    219  1.1.1.1.8.2  tls 						 WNM_SLEEP_SUBELEM_IGTK, ptr);
    220  1.1.1.1.8.2  tls 			ptr += 10 + WPA_IGTK_LEN;
    221  1.1.1.1.8.2  tls #endif /* CONFIG_IEEE80211W */
    222  1.1.1.1.8.2  tls 		} else
    223  1.1.1.1.8.2  tls 			break; /* skip the loop */
    224  1.1.1.1.8.2  tls 	}
    225  1.1.1.1.8.2  tls }
    226  1.1.1.1.8.2  tls 
    227  1.1.1.1.8.2  tls 
    228  1.1.1.1.8.2  tls static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    229  1.1.1.1.8.2  tls 					const u8 *frm, int len)
    230  1.1.1.1.8.2  tls {
    231  1.1.1.1.8.2  tls 	/*
    232  1.1.1.1.8.2  tls 	 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
    233  1.1.1.1.8.2  tls 	 * WNM-Sleep Mode IE | TFS Response IE
    234  1.1.1.1.8.2  tls 	 */
    235  1.1.1.1.8.2  tls 	u8 *pos = (u8 *) frm; /* point to action field */
    236  1.1.1.1.8.2  tls 	u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
    237  1.1.1.1.8.2  tls 	struct wnm_sleep_element *wnmsleep_ie = NULL;
    238  1.1.1.1.8.2  tls 	/* multiple TFS Resp IE (assuming consecutive) */
    239  1.1.1.1.8.2  tls 	u8 *tfsresp_ie_start = NULL;
    240  1.1.1.1.8.2  tls 	u8 *tfsresp_ie_end = NULL;
    241  1.1.1.1.8.2  tls 
    242  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
    243  1.1.1.1.8.2  tls 		   frm[0], frm[1], key_len_total);
    244  1.1.1.1.8.2  tls 	pos += 4 + key_len_total;
    245  1.1.1.1.8.2  tls 	if (pos > frm + len) {
    246  1.1.1.1.8.2  tls 		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
    247  1.1.1.1.8.2  tls 		return;
    248  1.1.1.1.8.2  tls 	}
    249  1.1.1.1.8.2  tls 	while (pos - frm < len) {
    250  1.1.1.1.8.2  tls 		u8 ie_len = *(pos + 1);
    251  1.1.1.1.8.2  tls 		if (pos + 2 + ie_len > frm + len) {
    252  1.1.1.1.8.2  tls 			wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
    253  1.1.1.1.8.2  tls 			break;
    254  1.1.1.1.8.2  tls 		}
    255  1.1.1.1.8.2  tls 		wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
    256  1.1.1.1.8.2  tls 		if (*pos == WLAN_EID_WNMSLEEP)
    257  1.1.1.1.8.2  tls 			wnmsleep_ie = (struct wnm_sleep_element *) pos;
    258  1.1.1.1.8.2  tls 		else if (*pos == WLAN_EID_TFS_RESP) {
    259  1.1.1.1.8.2  tls 			if (!tfsresp_ie_start)
    260  1.1.1.1.8.2  tls 				tfsresp_ie_start = pos;
    261  1.1.1.1.8.2  tls 			tfsresp_ie_end = pos;
    262  1.1.1.1.8.2  tls 		} else
    263  1.1.1.1.8.2  tls 			wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
    264  1.1.1.1.8.2  tls 		pos += ie_len + 2;
    265  1.1.1.1.8.2  tls 	}
    266  1.1.1.1.8.2  tls 
    267  1.1.1.1.8.2  tls 	if (!wnmsleep_ie) {
    268  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
    269  1.1.1.1.8.2  tls 		return;
    270  1.1.1.1.8.2  tls 	}
    271  1.1.1.1.8.2  tls 
    272  1.1.1.1.8.2  tls 	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
    273  1.1.1.1.8.2  tls 	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
    274  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
    275  1.1.1.1.8.2  tls 			   "frame (action=%d, intval=%d)",
    276  1.1.1.1.8.2  tls 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
    277  1.1.1.1.8.2  tls 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
    278  1.1.1.1.8.2  tls 			wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
    279  1.1.1.1.8.2  tls 						     tfsresp_ie_end);
    280  1.1.1.1.8.2  tls 		} else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
    281  1.1.1.1.8.2  tls 			wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
    282  1.1.1.1.8.2  tls 		}
    283  1.1.1.1.8.2  tls 	} else {
    284  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
    285  1.1.1.1.8.2  tls 			   "(action=%d, intval=%d)",
    286  1.1.1.1.8.2  tls 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
    287  1.1.1.1.8.2  tls 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
    288  1.1.1.1.8.2  tls 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
    289  1.1.1.1.8.2  tls 					 wpa_s->bssid, NULL, NULL);
    290  1.1.1.1.8.2  tls 		else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
    291  1.1.1.1.8.2  tls 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
    292  1.1.1.1.8.2  tls 					 wpa_s->bssid, NULL, NULL);
    293  1.1.1.1.8.2  tls 	}
    294  1.1.1.1.8.2  tls }
    295  1.1.1.1.8.2  tls 
    296  1.1.1.1.8.2  tls 
    297  1.1.1.1.8.2  tls static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
    298  1.1.1.1.8.2  tls 					      u8 dialog_token, u8 status,
    299  1.1.1.1.8.2  tls 					      u8 delay, const u8 *target_bssid)
    300  1.1.1.1.8.2  tls {
    301  1.1.1.1.8.2  tls 	u8 buf[1000], *pos;
    302  1.1.1.1.8.2  tls 	struct ieee80211_mgmt *mgmt;
    303  1.1.1.1.8.2  tls 	size_t len;
    304  1.1.1.1.8.2  tls 
    305  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
    306  1.1.1.1.8.2  tls 		   "to " MACSTR " dialog_token=%u status=%u delay=%d",
    307  1.1.1.1.8.2  tls 		   MAC2STR(wpa_s->bssid), dialog_token, status, delay);
    308  1.1.1.1.8.2  tls 
    309  1.1.1.1.8.2  tls 	mgmt = (struct ieee80211_mgmt *) buf;
    310  1.1.1.1.8.2  tls 	os_memset(&buf, 0, sizeof(buf));
    311  1.1.1.1.8.2  tls 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
    312  1.1.1.1.8.2  tls 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
    313  1.1.1.1.8.2  tls 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
    314  1.1.1.1.8.2  tls 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    315  1.1.1.1.8.2  tls 					   WLAN_FC_STYPE_ACTION);
    316  1.1.1.1.8.2  tls 	mgmt->u.action.category = WLAN_ACTION_WNM;
    317  1.1.1.1.8.2  tls 	mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
    318  1.1.1.1.8.2  tls 	mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
    319  1.1.1.1.8.2  tls 	mgmt->u.action.u.bss_tm_resp.status_code = status;
    320  1.1.1.1.8.2  tls 	mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
    321  1.1.1.1.8.2  tls 	pos = mgmt->u.action.u.bss_tm_resp.variable;
    322  1.1.1.1.8.2  tls 	if (target_bssid) {
    323  1.1.1.1.8.2  tls 		os_memcpy(pos, target_bssid, ETH_ALEN);
    324  1.1.1.1.8.2  tls 		pos += ETH_ALEN;
    325  1.1.1.1.8.2  tls 	}
    326  1.1.1.1.8.2  tls 
    327  1.1.1.1.8.2  tls 	len = pos - (u8 *) &mgmt->u.action.category;
    328  1.1.1.1.8.2  tls 
    329  1.1.1.1.8.2  tls 	wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
    330  1.1.1.1.8.2  tls 			    wpa_s->own_addr, wpa_s->bssid,
    331  1.1.1.1.8.2  tls 			    &mgmt->u.action.category, len, 0);
    332  1.1.1.1.8.2  tls }
    333  1.1.1.1.8.2  tls 
    334  1.1.1.1.8.2  tls 
    335  1.1.1.1.8.2  tls static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
    336  1.1.1.1.8.2  tls 					     const u8 *pos, const u8 *end,
    337  1.1.1.1.8.2  tls 					     int reply)
    338  1.1.1.1.8.2  tls {
    339  1.1.1.1.8.2  tls 	u8 dialog_token;
    340  1.1.1.1.8.2  tls 	u8 mode;
    341  1.1.1.1.8.2  tls 	u16 disassoc_timer;
    342  1.1.1.1.8.2  tls 
    343  1.1.1.1.8.2  tls 	if (pos + 5 > end)
    344  1.1.1.1.8.2  tls 		return;
    345  1.1.1.1.8.2  tls 
    346  1.1.1.1.8.2  tls 	dialog_token = pos[0];
    347  1.1.1.1.8.2  tls 	mode = pos[1];
    348  1.1.1.1.8.2  tls 	disassoc_timer = WPA_GET_LE16(pos + 2);
    349  1.1.1.1.8.2  tls 
    350  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
    351  1.1.1.1.8.2  tls 		   "dialog_token=%u request_mode=0x%x "
    352  1.1.1.1.8.2  tls 		   "disassoc_timer=%u validity_interval=%u",
    353  1.1.1.1.8.2  tls 		   dialog_token, mode, disassoc_timer, pos[4]);
    354  1.1.1.1.8.2  tls 	pos += 5;
    355  1.1.1.1.8.2  tls 	if (mode & 0x08)
    356  1.1.1.1.8.2  tls 		pos += 12; /* BSS Termination Duration */
    357  1.1.1.1.8.2  tls 	if (mode & 0x10) {
    358  1.1.1.1.8.2  tls 		char url[256];
    359  1.1.1.1.8.2  tls 		if (pos + 1 > end || pos + 1 + pos[0] > end) {
    360  1.1.1.1.8.2  tls 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
    361  1.1.1.1.8.2  tls 				   "Management Request (URL)");
    362  1.1.1.1.8.2  tls 			return;
    363  1.1.1.1.8.2  tls 		}
    364  1.1.1.1.8.2  tls 		os_memcpy(url, pos + 1, pos[0]);
    365  1.1.1.1.8.2  tls 		url[pos[0]] = '\0';
    366  1.1.1.1.8.2  tls 		wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
    367  1.1.1.1.8.2  tls 			"session_info_url=%s", url);
    368  1.1.1.1.8.2  tls 	}
    369  1.1.1.1.8.2  tls 
    370  1.1.1.1.8.2  tls 	if (mode & 0x04) {
    371  1.1.1.1.8.2  tls 		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
    372  1.1.1.1.8.2  tls 			"Disassociation Timer %u", disassoc_timer);
    373  1.1.1.1.8.2  tls 		if (disassoc_timer && !wpa_s->scanning) {
    374  1.1.1.1.8.2  tls 			/* TODO: mark current BSS less preferred for
    375  1.1.1.1.8.2  tls 			 * selection */
    376  1.1.1.1.8.2  tls 			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
    377  1.1.1.1.8.2  tls 			wpa_supplicant_req_scan(wpa_s, 0, 0);
    378  1.1.1.1.8.2  tls 		}
    379  1.1.1.1.8.2  tls 	}
    380  1.1.1.1.8.2  tls 
    381  1.1.1.1.8.2  tls 	if (reply) {
    382  1.1.1.1.8.2  tls 		/* TODO: add support for reporting Accept */
    383  1.1.1.1.8.2  tls 		wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
    384  1.1.1.1.8.2  tls 						  1 /* Reject - unspecified */,
    385  1.1.1.1.8.2  tls 						  0, NULL);
    386  1.1.1.1.8.2  tls 	}
    387  1.1.1.1.8.2  tls }
    388  1.1.1.1.8.2  tls 
    389  1.1.1.1.8.2  tls 
    390  1.1.1.1.8.2  tls void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
    391  1.1.1.1.8.2  tls 			      struct rx_action *action)
    392  1.1.1.1.8.2  tls {
    393  1.1.1.1.8.2  tls 	const u8 *pos, *end;
    394  1.1.1.1.8.2  tls 	u8 act;
    395  1.1.1.1.8.2  tls 
    396  1.1.1.1.8.2  tls 	if (action->data == NULL || action->len == 0)
    397  1.1.1.1.8.2  tls 		return;
    398  1.1.1.1.8.2  tls 
    399  1.1.1.1.8.2  tls 	pos = action->data;
    400  1.1.1.1.8.2  tls 	end = pos + action->len;
    401  1.1.1.1.8.2  tls 	act = *pos++;
    402  1.1.1.1.8.2  tls 
    403  1.1.1.1.8.2  tls 	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
    404  1.1.1.1.8.2  tls 		   act, MAC2STR(action->sa));
    405  1.1.1.1.8.2  tls 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
    406  1.1.1.1.8.2  tls 	    os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
    407  1.1.1.1.8.2  tls 		wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
    408  1.1.1.1.8.2  tls 			   "frame");
    409  1.1.1.1.8.2  tls 		return;
    410  1.1.1.1.8.2  tls 	}
    411  1.1.1.1.8.2  tls 
    412  1.1.1.1.8.2  tls 	switch (act) {
    413  1.1.1.1.8.2  tls 	case WNM_BSS_TRANS_MGMT_REQ:
    414  1.1.1.1.8.2  tls 		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
    415  1.1.1.1.8.2  tls 						 !(action->da[0] & 0x01));
    416  1.1.1.1.8.2  tls 		break;
    417  1.1.1.1.8.2  tls 	case WNM_SLEEP_MODE_RESP:
    418  1.1.1.1.8.2  tls 		ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
    419  1.1.1.1.8.2  tls 		break;
    420  1.1.1.1.8.2  tls 	default:
    421  1.1.1.1.8.2  tls 		break;
    422  1.1.1.1.8.2  tls 	}
    423  1.1.1.1.8.2  tls }
    424