mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-25 13:38:54 +00:00
939 lines
24 KiB
C
939 lines
24 KiB
C
/**************************************************************************************************************
|
|
* altobeam Wi-Fi
|
|
*
|
|
* Copyright (c) 2018, altobeam.inc All rights reserved.
|
|
*
|
|
* The source code contains proprietary information of AltoBeam, and shall not be distributed,
|
|
* copied, reproduced, or disclosed in whole or in part without prior written permission of AltoBeam.
|
|
*****************************************************************************************************************/
|
|
#include "atbm_hal.h"
|
|
#include "uuid.h"
|
|
#include "wps.h"
|
|
#include "wps_i.h"
|
|
#include "wps_defs.h"
|
|
#include "wps_dev_attr.h"
|
|
#include "wps_attr_parse.h"
|
|
#include "wps_hostapd.h"
|
|
#include "wpabuf.h"
|
|
#include "wps_attr_parse.h"
|
|
#include "wps_sta.h"
|
|
#include "wpa_debug.h"
|
|
|
|
extern struct wpabuf * eap_msg_alloc(EapVenType vendor, EapType type, atbm_uint32 payload_len,
|
|
EapCodeType code, atbm_uint8 identifier);
|
|
extern const atbm_uint8 * eap_hdr_validate(EapVenType vendor, EapType eap_type,
|
|
const struct wpabuf *msg, atbm_size_t *plen);
|
|
extern atbm_int32 wps_set_attr(struct wps_parse_attr *attr, atbm_uint16 type,
|
|
const atbm_uint8 *pos, atbm_uint16 len);
|
|
extern atbm_uint8 eap_get_id(const struct wpabuf *msg);
|
|
extern int wps_add_pin(struct hostapd_data *hapd, atbm_void *ctx);
|
|
|
|
/**
|
|
* wps_build_probe_req_ie - Build WPS IE for Probe Request
|
|
* @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
|
|
* most other use cases)
|
|
* @dev: Device attributes
|
|
* @uuid: Own UUID
|
|
* @req_type: Value for Request Type attribute
|
|
* @num_req_dev_types: Number of requested device types
|
|
* @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
|
|
* %NULL if none
|
|
* Returns: WPS IE or %NULL on failure
|
|
*
|
|
* The caller is responsible for freeing the buffer.
|
|
*/
|
|
struct wpabuf * wps_build_probe_req_ie(atbm_uint16 pw_id, struct wps_device_data *dev,
|
|
const atbm_uint8 *uuid,
|
|
enum wps_request_type req_type,
|
|
atbm_uint32 num_req_dev_types,
|
|
const atbm_uint8 *req_dev_types)
|
|
{
|
|
struct wpabuf *ie;
|
|
|
|
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
|
|
|
|
ie = wpabuf_alloc(500);
|
|
if (ie == NULL)
|
|
return NULL;
|
|
|
|
if (wps_build_version(ie) ||
|
|
wps_build_req_type(ie, req_type) ||
|
|
wps_build_config_methods(ie, dev->config_methods) ||
|
|
wps_build_uuid_e(ie, uuid) ||
|
|
wps_build_primary_dev_type(dev, ie) ||
|
|
wps_build_rf_bands(dev, ie) ||
|
|
wps_build_assoc_state(NULL, ie) ||
|
|
wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
|
|
wps_build_dev_password_id(ie, pw_id) ||
|
|
#if CONFIG_WPS2
|
|
wps_build_manufacturer(dev, ie) ||
|
|
wps_build_model_name(dev, ie) ||
|
|
wps_build_model_number(dev, ie) ||
|
|
wps_build_dev_name(dev, ie) ||
|
|
wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
|
|
#endif /* CONFIG_WPS2 */
|
|
wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
|
|
||
|
|
wps_build_secondary_dev_type(dev, ie)
|
|
) {
|
|
wpabuf_free(ie);
|
|
return NULL;
|
|
}
|
|
|
|
#if (CONFIG_WPS2 == 0)
|
|
if (dev->p2p && wps_build_dev_name(dev, ie)) {
|
|
wpabuf_free(ie);
|
|
return NULL;
|
|
}
|
|
#endif /* CONFIG_WPS2 */
|
|
|
|
return wps_ie_encapsulate(ie);
|
|
}
|
|
extern atbm_void sys_dump_mem(const atbm_void *pMem, int size);
|
|
atbm_uint8 * atbmwifi_ieee80211_add_preq_wps_ie(struct atbmwifi_vif *priv,atbm_uint8 * pos)
|
|
{
|
|
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
|
|
struct wpa_supplicant *wpa_s;
|
|
struct wps_context *wps_ctx;
|
|
//char WIFI_OUI[3] = {0x00, 0x50, 0xF2};
|
|
//char WIFI_WPS_OUI_TYPE = 0x04;
|
|
|
|
wpa_s = (struct wpa_supplicant *)priv->appdata;
|
|
if( wpa_s->wsc_data == NULL)
|
|
return pos;
|
|
wps_ctx = wpa_s->wsc_data->wps_ctx;
|
|
wpa_printf(MSG_DEBUG,"WPS: atbmwifi_ieee80211_add_preq_wps_ie, wps_mode=%d", wpa_s->wps_mode);
|
|
if (wpa_s->wps_mode != WPS_MODE_UNKNOWN) {
|
|
struct wpabuf *wps_ie;
|
|
wps_ie = wps_build_probe_req_ie(wpa_s->wps_mode == WPS_MODE_PBC ? DEV_PW_PUSHBUTTON :
|
|
DEV_PW_DEFAULT,
|
|
&wps_ctx->dev,
|
|
wps_ctx->uuid, req_type,
|
|
0, NULL);
|
|
if (wps_ie) {
|
|
//*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
|
//*pos++ = 4/*OUI + OUI Type*/+wps_ie->used;
|
|
//atbm_memcpy(pos, WIFI_OUI, 3);
|
|
//pos += 3;
|
|
//*pos++ = WIFI_WPS_OUI_TYPE;
|
|
wpa_printf(MSG_DEBUG,"WPS: ie length = %d", wps_ie->used);
|
|
//sys_dump_mem(wps_ie->buf, wps_ie->used);
|
|
|
|
atbm_memcpy(pos, wps_ie->buf, wps_ie->used);
|
|
pos += wps_ie->used;
|
|
|
|
wpabuf_free(wps_ie);
|
|
}else{
|
|
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request failed.");
|
|
}
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
atbm_uint8 * atbmwifi_ieee80211_add_assocreq_wps_ie(struct atbmwifi_vif *priv,atbm_uint8 * pos)
|
|
{
|
|
struct wpa_supplicant *wpa_s;
|
|
struct wpabuf *wps_ie;
|
|
atbm_uint8 wps_oui[] = {0x00, 0x50, 0xF2, 0x04};
|
|
|
|
wpa_s = (struct wpa_supplicant *)priv->appdata;
|
|
|
|
if (wpa_s->wps_mode == WPS_MODE_UNKNOWN) {
|
|
return pos;// not to do anything
|
|
}
|
|
|
|
wps_ie = wpabuf_alloc(100);
|
|
if(wps_ie == NULL){
|
|
wpa_printf(MSG_ERROR, "assoc req add wps ie failed.");
|
|
return pos;
|
|
}
|
|
|
|
if (wps_build_version(wps_ie) ||
|
|
wps_build_req_type(wps_ie, WPS_REQ_ENROLLEE) ||
|
|
wps_build_wfa_ext(wps_ie, 0, NULL, 0)){
|
|
wpabuf_free(wps_ie);
|
|
return pos;
|
|
}
|
|
|
|
//wps_ie_encapsulate(wps_ie);
|
|
|
|
//wps ie id
|
|
*pos++ = ATBM_WLAN_EID_VENDOR_SPECIFIC;
|
|
|
|
//wps ie length
|
|
*pos++ = wps_ie->used + 4;
|
|
|
|
//wps oui
|
|
atbm_memcpy(pos, wps_oui, 4);
|
|
pos += 4;
|
|
|
|
atbm_memcpy(pos, wps_ie->buf, wps_ie->used);
|
|
pos += wps_ie->used;
|
|
|
|
wpabuf_free(wps_ie);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
|
|
atbm_uint8 id, atbm_uint8 len, const atbm_uint8 *pos)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "WPS: WFA subelement id=%u len=%u", id, len);
|
|
switch (id) {
|
|
case WFA_ELEM_VERSION2:
|
|
if (len != 1) {
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid Version2 length %u", len);
|
|
return -1;
|
|
}
|
|
attr->version2 = pos;
|
|
break;
|
|
case WFA_ELEM_AUTHORIZEDMACS:
|
|
attr->authorized_macs = pos;
|
|
attr->authorized_macs_len = len;
|
|
break;
|
|
case WFA_ELEM_NETWORK_KEY_SHAREABLE:
|
|
if (len != 1) {
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
|
|
"Shareable length %u", len);
|
|
return -1;
|
|
}
|
|
attr->network_key_shareable = pos;
|
|
break;
|
|
case WFA_ELEM_REQUEST_TO_ENROLL:
|
|
if (len != 1) {
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid Request to Enroll "
|
|
"length %u", len);
|
|
return -1;
|
|
}
|
|
attr->request_to_enroll = pos;
|
|
break;
|
|
case WFA_ELEM_SETTINGS_DELAY_TIME:
|
|
if (len != 1) {
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid Settings Delay "
|
|
"Time length %u", len);
|
|
return -1;
|
|
}
|
|
attr->settings_delay_time = pos;
|
|
break;
|
|
default:
|
|
wpa_printf(MSG_ERROR, "WPS: Skipped unknown WFA Vendor "
|
|
"Extension subelement %u", id);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const atbm_uint8 *pos,
|
|
atbm_uint16 len)
|
|
{
|
|
const atbm_uint8 *end = pos + len;
|
|
atbm_uint8 id, elen;
|
|
|
|
while (pos + 2 <= end) {
|
|
id = *pos++;
|
|
elen = *pos++;
|
|
if (pos + elen > end)
|
|
break;
|
|
if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
|
|
return -1;
|
|
pos += elen;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wps_parse_vendor_ext(struct wps_parse_attr *attr, const atbm_uint8 *pos,
|
|
atbm_uint16 len)
|
|
{
|
|
atbm_uint32 vendor_id;
|
|
|
|
if (len < 3) {
|
|
wpa_printf(MSG_ERROR, "WPS: Skip invalid Vendor Extension");
|
|
return 0;
|
|
}
|
|
|
|
vendor_id = ATBM_WPA_GET_BE24(pos);
|
|
switch (vendor_id) {
|
|
case WPS_VENDOR_ID_WFA:
|
|
return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
|
|
}
|
|
|
|
/* Handle unknown vendor extensions */
|
|
|
|
wpa_printf(MSG_DEBUG, "WPS: Unknown Vendor Extension (Vendor ID %u)",
|
|
vendor_id);
|
|
|
|
if (len > WPS_MAX_VENDOR_EXT_LEN) {
|
|
wpa_printf(MSG_ERROR, "WPS: Too long Vendor Extension (%u)",
|
|
len);
|
|
return -1;
|
|
}
|
|
|
|
if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
|
|
wpa_printf(MSG_ERROR, "WPS: Skipped Vendor Extension "
|
|
"attribute (max %d vendor extensions)",
|
|
MAX_WPS_PARSE_VENDOR_EXT);
|
|
return -1;
|
|
}
|
|
attr->vendor_ext[attr->num_vendor_ext] = pos;
|
|
attr->vendor_ext_len[attr->num_vendor_ext] = len;
|
|
attr->num_vendor_ext++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wps_parse_msg_attr(const atbm_uint8 *msg, atbm_uint8 length, struct wps_parse_attr *attr)
|
|
{
|
|
const atbm_uint8 *pos, *end;
|
|
atbm_uint16 type, len;
|
|
#ifdef WPS_WORKAROUNDS
|
|
atbm_uint16 prev_type = 0;
|
|
#endif /* WPS_WORKAROUNDS */
|
|
|
|
atbm_memset(attr, 0, sizeof(*attr));
|
|
//wpa_printf(MSG_DEBUG,"WPS: parse msg attr.");
|
|
|
|
//sys_dump_mem(msg, length);
|
|
|
|
end = msg + length;
|
|
pos = msg+4;/* OUI: 3bytes OUI type:1byte*/
|
|
|
|
while (pos < end) {
|
|
if (end - pos < 4) {
|
|
wpa_printf(MSG_ERROR, "WPS: Invalid message - "
|
|
"%lu bytes remaining",
|
|
(unsigned long) (end - pos));
|
|
return -1;
|
|
}
|
|
|
|
type = ATBM_WPA_GET_BE16(pos);
|
|
pos += 2;
|
|
len = ATBM_WPA_GET_BE16(pos);
|
|
pos += 2;
|
|
//wpa_printf(MSG_DEBUG, "WPS: attr type=0x%x len=%u", type, len);
|
|
if (len > end - pos) {
|
|
wpa_printf(MSG_WARNING, "WPS: Attribute overflow");
|
|
//wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
|
|
#ifdef WPS_WORKAROUNDS
|
|
/*
|
|
* Some deployed APs seem to have a bug in encoding of
|
|
* Network Key attribute in the Credential attribute
|
|
* where they add an extra octet after the Network Key
|
|
* attribute at least when open network is being
|
|
* provisioned.
|
|
*/
|
|
if ((type & 0xff00) != 0x1000 &&
|
|
prev_type == ATTR_NETWORK_KEY) {
|
|
wpa_printf(MSG_WARNING, "WPS: Workaround - try "
|
|
"to skip unexpected octet after "
|
|
"Network Key");
|
|
pos -= 3;
|
|
continue;
|
|
}
|
|
#endif /* WPS_WORKAROUNDS */
|
|
return -1;
|
|
}
|
|
|
|
#ifdef WPS_WORKAROUNDS
|
|
if (type == 0 && len == 0) {
|
|
/*
|
|
* Mac OS X 10.6 seems to be adding 0x00 padding to the
|
|
* end of M1. Skip those to avoid interop issues.
|
|
*/
|
|
int i;
|
|
for (i = 0; i < end - pos; i++) {
|
|
if (pos[i])
|
|
break;
|
|
}
|
|
if (i == end - pos) {
|
|
wpa_printf(MSG_WARNING, "WPS: Workaround - skip "
|
|
"unexpected message padding");
|
|
break;
|
|
}
|
|
}
|
|
#endif /* WPS_WORKAROUNDS */
|
|
|
|
if (wps_set_attr(attr, type, pos, len) < 0)
|
|
return -1;
|
|
|
|
#ifdef WPS_WORKAROUNDS
|
|
prev_type = type;
|
|
#endif /* WPS_WORKAROUNDS */
|
|
pos += len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wps_is_addr_authorized(struct wps_parse_attr *attr, const atbm_uint8 *addr)
|
|
{
|
|
unsigned int i;
|
|
const atbm_uint8 *pos;
|
|
const atbm_uint8 bcast[ATBM_ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
|
|
if (!attr->authorized_macs)
|
|
return 0;
|
|
|
|
pos = attr->authorized_macs;
|
|
for (i = 0; i < attr->authorized_macs_len / ATBM_ETH_ALEN; i++) {
|
|
if (atbm_memcmp(pos, addr, ATBM_ETH_ALEN) == 0)
|
|
return 2;
|
|
if (atbm_memcmp(pos, bcast, ATBM_ETH_ALEN) == 0)
|
|
return 1;
|
|
pos += ATBM_ETH_ALEN;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
|
|
#define WPS_PIN_TIME_IGNORE_SEL_REG 10
|
|
int check_valid_wps_ap(struct atbmwifi_vif *priv, struct wps_parse_attr *attr, atbm_uint8 *addr){
|
|
//struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)priv->appdata;
|
|
|
|
if(attr->selected_registrar){
|
|
if(*(attr->selected_registrar) == 0)
|
|
return 0;
|
|
else if(attr->primary_dev_type != ATBM_NULL)
|
|
return 1;
|
|
}
|
|
if(priv->pin){
|
|
if(wps_is_addr_authorized(attr, addr)){
|
|
return 1;
|
|
}
|
|
/*for wps Interoperability Test(5.4.5) wsc 1.0 ap with external registar*/
|
|
#if 0
|
|
if(wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG ||
|
|
((atbm_GetOsTime() - wpa_s->wps_pin_start_time >= WPS_PIN_TIME_IGNORE_SEL_REG * HZ)){
|
|
return 1;
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const char * eap_wsc_state_txt(int state)
|
|
{
|
|
switch (state) {
|
|
case WAIT_START:
|
|
return "WAIT_START";
|
|
case MESG:
|
|
return "MESG";
|
|
case FRAG_ACK:
|
|
return "FRAG_ACK";
|
|
case WAIT_FRAG_ACK:
|
|
return "WAIT_FRAG_ACK";
|
|
case ATBM_WPS_DONE:
|
|
return "ATBM_WPS_DONE";
|
|
case ATBM_WPS_FAIL:
|
|
return "ATBM_WPS_FAIL";
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
atbm_void eap_wsc_state(struct eap_wsc_data *data, int state)
|
|
{
|
|
wpa_printf(WIFI_WPA, "EAP-WSC State: %s -> %s",
|
|
eap_wsc_state_txt(data->state),
|
|
eap_wsc_state_txt(state));
|
|
data->state = state;
|
|
return;
|
|
}
|
|
|
|
static int wpa_supplicant_ap_wps_pin(struct hostapd_data *hapd, const atbm_uint8 *bssid,
|
|
const char *pin, char *buf, atbm_size_t buflen)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* wps_get_msg - Build a WPS message
|
|
* @wps: WPS Registration protocol data from wps_init()
|
|
* @op_code: Buffer for returning message OP Code
|
|
* Returns: The generated WPS message or %NULL on failure
|
|
*
|
|
* This function is used to build a response to a message processed by calling
|
|
* wps_process_msg(). The caller is responsible for freeing the buffer.
|
|
*/
|
|
struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
|
|
{
|
|
if (wps->registrar)
|
|
return wps_registrar_get_msg(wps, op_code);
|
|
else
|
|
return wps_enrollee_get_msg(wps, op_code);
|
|
}
|
|
|
|
/**
|
|
* wps_process_msg - Process a WPS message
|
|
* @wps: WPS Registration protocol data from wps_init()
|
|
* @op_code: Message OP Code
|
|
* @msg: Message data
|
|
* Returns: Processing result
|
|
*
|
|
* This function is used to process WPS messages with OP Codes WSC_ACK,
|
|
* WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
|
|
* responsible for reassembling the messages before calling this function.
|
|
* Response to this message is built by calling wps_get_msg().
|
|
*/
|
|
enum wps_process_res wps_process_msg(struct wps_data *wps,
|
|
enum wsc_op_code op_code,
|
|
const struct wpabuf *msg)
|
|
{
|
|
if (wps->registrar)
|
|
return wps_registrar_process_msg(wps, op_code, msg);
|
|
else
|
|
return wps_enrollee_process_msg(wps, op_code, msg);
|
|
}
|
|
|
|
struct wpabuf * eap_wsc_build_frag_ack(atbm_uint8 id, atbm_uint8 code)
|
|
{
|
|
struct wpabuf *msg;
|
|
|
|
msg = eap_msg_alloc(ATBM_EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id);
|
|
if (msg == NULL) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for FRAG_ACK");
|
|
return NULL;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK");
|
|
wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */
|
|
wpabuf_put_u8(msg, 0); /* Flags */
|
|
|
|
return msg;
|
|
}
|
|
|
|
static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
|
|
atbm_uint8 id, atbm_uint8 flags, atbm_uint8 op_code,
|
|
atbm_uint16 message_length,
|
|
const atbm_uint8 *buf, atbm_size_t len)
|
|
{
|
|
/* Process a fragment that is not the last one of the message */
|
|
if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
|
|
wpa_printf(MSG_ERROR,"EAP-WSC: No Message Length field in a fragmented packet");
|
|
return NULL;
|
|
}
|
|
|
|
if (data->in_buf == NULL) {
|
|
/* First fragment of the message */
|
|
data->in_buf = wpabuf_alloc(message_length);
|
|
if (data->in_buf == NULL) {
|
|
wpa_printf(MSG_ERROR,"EAP-WSC: No memory for message");
|
|
return NULL;
|
|
}
|
|
data->in_op_code = op_code;
|
|
wpabuf_put_data(data->in_buf, buf, len);
|
|
wpa_printf(MSG_ERROR,"EAP-WSC: Received %lu bytes in first "
|
|
"fragment, waiting for %lu bytes more",
|
|
(unsigned long) len,
|
|
(unsigned long) wpabuf_tailroom(data->in_buf));
|
|
}
|
|
|
|
return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
|
|
}
|
|
|
|
static int eap_wsc_process_cont(struct eap_wsc_data *data,
|
|
const atbm_uint8 *buf, atbm_size_t len, atbm_uint8 op_code)
|
|
{
|
|
/* Process continuation of a pending message */
|
|
if (op_code != data->in_op_code) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Unexpected Op-Code %d in "
|
|
"fragment (expected %d)",
|
|
op_code, data->in_op_code);
|
|
return -1;
|
|
}
|
|
|
|
if (len > wpabuf_tailroom(data->in_buf)) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Fragment overflow");
|
|
eap_wsc_state(data, ATBM_WPS_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
wpabuf_put_data(data->in_buf, buf, len);
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
|
|
"for %lu bytes more", (unsigned long) len,
|
|
(unsigned long) wpabuf_tailroom(data->in_buf));
|
|
|
|
return 0;
|
|
}
|
|
static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,atbm_uint8 id)
|
|
{
|
|
struct wpabuf *resp;
|
|
atbm_uint8 flags;
|
|
atbm_size_t send_len, plen;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
|
|
|
|
flags = 0;
|
|
send_len = wpabuf_len(data->out_buf) - data->out_used;
|
|
if (2 + send_len > data->fragment_size) {
|
|
send_len = data->fragment_size - 2;
|
|
flags |= WSC_FLAGS_MF;
|
|
if (data->out_used == 0) {
|
|
flags |= WSC_FLAGS_LF;
|
|
send_len -= 2;
|
|
}
|
|
}
|
|
plen = 2 + send_len;
|
|
if (flags & WSC_FLAGS_LF)
|
|
plen += 2;
|
|
resp = eap_msg_alloc(ATBM_EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
|
|
EAP_CODE_RESPONSE, id);
|
|
if (resp == NULL)
|
|
return NULL;
|
|
|
|
wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
|
|
wpabuf_put_u8(resp, flags); /* Flags */
|
|
if (flags & WSC_FLAGS_LF)
|
|
wpabuf_put_be16(resp, wpabuf_len(data->out_buf));
|
|
|
|
wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
|
|
send_len);
|
|
data->out_used += send_len;
|
|
|
|
if (data->out_used == wpabuf_len(data->out_buf)) {
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
|
|
"(message sent completely)",
|
|
(unsigned long) send_len);
|
|
wpabuf_free(data->out_buf);
|
|
data->out_buf = NULL;
|
|
data->out_used = 0;
|
|
if ((data->state == ATBM_WPS_FAIL && data->out_op_code == WSC_ACK) ||
|
|
data->out_op_code == WSC_NACK ||
|
|
data->out_op_code == WSC_Done) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: building msg failed.");
|
|
eap_wsc_state(data, ATBM_WPS_FAIL);
|
|
} else
|
|
eap_wsc_state(data, MESG);
|
|
} else {
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
|
|
"(%lu more to send)", (unsigned long) send_len,
|
|
(unsigned long) wpabuf_len(data->out_buf) -
|
|
data->out_used);
|
|
eap_wsc_state(data, WAIT_FRAG_ACK);
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
struct wpabuf * wpas_eap_wsc_process(struct wpa_supplicant *wpa_s, const struct wpabuf *reqData)
|
|
{
|
|
struct eap_wsc_data *data;
|
|
const atbm_uint8 *start, *pos, *end;
|
|
atbm_size_t len;
|
|
atbm_uint8 op_code, flags, id;
|
|
atbm_uint16 message_length = 0;
|
|
enum wps_process_res res;
|
|
struct wpabuf tmpbuf;
|
|
struct wpabuf *r;
|
|
|
|
|
|
data = wpa_s->wsc_data;
|
|
|
|
pos = eap_hdr_validate(ATBM_EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,&len);
|
|
if (pos == NULL || len < 2) {
|
|
return NULL;
|
|
}
|
|
|
|
id = eap_get_id(reqData);
|
|
|
|
start = pos;
|
|
end = start + len;
|
|
|
|
op_code = *pos++;
|
|
flags = *pos++;
|
|
if (flags & WSC_FLAGS_LF) {
|
|
if (end - pos < 2) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Message underflow");
|
|
return NULL;
|
|
}
|
|
message_length = ATBM_WPA_GET_BE16(pos);
|
|
pos += 2;
|
|
|
|
if (message_length < end - pos) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Invalid Message Length");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
|
|
"Flags 0x%x Message Length %d",
|
|
op_code, flags, message_length);
|
|
|
|
if (data->state == WAIT_FRAG_ACK) {
|
|
if (op_code != WSC_FRAG_ACK) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Unexpected Op-Code %d "
|
|
"in WAIT_FRAG_ACK state", op_code);
|
|
return NULL;
|
|
}
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
|
|
eap_wsc_state(data, MESG);
|
|
return eap_wsc_build_msg(data, id);
|
|
}
|
|
|
|
if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
|
|
op_code != WSC_Done && op_code != WSC_Start) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Unexpected Op-Code %d",
|
|
op_code);
|
|
return NULL;
|
|
}
|
|
|
|
if (data->state == WAIT_START) {
|
|
if (op_code != WSC_Start) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Unexpected Op-Code %d "
|
|
"in WAIT_START state", op_code);
|
|
return NULL;
|
|
}
|
|
wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
|
|
eap_wsc_state(data, MESG);
|
|
/* Start message has empty payload, skip processing */
|
|
goto send_msg;
|
|
} else if (op_code == WSC_Start) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Unexpected Op-Code %d",
|
|
op_code);
|
|
return NULL;
|
|
}
|
|
|
|
if (data->in_buf &&
|
|
eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (flags & WSC_FLAGS_MF) {
|
|
return eap_wsc_process_fragment(data, id, flags, op_code,
|
|
message_length, pos,
|
|
end - pos);
|
|
}
|
|
|
|
if (data->in_buf == NULL) {
|
|
/* Wrap unfragmented messages as wpabuf without extra copy */
|
|
wpabuf_set(&tmpbuf, pos, end - pos);
|
|
data->in_buf = &tmpbuf;
|
|
}
|
|
|
|
res = wps_process_msg(data->wps, op_code, data->in_buf);
|
|
switch (res) {
|
|
case WPS_DONE:
|
|
wpa_printf(MSG_ALWAYS, "EAP-WSC: WPS processing completed "
|
|
"successfully - wait for EAP failure");
|
|
eap_wsc_state(data, ATBM_WPS_FAIL);
|
|
break;
|
|
case WPS_CONTINUE:
|
|
eap_wsc_state(data, MESG);
|
|
break;
|
|
case WPS_FAILURE:
|
|
case WPS_PENDING:
|
|
wpa_printf(MSG_ALWAYS, "EAP-WSC: WPS processing failed");
|
|
eap_wsc_state(data, ATBM_WPS_FAIL);
|
|
break;
|
|
}
|
|
|
|
if (data->in_buf != &tmpbuf)
|
|
wpabuf_free(data->in_buf);
|
|
data->in_buf = NULL;
|
|
|
|
send_msg:
|
|
if (data->out_buf == NULL) {
|
|
data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
|
|
if (data->out_buf == NULL) {
|
|
wpa_printf(MSG_ERROR, "EAP-WSC: Failed to receive "
|
|
"message from WPS");
|
|
return NULL;
|
|
}
|
|
data->out_used = 0;
|
|
}
|
|
|
|
eap_wsc_state(data, MESG);
|
|
r = eap_wsc_build_msg(data, id);
|
|
if (data->state == ATBM_WPS_FAIL) {
|
|
/* Use reduced client timeout for WPS to avoid long wait */
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* atbmwps_start_pbc - start wps via pbc
|
|
* Returns: 0 on success, -1 on failure
|
|
*
|
|
* This function is called at user start wps via pbc.
|
|
*/
|
|
int atbmwps_start_pbc(struct atbmwifi_vif *priv, atbm_uint8 *p2p_info)
|
|
{
|
|
int ret = 0;
|
|
int p2p_group=0;
|
|
|
|
if(priv == NULL){
|
|
wpa_printf(MSG_ERROR, "wps: pbc mode, priv is not finish init.");
|
|
return -1;
|
|
}
|
|
|
|
switch(priv->iftype){
|
|
|
|
case ATBM_NL80211_IFTYPE_AP:
|
|
priv->config.dev_password_len = 0;
|
|
priv->pbc = 1;
|
|
priv->pin = 0;
|
|
ret = hostapd_wps_button_pushed(priv->appdata, NULL);
|
|
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_STATION:
|
|
if(p2p_info){
|
|
atbm_memcpy(&p2p_group, p2p_info, sizeof(int));
|
|
}
|
|
ret = wpas_wps_start_pbc(priv->appdata, NULL, p2p_group);
|
|
|
|
break;
|
|
default:
|
|
wpa_printf(MSG_ERROR, "wps: pbc mode, iftype is not support.");
|
|
ret = -1;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* atbmwps_start_pin - start wps via pin
|
|
* Returns: 0 on success, -1 on failure
|
|
*
|
|
* This function is called at user start wps via pin.
|
|
*/
|
|
int atbmwps_start_pin(struct atbmwifi_vif *priv, const char *pin, atbm_uint8* buf, atbm_uint32 info)
|
|
{
|
|
int ret = 0;
|
|
int p2p_group=0;
|
|
atbm_uint16 dev_pw_id;
|
|
|
|
if(priv == NULL){
|
|
wpa_printf(MSG_ERROR, "wps: pin mode, priv is not finish init.");
|
|
return -1;
|
|
}
|
|
|
|
if(pin == NULL){
|
|
wpa_printf(MSG_ERROR, "wps: pin mode, pin code is NULL.");
|
|
return -1;
|
|
}
|
|
|
|
switch(priv->iftype){
|
|
|
|
case ATBM_NL80211_IFTYPE_AP:
|
|
ret = wpa_supplicant_ap_wps_pin(priv->appdata, priv->bssid, pin, (char *)buf, (atbm_size_t)info/*buf length*/);
|
|
if(ret != 0)
|
|
break;
|
|
|
|
priv->config.dev_password_len = 8;//strlen(pin);
|
|
atbm_memcpy(priv->config.dev_password, pin, 8);
|
|
priv->pin = 1;
|
|
priv->pbc = 0;
|
|
ret = wps_add_pin((struct hostapd_data *)priv->appdata, NULL);
|
|
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_STATION:
|
|
if(buf){
|
|
atbm_memcpy(&p2p_group, buf, sizeof(int));
|
|
}
|
|
dev_pw_id = info;
|
|
ret = wpas_wps_start_pin(priv->appdata, priv->bssid, pin, p2p_group, dev_pw_id);
|
|
|
|
break;
|
|
default:
|
|
wpa_printf(MSG_ERROR, "wps: pin mode, iftype is not support.");
|
|
ret = -1;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* atbmwps_cancel - Cancel the wps pbc/pin requests
|
|
* Returns: 0 on success, -1 on failure
|
|
*
|
|
* This function is called at the wps pbc/pin requests is cancelled.
|
|
*/
|
|
int atbmwps_cancel(struct atbmwifi_vif *priv)
|
|
{
|
|
int ret = 0;
|
|
|
|
if(priv == NULL){
|
|
wpa_printf(MSG_ERROR, "wps: cancel, priv is not finish init.");
|
|
return -1;
|
|
}
|
|
|
|
if(atbmwifi_is_ap_mode(priv->iftype)){
|
|
hostapd_cancel_wps(priv->appdata);
|
|
}else if(atbmwifi_is_sta_mode(priv->iftype)){
|
|
wpas_cancel_wps(priv->appdata);
|
|
}else{
|
|
wpa_printf(MSG_ERROR, "wps: cancel, iftype is not support.");
|
|
ret = -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if CONFIG_P2P
|
|
/**
|
|
* atbmwps_deinit - destrory wps structure
|
|
* Returns: 0 on success, -1 on failure
|
|
*
|
|
* This function is called at program over run to destroy wps.
|
|
*/
|
|
int atbmwps_deinit(struct atbmwifi_vif *priv)
|
|
{
|
|
int ret = 0;
|
|
|
|
if(priv == NULL){
|
|
wpa_printf(MSG_ERROR, "wps: deinit, priv is not finish init.");
|
|
return -1;
|
|
}
|
|
|
|
if(atbmwifi_is_ap_mode(priv->iftype)){
|
|
hostapd_deinit_wps(priv->appdata);
|
|
}else if(atbmwifi_is_sta_mode(priv->iftype)){
|
|
wpas_deinit_wps(priv->appdata);
|
|
}else{
|
|
wpa_printf(MSG_ERROR, "wps: deinit, iftype is not support.");
|
|
ret = -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* atbmwps_init - init wps STA or AP
|
|
* Returns: 0 on success, -1 on failure
|
|
*
|
|
* This function is called at program initialization to enable wps for STA/AP.
|
|
*/
|
|
int atbmwps_init(struct atbmwifi_vif *priv)
|
|
{
|
|
int ret = 0;
|
|
|
|
if(priv == NULL){
|
|
wpa_printf(MSG_ERROR, "WPS: init, priv is not finish init.");
|
|
return -1;
|
|
}
|
|
|
|
if(atbmwifi_is_ap_mode(priv->iftype)){
|
|
ret = hostapd_init_wps(priv->appdata);
|
|
}else if(atbmwifi_is_sta_mode(priv->iftype)){
|
|
ret = wpas_init_wps(priv->appdata);
|
|
}else{
|
|
wpa_printf(MSG_ERROR, "WPS: init, iftype is not support.");
|
|
ret = -1;
|
|
}
|
|
|
|
if(ret == 0)
|
|
wpa_printf(MSG_DEBUG, "WPS: init OK.");
|
|
else
|
|
wpa_printf(MSG_DEBUG, "WPS: init failed.");
|
|
|
|
return ret;
|
|
}
|
|
#endif
|