Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / p2p / p2p_parse.c
index 25337a5..bd1e68b 100644 (file)
@@ -2,14 +2,8 @@
  * 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"
@@ -155,7 +149,8 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                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));
@@ -166,7 +161,7 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                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
@@ -208,7 +203,7 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                           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;
@@ -273,6 +268,125 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
                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);
@@ -301,23 +415,27 @@ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
 
        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;
@@ -327,6 +445,7 @@ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg)
 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))
@@ -344,6 +463,7 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
                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];
@@ -352,6 +472,27 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg)
                           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;
 }
@@ -375,7 +516,7 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
        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;
@@ -400,6 +541,16 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
                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;
 }
 
@@ -429,6 +580,33 @@ int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg)
 }
 
 
+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
@@ -439,6 +617,10 @@ void p2p_parse_free(struct p2p_message *msg)
        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 */
 }
 
 
@@ -495,8 +677,8 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
                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;
 
@@ -524,7 +706,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
 
        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;
@@ -534,7 +716,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
                                  "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;
 
@@ -545,7 +727,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
                                  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;
 
@@ -554,7 +736,7 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
                                          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;
                }
@@ -563,13 +745,13 @@ static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf,
                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;
        }
@@ -603,7 +785,7 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
                                  "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;
        }
@@ -615,14 +797,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
                                  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;
 
@@ -630,14 +812,14 @@ int p2p_attr_text(struct wpabuf *data, char *buf, char *end)
                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;