mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-02-07 04:34:04 -05:00
atheros: Implement WNM-Sleep Mode driver operations
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
75cad1a0d4
commit
c7673de462
@ -875,7 +875,56 @@ static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
|
#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
|
||||||
|
static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct atheros_driver_data *drv = ctx;
|
||||||
|
union wpa_event_data event;
|
||||||
|
const struct ieee80211_mgmt *mgmt;
|
||||||
|
u16 fc;
|
||||||
|
u16 stype;
|
||||||
|
|
||||||
|
/* Do 11R processing for WNM ACTION frames */
|
||||||
|
if (len < IEEE80211_HDRLEN)
|
||||||
|
return;
|
||||||
|
mgmt = (const struct ieee80211_mgmt *) buf;
|
||||||
|
|
||||||
|
fc = le_to_host16(mgmt->frame_control);
|
||||||
|
|
||||||
|
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
|
||||||
|
return;
|
||||||
|
stype = WLAN_FC_GET_STYPE(fc);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
|
||||||
|
(int) len);
|
||||||
|
|
||||||
|
if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
|
||||||
|
__func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stype) {
|
||||||
|
case WLAN_FC_STYPE_ACTION:
|
||||||
|
if (&mgmt->u.action.category > buf + len)
|
||||||
|
break;
|
||||||
|
os_memset(&event, 0, sizeof(event));
|
||||||
|
event.rx_action.da = mgmt->da;
|
||||||
|
event.rx_action.sa = mgmt->sa;
|
||||||
|
event.rx_action.bssid = mgmt->bssid;
|
||||||
|
event.rx_action.category = mgmt->u.action.category;
|
||||||
|
event.rx_action.data = &mgmt->u.action.category;
|
||||||
|
event.rx_action.len = buf + len - event.rx_action.data;
|
||||||
|
wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211V */
|
||||||
|
|
||||||
|
#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211V)
|
||||||
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
@ -885,6 +934,9 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
|||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
atheros_raw_recv_11r(ctx, src_addr, buf, len);
|
atheros_raw_recv_11r(ctx, src_addr, buf, len);
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
|
||||||
|
atheros_raw_recv_11v(ctx, src_addr, buf, len);
|
||||||
|
#endif /* CONFIG_IEEE80211V */
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
atheros_raw_recv_hs20(ctx, src_addr, buf, len);
|
atheros_raw_recv_hs20(ctx, src_addr, buf, len);
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
@ -906,6 +958,9 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
|
|||||||
IEEE80211_FILTER_TYPE_AUTH |
|
IEEE80211_FILTER_TYPE_AUTH |
|
||||||
IEEE80211_FILTER_TYPE_ACTION);
|
IEEE80211_FILTER_TYPE_ACTION);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_IEEE80211V
|
||||||
|
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
|
||||||
|
#endif /* CONFIG_IEEE80211V */
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
|
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
@ -1906,6 +1961,162 @@ static int atheros_send_action(void *priv, unsigned int freq,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211V
|
||||||
|
static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
|
||||||
|
u8 *ie, u16 *len, enum wnm_oper oper)
|
||||||
|
{
|
||||||
|
#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */
|
||||||
|
u8 buf[IEEE80211_APPIE_MAX];
|
||||||
|
struct ieee80211req_getset_appiebuf *tfs_ie;
|
||||||
|
u16 val;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
|
||||||
|
drv->iface, oper, MAC2STR(peer));
|
||||||
|
|
||||||
|
switch (oper) {
|
||||||
|
case WNM_SLEEP_TFS_REQ_IE_SET:
|
||||||
|
if (*len > IEEE80211_APPIE_MAX -
|
||||||
|
sizeof(struct ieee80211req_getset_appiebuf)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
|
||||||
|
tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
|
||||||
|
tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
|
||||||
|
|
||||||
|
/* Command header for driver */
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
|
||||||
|
val = oper;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
|
||||||
|
val = *len;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
|
||||||
|
|
||||||
|
/* copy the ie */
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
|
||||||
|
|
||||||
|
if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
|
||||||
|
IEEE80211_APPIE_MAX)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
|
||||||
|
"%s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WNM_SLEEP_TFS_RESP_IE_ADD:
|
||||||
|
tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
|
||||||
|
tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
|
||||||
|
tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
|
||||||
|
sizeof(struct ieee80211req_getset_appiebuf);
|
||||||
|
/* Command header for driver */
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
|
||||||
|
val = oper;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
|
||||||
|
val = 0;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
|
||||||
|
|
||||||
|
if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
|
||||||
|
IEEE80211_APPIE_MAX)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
|
||||||
|
"%s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*len = tfs_ie->app_buflen;
|
||||||
|
os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
|
||||||
|
wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
|
||||||
|
*len);
|
||||||
|
break;
|
||||||
|
case WNM_SLEEP_TFS_RESP_IE_NONE:
|
||||||
|
*len = 0;
|
||||||
|
break;
|
||||||
|
case WNM_SLEEP_TFS_IE_DEL:
|
||||||
|
tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
|
||||||
|
tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
|
||||||
|
tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
|
||||||
|
sizeof(struct ieee80211req_getset_appiebuf);
|
||||||
|
/* Command header for driver */
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
|
||||||
|
val = oper;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
|
||||||
|
val = 0;
|
||||||
|
os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
|
||||||
|
|
||||||
|
if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
|
||||||
|
IEEE80211_APPIE_MAX)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
|
||||||
|
"%s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int atheros_wnm_sleep(struct atheros_driver_data *drv,
|
||||||
|
const u8 *peer, enum wnm_oper oper)
|
||||||
|
{
|
||||||
|
u8 *data, *pos;
|
||||||
|
size_t dlen;
|
||||||
|
int ret;
|
||||||
|
u16 val;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
|
||||||
|
oper, MAC2STR(peer));
|
||||||
|
|
||||||
|
dlen = ETH_ALEN + 2 + 2;
|
||||||
|
data = os_malloc(dlen);
|
||||||
|
if (data == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Command header for driver */
|
||||||
|
pos = data;
|
||||||
|
os_memcpy(pos, peer, ETH_ALEN);
|
||||||
|
pos += ETH_ALEN;
|
||||||
|
|
||||||
|
val = oper;
|
||||||
|
os_memcpy(pos, &val, 2);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
val = 0;
|
||||||
|
os_memcpy(pos, &val, 2);
|
||||||
|
|
||||||
|
ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
|
||||||
|
|
||||||
|
os_free(data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
|
||||||
|
u8 *buf, u16 *buf_len)
|
||||||
|
{
|
||||||
|
struct atheros_driver_data *drv = priv;
|
||||||
|
|
||||||
|
switch (oper) {
|
||||||
|
case WNM_SLEEP_ENTER_CONFIRM:
|
||||||
|
case WNM_SLEEP_ENTER_FAIL:
|
||||||
|
case WNM_SLEEP_EXIT_CONFIRM:
|
||||||
|
case WNM_SLEEP_EXIT_FAIL:
|
||||||
|
return atheros_wnm_sleep(drv, peer, oper);
|
||||||
|
case WNM_SLEEP_TFS_REQ_IE_SET:
|
||||||
|
case WNM_SLEEP_TFS_RESP_IE_ADD:
|
||||||
|
case WNM_SLEEP_TFS_RESP_IE_NONE:
|
||||||
|
case WNM_SLEEP_TFS_IE_DEL:
|
||||||
|
return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
|
||||||
|
default:
|
||||||
|
wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
|
||||||
|
oper);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211V */
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_atheros_ops = {
|
const struct wpa_driver_ops wpa_driver_atheros_ops = {
|
||||||
.name = "atheros",
|
.name = "atheros",
|
||||||
.hapd_init = atheros_init,
|
.hapd_init = atheros_init,
|
||||||
@ -1937,4 +2148,7 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
|
|||||||
.add_sta_node = atheros_add_sta_node,
|
.add_sta_node = atheros_add_sta_node,
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
.send_action = atheros_send_action,
|
.send_action = atheros_send_action,
|
||||||
|
#ifdef CONFIG_IEEE80211V
|
||||||
|
.wnm_oper = atheros_wnm_oper,
|
||||||
|
#endif /* CONFIG_IEEE80211V */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user