mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
Move GAS/ANQP build routines to a separate file from P2P
GAS/ANQP is a generic protocol and in no way specific to P2P, so move routines used to build GAS/ANQP frames to a separate file that can be shared for other uses than just P2P service discovery.
This commit is contained in:
parent
206e1f422f
commit
0c840c33f7
279
src/common/gas.c
Normal file
279
src/common/gas.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) (IEEE 802.11u)
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011, Qualcomm Atheros
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "gas.h"
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
gas_build_req(u8 action, u8 dialog_token, size_t size)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(100 + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, action);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
|
||||
{
|
||||
return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
|
||||
size);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_build_comeback_req(u8 dialog_token)
|
||||
{
|
||||
return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
|
||||
u8 more, u16 comeback_delay, size_t size)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(100 + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, action);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
wpabuf_put_le16(buf, status_code);
|
||||
if (action == WLAN_PA_GAS_COMEBACK_RESP)
|
||||
wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
|
||||
wpabuf_put_le16(buf, comeback_delay);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
|
||||
size_t size)
|
||||
{
|
||||
return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
|
||||
status_code, 0, 0, comeback_delay, size);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
|
||||
u16 comeback_delay, size_t size)
|
||||
{
|
||||
return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
|
||||
status_code, frag_id, more, comeback_delay,
|
||||
size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_add_adv_proto_anqp - Add an Advertisement Protocol element
|
||||
* @buf: Buffer to which the element is added
|
||||
* @query_resp_len_limit: Query Response Length Limit in units of 256 octets
|
||||
* @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
|
||||
*
|
||||
*
|
||||
* @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
|
||||
* that the maximum limit is determined by the maximum allowable number of
|
||||
* fragments in the GAS Query Response Fragment ID.
|
||||
*/
|
||||
static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
|
||||
u8 pame_bi)
|
||||
{
|
||||
/* Advertisement Protocol IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 2); /* Length */
|
||||
wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
|
||||
(pame_bi ? 0x80 : 0));
|
||||
/* Advertisement Protocol */
|
||||
wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = gas_build_initial_req(dialog_token, 4 + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
gas_add_adv_proto_anqp(buf, 0, 0);
|
||||
|
||||
wpabuf_put(buf, 2); /* Query Request Length to be filled */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
|
||||
u16 comeback_delay, size_t size)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
|
||||
4 + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
gas_add_adv_proto_anqp(buf, 0x7f, 0);
|
||||
|
||||
wpabuf_put(buf, 2); /* Query Response Length to be filled */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
|
||||
u16 status_code,
|
||||
u16 comeback_delay,
|
||||
struct wpabuf *payload)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = gas_anqp_build_initial_resp(dialog_token, status_code,
|
||||
comeback_delay,
|
||||
payload ? wpabuf_len(payload) : 0);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
if (payload)
|
||||
wpabuf_put_buf(buf, payload);
|
||||
|
||||
gas_anqp_set_len(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
|
||||
u8 frag_id, u8 more,
|
||||
u16 comeback_delay, size_t size)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = gas_build_comeback_resp(dialog_token, status_code,
|
||||
frag_id, more, comeback_delay, 4 + size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
gas_add_adv_proto_anqp(buf, 0x7f, 0);
|
||||
|
||||
wpabuf_put(buf, 2); /* Query Response Length to be filled */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
|
||||
u16 status_code,
|
||||
u8 frag_id, u8 more,
|
||||
u16 comeback_delay,
|
||||
struct wpabuf *payload)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
|
||||
more, comeback_delay,
|
||||
payload ? wpabuf_len(payload) : 0);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
if (payload)
|
||||
wpabuf_put_buf(buf, payload);
|
||||
|
||||
gas_anqp_set_len(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_anqp_set_len - Set Query Request/Response Length
|
||||
* @buf: GAS message
|
||||
*
|
||||
* This function is used to update the Query Request/Response Length field once
|
||||
* the payload has been filled.
|
||||
*/
|
||||
void gas_anqp_set_len(struct wpabuf *buf)
|
||||
{
|
||||
u8 action;
|
||||
size_t offset;
|
||||
u8 *len;
|
||||
|
||||
if (buf == NULL || wpabuf_len(buf) < 2)
|
||||
return;
|
||||
|
||||
action = *(wpabuf_head_u8(buf) + 1);
|
||||
switch (action) {
|
||||
case WLAN_PA_GAS_INITIAL_REQ:
|
||||
offset = 3 + 4;
|
||||
break;
|
||||
case WLAN_PA_GAS_INITIAL_RESP:
|
||||
offset = 7 + 4;
|
||||
break;
|
||||
case WLAN_PA_GAS_COMEBACK_RESP:
|
||||
offset = 8 + 4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (wpabuf_len(buf) < offset + 2)
|
||||
return;
|
||||
|
||||
len = wpabuf_mhead_u8(buf) + offset;
|
||||
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_anqp_add_element - Add ANQP element header
|
||||
* @buf: GAS message
|
||||
* @info_id: ANQP Info ID
|
||||
* Returns: Pointer to the Length field for gas_anqp_set_element_len()
|
||||
*/
|
||||
u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
|
||||
{
|
||||
wpabuf_put_le16(buf, info_id);
|
||||
return wpabuf_put(buf, 2); /* Length to be filled */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_anqp_set_element_len - Update ANQP element Length field
|
||||
* @buf: GAS message
|
||||
* @len_pos: Length field position from gas_anqp_add_element()
|
||||
*
|
||||
* This function is called after the ANQP element payload has been added to the
|
||||
* buffer.
|
||||
*/
|
||||
void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
|
||||
{
|
||||
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
|
||||
}
|
40
src/common/gas.h
Normal file
40
src/common/gas.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) (IEEE 802.11u)
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011, Qualcomm Atheros
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef GAS_H
|
||||
#define GAS_H
|
||||
|
||||
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
|
||||
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
|
||||
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
|
||||
u16 comeback_delay, size_t size);
|
||||
struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
|
||||
u16 status_code,
|
||||
u16 comeback_delay,
|
||||
struct wpabuf *payload);
|
||||
struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
|
||||
u8 frag_id, u8 more,
|
||||
u16 comeback_delay, size_t size);
|
||||
struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
|
||||
u16 status_code,
|
||||
u8 frag_id, u8 more,
|
||||
u16 comeback_delay,
|
||||
struct wpabuf *payload);
|
||||
void gas_anqp_set_len(struct wpabuf *buf);
|
||||
|
||||
u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
|
||||
void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
|
||||
|
||||
#endif /* GAS_H */
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/gas.h"
|
||||
#include "p2p_i.h"
|
||||
#include "p2p.h"
|
||||
|
||||
@ -90,52 +91,21 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic,
|
||||
struct wpabuf *tlvs)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *len_pos, *len_pos2;
|
||||
u8 *len_pos;
|
||||
|
||||
buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
|
||||
buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
|
||||
wpabuf_put_u8(buf, 0); /* Dialog Token */
|
||||
|
||||
/* Advertisement Protocol IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 2); /* Length */
|
||||
wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
|
||||
/* Advertisement Protocol */
|
||||
wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
|
||||
|
||||
/* Query Request */
|
||||
len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
|
||||
|
||||
/* ANQP Query Request Frame */
|
||||
wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
|
||||
len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
|
||||
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, P2P_OUI_TYPE);
|
||||
wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
|
||||
wpabuf_put_buf(buf, tlvs);
|
||||
gas_anqp_set_element_len(buf, len_pos);
|
||||
|
||||
WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
|
||||
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(3);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
gas_anqp_set_len(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -146,7 +116,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
|
||||
{
|
||||
struct wpabuf *req;
|
||||
|
||||
req = p2p_build_gas_comeback_req(dialog_token);
|
||||
req = gas_build_comeback_req(dialog_token);
|
||||
if (req == NULL)
|
||||
return;
|
||||
|
||||
@ -166,43 +136,26 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
|
||||
const struct wpabuf *tlvs)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *len_pos, *len_pos2;
|
||||
u8 *len_pos;
|
||||
|
||||
buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
|
||||
buf = gas_anqp_build_initial_resp(dialog_token, status_code,
|
||||
comeback_delay,
|
||||
100 + (tlvs ? wpabuf_len(tlvs) : 0));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
wpabuf_put_le16(buf, status_code);
|
||||
wpabuf_put_le16(buf, comeback_delay);
|
||||
|
||||
/* Advertisement Protocol IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 2); /* Length */
|
||||
wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
|
||||
/* Advertisement Protocol */
|
||||
wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
|
||||
|
||||
/* Query Response */
|
||||
len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
|
||||
|
||||
if (tlvs) {
|
||||
/* ANQP Query Response Frame */
|
||||
wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
|
||||
len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
|
||||
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, P2P_OUI_TYPE);
|
||||
/* Service Update Indicator */
|
||||
wpabuf_put_le16(buf, update_indic);
|
||||
wpabuf_put_buf(buf, tlvs);
|
||||
|
||||
WPA_PUT_LE16(len_pos2,
|
||||
(u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
|
||||
gas_anqp_set_element_len(buf, len_pos);
|
||||
}
|
||||
|
||||
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
|
||||
gas_anqp_set_len(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -216,29 +169,12 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
|
||||
u16 total_len)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *len_pos;
|
||||
|
||||
buf = wpabuf_alloc(1000 + len);
|
||||
buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
|
||||
more, 0, 100 + len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
wpabuf_put_le16(buf, status_code);
|
||||
wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
|
||||
wpabuf_put_le16(buf, 0); /* Comeback Delay */
|
||||
|
||||
/* Advertisement Protocol IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 2); /* Length */
|
||||
wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
|
||||
/* Advertisement Protocol */
|
||||
wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
|
||||
|
||||
/* Query Response */
|
||||
len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
|
||||
|
||||
if (frag_id == 0) {
|
||||
/* ANQP Query Response Frame */
|
||||
wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
|
||||
@ -250,8 +186,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
|
||||
}
|
||||
|
||||
wpabuf_put_data(buf, data, len);
|
||||
|
||||
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
|
||||
gas_anqp_set_len(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -201,6 +201,7 @@ OBJS += ../src/p2p/p2p_dev_disc.o
|
||||
OBJS += ../src/p2p/p2p_group.o
|
||||
OBJS += ../src/ap/p2p_hostapd.o
|
||||
CFLAGS += -DCONFIG_P2P
|
||||
NEED_GAS=y
|
||||
NEED_80211_COMMON=y
|
||||
ifdef CONFIG_P2P_STRICT
|
||||
CFLAGS += -DCONFIG_P2P_STRICT
|
||||
@ -1282,6 +1283,10 @@ CFLAGS += -DCONFIG_BGSCAN
|
||||
OBJS += bgscan.o
|
||||
endif
|
||||
|
||||
ifdef NEED_GAS
|
||||
OBJS += ../src/common/gas.o
|
||||
endif
|
||||
|
||||
OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
|
||||
OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
|
||||
ifdef CONFIG_AUTHENTICATOR
|
||||
|
Loading…
Reference in New Issue
Block a user