* P2P - IE parser
* Copyright (c) 2009-2010, Atheros Communications
*
- * 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
pos += 2;
nlen = WPA_GET_BE16(pos);
pos += 2;
- if (data + len - pos < (int) nlen || nlen > 32) {
+ if (data + len - pos < (int) nlen ||
+ nlen > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
"length %d (buf len %d)", (int) nlen,
(int) (data + len - pos));
for (i = 0; i < nlen; i++) {
if (msg->device_name[i] == '\0')
break;
- if (msg->device_name[i] < 32)
+ if (is_ctrl_char(msg->device_name[i]))
msg->device_name[i] = '_';
}
wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR
MAC2STR(msg->group_bssid));
break;
case P2P_ATTR_GROUP_ID:
- if (len < ETH_ALEN || len > ETH_ALEN + 32) {
+ if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID "
"attribute length %d", len);
return -1;
wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u",
*msg->minor_reason_code);
break;
+ case P2P_ATTR_OOB_GO_NEG_CHANNEL:
+ if (len < 6) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg "
+ "Channel attribute (length %d)", len);
+ return -1;
+ }
+ msg->oob_go_neg_channel = data;
+ wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: "
+ "Country %c%c(0x%02x) Operating Class %d "
+ "Channel Number %d Role %d",
+ data[0], data[1], data[2], data[3], data[4],
+ data[5]);
+ break;
+ case P2P_ATTR_SERVICE_HASH:
+ if (len < P2PS_HASH_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Hash (length %u)",
+ len);
+ return -1;
+ }
+ msg->service_hash_count = len / P2PS_HASH_LEN;
+ msg->service_hash = data;
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len);
+ break;
+ case P2P_ATTR_SESSION_INFORMATION_DATA:
+ msg->session_info = data;
+ msg->session_info_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p",
+ len, data);
+ break;
+ case P2P_ATTR_CONNECTION_CAPABILITY:
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Connection Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->conn_cap = data;
+ wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
+ *msg->conn_cap);
+ break;
+ case P2P_ATTR_ADVERTISEMENT_ID:
+ if (len < 10) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Advertisement ID (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_id = data;
+ msg->adv_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x",
+ WPA_GET_LE32(data));
+ break;
+ case P2P_ATTR_ADVERTISED_SERVICE:
+ if (len < 8) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Service Instance (length %u)",
+ len);
+ return -1;
+ }
+ msg->adv_service_instance = data;
+ msg->adv_service_instance_len = len;
+ if (len <= 255 + 8) {
+ char str[256];
+ u8 namelen;
+
+ namelen = data[6];
+ if (namelen > len - 7)
+ break;
+ os_memcpy(str, &data[7], namelen);
+ str[namelen] = '\0';
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s",
+ WPA_GET_LE32(data), str);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p",
+ data);
+ }
+ break;
+ case P2P_ATTR_SESSION_ID:
+ if (len < sizeof(u32) + ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Session ID Info (length %u)",
+ len);
+ return -1;
+ }
+ msg->session_id = data;
+ msg->session_mac = &data[sizeof(u32)];
+ wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR,
+ WPA_GET_LE32(data), MAC2STR(msg->session_mac));
+ break;
+ case P2P_ATTR_FEATURE_CAPABILITY:
+ if (!len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Feature Capability (length %u)",
+ len);
+ return -1;
+ }
+ msg->feature_cap = data;
+ msg->feature_cap_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len);
+ break;
+ case P2P_ATTR_PERSISTENT_GROUP:
+ {
+ if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Invalid Persistent Group Info (length %u)",
+ len);
+ return -1;
+ }
+
+ msg->persistent_dev = data;
+ msg->persistent_ssid_len = len - ETH_ALEN;
+ msg->persistent_ssid = &data[ETH_ALEN];
+ wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s",
+ MAC2STR(msg->persistent_dev),
+ wpa_ssid_txt(msg->persistent_ssid,
+ msg->persistent_ssid_len));
+ break;
+ }
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
while (pos < end) {
u16 attr_len;
- if (pos + 2 >= end) {
+ u8 id;
+
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
return -1;
}
- attr_len = WPA_GET_LE16(pos + 1);
+ id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
- pos[0], attr_len);
- if (pos + 3 + attr_len > end) {
+ id, attr_len);
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
"(len=%u left=%d)",
- attr_len, (int) (end - pos - 3));
+ attr_len, (int) (end - pos));
wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
return -1;
}
- if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+ if (p2p_parse_attribute(id, pos, attr_len, msg))
return -1;
- pos += 3 + attr_len;
+ pos += attr_len;
}
return 0;
static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
{
struct wps_parse_attr attr;
+ int i;
wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE");
if (wps_parse_msg(buf, &attr))
msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id);
wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d",
msg->dev_password_id);
+ msg->dev_password_id_present = 1;
}
if (attr.primary_dev_type) {
char devtype[WPS_DEV_TYPE_BUFSIZE];
wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype,
sizeof(devtype)));
}
+ if (attr.sec_dev_type_list) {
+ msg->wps_sec_dev_type_list = attr.sec_dev_type_list;
+ msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len;
+ }
+
+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+ msg->wps_vendor_ext[i] = attr.vendor_ext[i];
+ msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i];
+ }
+
+ msg->manufacturer = attr.manufacturer;
+ msg->manufacturer_len = attr.manufacturer_len;
+ msg->model_name = attr.model_name;
+ msg->model_name_len = attr.model_name_len;
+ msg->model_number = attr.model_number;
+ msg->model_number_len = attr.model_number_len;
+ msg->serial_number = attr.serial_number;
+ msg->serial_number_len = attr.serial_number_len;
+
+ msg->oob_dev_password = attr.oob_dev_password;
+ msg->oob_dev_password_len = attr.oob_dev_password_len;
return 0;
}
struct ieee802_11_elems elems;
ieee802_11_parse_elems(data, len, &elems, 0);
- if (elems.ds_params && elems.ds_params_len >= 1)
+ if (elems.ds_params)
msg->ds_params = elems.ds_params;
if (elems.ssid)
msg->ssid = elems.ssid - 2;
return -1;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (elems.wfd) {
+ msg->wfd_subelems = ieee802_11_vendor_ie_concat(
+ data, len, WFD_IE_VENDOR_TYPE);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ msg->pref_freq_list = elems.pref_freq_list;
+ msg->pref_freq_list_len = elems.pref_freq_list_len;
+
return 0;
}
}
+int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
+ size_t p2p_len, struct p2p_message *msg)
+{
+ os_memset(msg, 0, sizeof(*msg));
+
+ msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
+ if (msg->wps_attributes &&
+ p2p_parse_wps_ie(msg->wps_attributes, msg)) {
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
+ if (msg->p2p_attributes &&
+ p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
+ if (msg->p2p_attributes)
+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
+ msg->p2p_attributes);
+ p2p_parse_free(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* p2p_parse_free - Free temporary data from P2P parsing
* @msg: Parsed attributes
msg->p2p_attributes = NULL;
wpabuf_free(msg->wps_attributes);
msg->wps_attributes = NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ wpabuf_free(msg->wfd_subelems);
+ msg->wfd_subelems = NULL;
+#endif /* CONFIG_WIFI_DISPLAY */
}
t += 2;
if (count > cend - t)
return -1; /* invalid Device Name TLV */
- if (count >= 32)
- count = 32;
+ if (count >= WPS_DEV_NAME_MAX_LEN)
+ count = WPS_DEV_NAME_MAX_LEN;
cli->dev_name = (const char *) t;
cli->dev_name_len = count;
for (i = 0; i < info.num_clients; i++) {
struct p2p_client_info *cli;
- char name[33];
+ char name[WPS_DEV_NAME_MAX_LEN + 1];
char devtype[WPS_DEV_TYPE_BUFSIZE];
u8 s;
int count;
"dev=" MACSTR " iface=" MACSTR,
MAC2STR(cli->p2p_device_addr),
MAC2STR(cli->p2p_interface_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
wps_dev_type_bin2str(cli->pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
wps_dev_type_bin2str(
&cli->sec_dev_types[s * 8],
devtype, sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
name[cli->dev_name_len] = '\0';
count = (int) cli->dev_name_len - 1;
while (count >= 0) {
- if (name[count] < 32)
+ if (is_ctrl_char(name[count]))
name[count] = '_';
count--;
}
ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
"p2p_dev_capab=0x%x\n"
"p2p_group_capab=0x%x\n",
msg.capability[0], msg.capability[1]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
wps_dev_type_bin2str(msg.pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
msg.device_name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
"\n",
MAC2STR(msg.p2p_device_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
msg.config_methods);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;