1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * P2P - IE parser 3e5b75505Sopenharmony_ci * Copyright (c) 2009-2010, Atheros Communications 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 13e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h" 14e5b75505Sopenharmony_ci#include "wps/wps_i.h" 15e5b75505Sopenharmony_ci#include "p2p_i.h" 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_civoid p2p_copy_filter_devname(char *dst, size_t dst_len, 19e5b75505Sopenharmony_ci const void *src, size_t src_len) 20e5b75505Sopenharmony_ci{ 21e5b75505Sopenharmony_ci size_t i; 22e5b75505Sopenharmony_ci 23e5b75505Sopenharmony_ci if (src_len >= dst_len) 24e5b75505Sopenharmony_ci src_len = dst_len - 1; 25e5b75505Sopenharmony_ci os_memcpy(dst, src, src_len); 26e5b75505Sopenharmony_ci dst[src_len] = '\0'; 27e5b75505Sopenharmony_ci for (i = 0; i < src_len; i++) { 28e5b75505Sopenharmony_ci if (dst[i] == '\0') 29e5b75505Sopenharmony_ci break; 30e5b75505Sopenharmony_ci if (is_ctrl_char(dst[i])) 31e5b75505Sopenharmony_ci dst[i] = '_'; 32e5b75505Sopenharmony_ci } 33e5b75505Sopenharmony_ci} 34e5b75505Sopenharmony_ci 35e5b75505Sopenharmony_ci 36e5b75505Sopenharmony_cistatic int p2p_parse_attribute(u8 id, const u8 *data, u16 len, 37e5b75505Sopenharmony_ci struct p2p_message *msg) 38e5b75505Sopenharmony_ci{ 39e5b75505Sopenharmony_ci const u8 *pos; 40e5b75505Sopenharmony_ci u16 nlen; 41e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci switch (id) { 44e5b75505Sopenharmony_ci case P2P_ATTR_CAPABILITY: 45e5b75505Sopenharmony_ci if (len < 2) { 46e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Capability " 47e5b75505Sopenharmony_ci "attribute (length %d)", len); 48e5b75505Sopenharmony_ci return -1; 49e5b75505Sopenharmony_ci } 50e5b75505Sopenharmony_ci msg->capability = data; 51e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x " 52e5b75505Sopenharmony_ci "Group Capability %02x", 53e5b75505Sopenharmony_ci data[0], data[1]); 54e5b75505Sopenharmony_ci break; 55e5b75505Sopenharmony_ci case P2P_ATTR_DEVICE_ID: 56e5b75505Sopenharmony_ci if (len < ETH_ALEN) { 57e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Device ID " 58e5b75505Sopenharmony_ci "attribute (length %d)", len); 59e5b75505Sopenharmony_ci return -1; 60e5b75505Sopenharmony_ci } 61e5b75505Sopenharmony_ci msg->device_id = data; 62e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR, 63e5b75505Sopenharmony_ci MAC2STR(msg->device_id)); 64e5b75505Sopenharmony_ci break; 65e5b75505Sopenharmony_ci case P2P_ATTR_GROUP_OWNER_INTENT: 66e5b75505Sopenharmony_ci if (len < 1) { 67e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent " 68e5b75505Sopenharmony_ci "attribute (length %d)", len); 69e5b75505Sopenharmony_ci return -1; 70e5b75505Sopenharmony_ci } 71e5b75505Sopenharmony_ci msg->go_intent = data; 72e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u " 73e5b75505Sopenharmony_ci "Tie breaker %u", data[0] >> 1, data[0] & 0x01); 74e5b75505Sopenharmony_ci break; 75e5b75505Sopenharmony_ci case P2P_ATTR_STATUS: 76e5b75505Sopenharmony_ci if (len < 1) { 77e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Status " 78e5b75505Sopenharmony_ci "attribute (length %d)", len); 79e5b75505Sopenharmony_ci return -1; 80e5b75505Sopenharmony_ci } 81e5b75505Sopenharmony_ci msg->status = data; 82e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]); 83e5b75505Sopenharmony_ci break; 84e5b75505Sopenharmony_ci case P2P_ATTR_LISTEN_CHANNEL: 85e5b75505Sopenharmony_ci if (len == 0) { 86e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore " 87e5b75505Sopenharmony_ci "null channel"); 88e5b75505Sopenharmony_ci break; 89e5b75505Sopenharmony_ci } 90e5b75505Sopenharmony_ci if (len < 5) { 91e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel " 92e5b75505Sopenharmony_ci "attribute (length %d)", len); 93e5b75505Sopenharmony_ci return -1; 94e5b75505Sopenharmony_ci } 95e5b75505Sopenharmony_ci msg->listen_channel = data; 96e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: " 97e5b75505Sopenharmony_ci "Country %c%c(0x%02x) Regulatory " 98e5b75505Sopenharmony_ci "Class %d Channel Number %d", data[0], data[1], 99e5b75505Sopenharmony_ci data[2], data[3], data[4]); 100e5b75505Sopenharmony_ci break; 101e5b75505Sopenharmony_ci case P2P_ATTR_OPERATING_CHANNEL: 102e5b75505Sopenharmony_ci if (len == 0) { 103e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " 104e5b75505Sopenharmony_ci "Ignore null channel"); 105e5b75505Sopenharmony_ci break; 106e5b75505Sopenharmony_ci } 107e5b75505Sopenharmony_ci if (len < 5) { 108e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Operating " 109e5b75505Sopenharmony_ci "Channel attribute (length %d)", len); 110e5b75505Sopenharmony_ci return -1; 111e5b75505Sopenharmony_ci } 112e5b75505Sopenharmony_ci msg->operating_channel = data; 113e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " 114e5b75505Sopenharmony_ci "Country %c%c(0x%02x) Regulatory " 115e5b75505Sopenharmony_ci "Class %d Channel Number %d", data[0], data[1], 116e5b75505Sopenharmony_ci data[2], data[3], data[4]); 117e5b75505Sopenharmony_ci break; 118e5b75505Sopenharmony_ci case P2P_ATTR_CHANNEL_LIST: 119e5b75505Sopenharmony_ci if (len < 3) { 120e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Channel List " 121e5b75505Sopenharmony_ci "attribute (length %d)", len); 122e5b75505Sopenharmony_ci return -1; 123e5b75505Sopenharmony_ci } 124e5b75505Sopenharmony_ci msg->channel_list = data; 125e5b75505Sopenharmony_ci msg->channel_list_len = len; 126e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String " 127e5b75505Sopenharmony_ci "'%c%c(0x%02x)'", data[0], data[1], data[2]); 128e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", 129e5b75505Sopenharmony_ci msg->channel_list, msg->channel_list_len); 130e5b75505Sopenharmony_ci break; 131e5b75505Sopenharmony_ci case P2P_ATTR_GROUP_INFO: 132e5b75505Sopenharmony_ci msg->group_info = data; 133e5b75505Sopenharmony_ci msg->group_info_len = len; 134e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Group Info"); 135e5b75505Sopenharmony_ci break; 136e5b75505Sopenharmony_ci case P2P_ATTR_DEVICE_INFO: 137e5b75505Sopenharmony_ci if (len < ETH_ALEN + 2 + 8 + 1) { 138e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Device Info " 139e5b75505Sopenharmony_ci "attribute (length %d)", len); 140e5b75505Sopenharmony_ci return -1; 141e5b75505Sopenharmony_ci } 142e5b75505Sopenharmony_ci msg->p2p_device_info = data; 143e5b75505Sopenharmony_ci msg->p2p_device_info_len = len; 144e5b75505Sopenharmony_ci pos = data; 145e5b75505Sopenharmony_ci msg->p2p_device_addr = pos; 146e5b75505Sopenharmony_ci pos += ETH_ALEN; 147e5b75505Sopenharmony_ci msg->config_methods = WPA_GET_BE16(pos); 148e5b75505Sopenharmony_ci pos += 2; 149e5b75505Sopenharmony_ci msg->pri_dev_type = pos; 150e5b75505Sopenharmony_ci pos += 8; 151e5b75505Sopenharmony_ci msg->num_sec_dev_types = *pos++; 152e5b75505Sopenharmony_ci if (msg->num_sec_dev_types * 8 > data + len - pos) { 153e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Device Info underflow"); 154e5b75505Sopenharmony_ci return -1; 155e5b75505Sopenharmony_ci } 156e5b75505Sopenharmony_ci pos += msg->num_sec_dev_types * 8; 157e5b75505Sopenharmony_ci if (data + len - pos < 4) { 158e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " 159e5b75505Sopenharmony_ci "length %d", (int) (data + len - pos)); 160e5b75505Sopenharmony_ci return -1; 161e5b75505Sopenharmony_ci } 162e5b75505Sopenharmony_ci if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) { 163e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name " 164e5b75505Sopenharmony_ci "header", pos, 4); 165e5b75505Sopenharmony_ci return -1; 166e5b75505Sopenharmony_ci } 167e5b75505Sopenharmony_ci pos += 2; 168e5b75505Sopenharmony_ci nlen = WPA_GET_BE16(pos); 169e5b75505Sopenharmony_ci pos += 2; 170e5b75505Sopenharmony_ci if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) { 171e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " 172e5b75505Sopenharmony_ci "length %u (buf len %d)", nlen, 173e5b75505Sopenharmony_ci (int) (data + len - pos)); 174e5b75505Sopenharmony_ci return -1; 175e5b75505Sopenharmony_ci } 176e5b75505Sopenharmony_ci p2p_copy_filter_devname(msg->device_name, 177e5b75505Sopenharmony_ci sizeof(msg->device_name), pos, nlen); 178e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "P2P: * Device Info: addr " MACSTR 179e5b75505Sopenharmony_ci " primary device type %s device name '%s' " 180e5b75505Sopenharmony_ci "config methods 0x%x", 181e5b75505Sopenharmony_ci MAC2STR(msg->p2p_device_addr), 182e5b75505Sopenharmony_ci wps_dev_type_bin2str(msg->pri_dev_type, devtype, 183e5b75505Sopenharmony_ci sizeof(devtype)), 184e5b75505Sopenharmony_ci msg->device_name, msg->config_methods); 185e5b75505Sopenharmony_ci break; 186e5b75505Sopenharmony_ci case P2P_ATTR_CONFIGURATION_TIMEOUT: 187e5b75505Sopenharmony_ci if (len < 2) { 188e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Configuration " 189e5b75505Sopenharmony_ci "Timeout attribute (length %d)", len); 190e5b75505Sopenharmony_ci return -1; 191e5b75505Sopenharmony_ci } 192e5b75505Sopenharmony_ci msg->config_timeout = data; 193e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout"); 194e5b75505Sopenharmony_ci break; 195e5b75505Sopenharmony_ci case P2P_ATTR_INTENDED_INTERFACE_ADDR: 196e5b75505Sopenharmony_ci if (len < ETH_ALEN) { 197e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P " 198e5b75505Sopenharmony_ci "Interface Address attribute (length %d)", 199e5b75505Sopenharmony_ci len); 200e5b75505Sopenharmony_ci return -1; 201e5b75505Sopenharmony_ci } 202e5b75505Sopenharmony_ci msg->intended_addr = data; 203e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: " 204e5b75505Sopenharmony_ci MACSTR, MAC2STR(msg->intended_addr)); 205e5b75505Sopenharmony_ci break; 206e5b75505Sopenharmony_ci case P2P_ATTR_GROUP_BSSID: 207e5b75505Sopenharmony_ci if (len < ETH_ALEN) { 208e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID " 209e5b75505Sopenharmony_ci "attribute (length %d)", len); 210e5b75505Sopenharmony_ci return -1; 211e5b75505Sopenharmony_ci } 212e5b75505Sopenharmony_ci msg->group_bssid = data; 213e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR, 214e5b75505Sopenharmony_ci MAC2STR(msg->group_bssid)); 215e5b75505Sopenharmony_ci break; 216e5b75505Sopenharmony_ci case P2P_ATTR_GROUP_ID: 217e5b75505Sopenharmony_ci if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { 218e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID " 219e5b75505Sopenharmony_ci "attribute length %d", len); 220e5b75505Sopenharmony_ci return -1; 221e5b75505Sopenharmony_ci } 222e5b75505Sopenharmony_ci msg->group_id = data; 223e5b75505Sopenharmony_ci msg->group_id_len = len; 224e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address " 225e5b75505Sopenharmony_ci MACSTR, MAC2STR(msg->group_id)); 226e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID", 227e5b75505Sopenharmony_ci msg->group_id + ETH_ALEN, 228e5b75505Sopenharmony_ci msg->group_id_len - ETH_ALEN); 229e5b75505Sopenharmony_ci break; 230e5b75505Sopenharmony_ci case P2P_ATTR_INVITATION_FLAGS: 231e5b75505Sopenharmony_ci if (len < 1) { 232e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Invitation " 233e5b75505Sopenharmony_ci "Flag attribute (length %d)", len); 234e5b75505Sopenharmony_ci return -1; 235e5b75505Sopenharmony_ci } 236e5b75505Sopenharmony_ci msg->invitation_flags = data; 237e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", 238e5b75505Sopenharmony_ci data[0]); 239e5b75505Sopenharmony_ci break; 240e5b75505Sopenharmony_ci case P2P_ATTR_MANAGEABILITY: 241e5b75505Sopenharmony_ci if (len < 1) { 242e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Manageability " 243e5b75505Sopenharmony_ci "attribute (length %d)", len); 244e5b75505Sopenharmony_ci return -1; 245e5b75505Sopenharmony_ci } 246e5b75505Sopenharmony_ci msg->manageability = data; 247e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x", 248e5b75505Sopenharmony_ci data[0]); 249e5b75505Sopenharmony_ci break; 250e5b75505Sopenharmony_ci case P2P_ATTR_NOTICE_OF_ABSENCE: 251e5b75505Sopenharmony_ci if (len < 2) { 252e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Notice of " 253e5b75505Sopenharmony_ci "Absence attribute (length %d)", len); 254e5b75505Sopenharmony_ci return -1; 255e5b75505Sopenharmony_ci } 256e5b75505Sopenharmony_ci msg->noa = data; 257e5b75505Sopenharmony_ci msg->noa_len = len; 258e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); 259e5b75505Sopenharmony_ci break; 260e5b75505Sopenharmony_ci case P2P_ATTR_EXT_LISTEN_TIMING: 261e5b75505Sopenharmony_ci if (len < 4) { 262e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen " 263e5b75505Sopenharmony_ci "Timing attribute (length %d)", len); 264e5b75505Sopenharmony_ci return -1; 265e5b75505Sopenharmony_ci } 266e5b75505Sopenharmony_ci msg->ext_listen_timing = data; 267e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing " 268e5b75505Sopenharmony_ci "(period %u msec interval %u msec)", 269e5b75505Sopenharmony_ci WPA_GET_LE16(msg->ext_listen_timing), 270e5b75505Sopenharmony_ci WPA_GET_LE16(msg->ext_listen_timing + 2)); 271e5b75505Sopenharmony_ci break; 272e5b75505Sopenharmony_ci case P2P_ATTR_MINOR_REASON_CODE: 273e5b75505Sopenharmony_ci if (len < 1) { 274e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason " 275e5b75505Sopenharmony_ci "Code attribute (length %d)", len); 276e5b75505Sopenharmony_ci return -1; 277e5b75505Sopenharmony_ci } 278e5b75505Sopenharmony_ci msg->minor_reason_code = data; 279e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u", 280e5b75505Sopenharmony_ci *msg->minor_reason_code); 281e5b75505Sopenharmony_ci break; 282e5b75505Sopenharmony_ci case P2P_ATTR_OOB_GO_NEG_CHANNEL: 283e5b75505Sopenharmony_ci if (len < 6) { 284e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg " 285e5b75505Sopenharmony_ci "Channel attribute (length %d)", len); 286e5b75505Sopenharmony_ci return -1; 287e5b75505Sopenharmony_ci } 288e5b75505Sopenharmony_ci msg->oob_go_neg_channel = data; 289e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: " 290e5b75505Sopenharmony_ci "Country %c%c(0x%02x) Operating Class %d " 291e5b75505Sopenharmony_ci "Channel Number %d Role %d", 292e5b75505Sopenharmony_ci data[0], data[1], data[2], data[3], data[4], 293e5b75505Sopenharmony_ci data[5]); 294e5b75505Sopenharmony_ci break; 295e5b75505Sopenharmony_ci case P2P_ATTR_SERVICE_HASH: 296e5b75505Sopenharmony_ci if (len < P2PS_HASH_LEN) { 297e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 298e5b75505Sopenharmony_ci "P2P: Too short Service Hash (length %u)", 299e5b75505Sopenharmony_ci len); 300e5b75505Sopenharmony_ci return -1; 301e5b75505Sopenharmony_ci } 302e5b75505Sopenharmony_ci msg->service_hash_count = len / P2PS_HASH_LEN; 303e5b75505Sopenharmony_ci msg->service_hash = data; 304e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len); 305e5b75505Sopenharmony_ci break; 306e5b75505Sopenharmony_ci case P2P_ATTR_SESSION_INFORMATION_DATA: 307e5b75505Sopenharmony_ci msg->session_info = data; 308e5b75505Sopenharmony_ci msg->session_info_len = len; 309e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p", 310e5b75505Sopenharmony_ci len, data); 311e5b75505Sopenharmony_ci break; 312e5b75505Sopenharmony_ci case P2P_ATTR_CONNECTION_CAPABILITY: 313e5b75505Sopenharmony_ci if (len < 1) { 314e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 315e5b75505Sopenharmony_ci "P2P: Too short Connection Capability (length %u)", 316e5b75505Sopenharmony_ci len); 317e5b75505Sopenharmony_ci return -1; 318e5b75505Sopenharmony_ci } 319e5b75505Sopenharmony_ci msg->conn_cap = data; 320e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x", 321e5b75505Sopenharmony_ci *msg->conn_cap); 322e5b75505Sopenharmony_ci break; 323e5b75505Sopenharmony_ci case P2P_ATTR_ADVERTISEMENT_ID: 324e5b75505Sopenharmony_ci if (len < 10) { 325e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 326e5b75505Sopenharmony_ci "P2P: Too short Advertisement ID (length %u)", 327e5b75505Sopenharmony_ci len); 328e5b75505Sopenharmony_ci return -1; 329e5b75505Sopenharmony_ci } 330e5b75505Sopenharmony_ci msg->adv_id = data; 331e5b75505Sopenharmony_ci msg->adv_mac = &data[sizeof(u32)]; 332e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x", 333e5b75505Sopenharmony_ci WPA_GET_LE32(data)); 334e5b75505Sopenharmony_ci break; 335e5b75505Sopenharmony_ci case P2P_ATTR_ADVERTISED_SERVICE: 336e5b75505Sopenharmony_ci if (len < 8) { 337e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 338e5b75505Sopenharmony_ci "P2P: Too short Service Instance (length %u)", 339e5b75505Sopenharmony_ci len); 340e5b75505Sopenharmony_ci return -1; 341e5b75505Sopenharmony_ci } 342e5b75505Sopenharmony_ci msg->adv_service_instance = data; 343e5b75505Sopenharmony_ci msg->adv_service_instance_len = len; 344e5b75505Sopenharmony_ci if (len <= 255 + 8) { 345e5b75505Sopenharmony_ci char str[256]; 346e5b75505Sopenharmony_ci u8 namelen; 347e5b75505Sopenharmony_ci 348e5b75505Sopenharmony_ci namelen = data[6]; 349e5b75505Sopenharmony_ci if (namelen > len - 7) 350e5b75505Sopenharmony_ci break; 351e5b75505Sopenharmony_ci os_memcpy(str, &data[7], namelen); 352e5b75505Sopenharmony_ci str[namelen] = '\0'; 353e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s", 354e5b75505Sopenharmony_ci WPA_GET_LE32(data), str); 355e5b75505Sopenharmony_ci } else { 356e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p", 357e5b75505Sopenharmony_ci data); 358e5b75505Sopenharmony_ci } 359e5b75505Sopenharmony_ci break; 360e5b75505Sopenharmony_ci case P2P_ATTR_SESSION_ID: 361e5b75505Sopenharmony_ci if (len < sizeof(u32) + ETH_ALEN) { 362e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 363e5b75505Sopenharmony_ci "P2P: Too short Session ID Info (length %u)", 364e5b75505Sopenharmony_ci len); 365e5b75505Sopenharmony_ci return -1; 366e5b75505Sopenharmony_ci } 367e5b75505Sopenharmony_ci msg->session_id = data; 368e5b75505Sopenharmony_ci msg->session_mac = &data[sizeof(u32)]; 369e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR, 370e5b75505Sopenharmony_ci WPA_GET_LE32(data), MAC2STR(msg->session_mac)); 371e5b75505Sopenharmony_ci break; 372e5b75505Sopenharmony_ci case P2P_ATTR_FEATURE_CAPABILITY: 373e5b75505Sopenharmony_ci if (!len) { 374e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 375e5b75505Sopenharmony_ci "P2P: Too short Feature Capability (length %u)", 376e5b75505Sopenharmony_ci len); 377e5b75505Sopenharmony_ci return -1; 378e5b75505Sopenharmony_ci } 379e5b75505Sopenharmony_ci msg->feature_cap = data; 380e5b75505Sopenharmony_ci msg->feature_cap_len = len; 381e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len); 382e5b75505Sopenharmony_ci break; 383e5b75505Sopenharmony_ci case P2P_ATTR_PERSISTENT_GROUP: 384e5b75505Sopenharmony_ci { 385e5b75505Sopenharmony_ci if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { 386e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 387e5b75505Sopenharmony_ci "P2P: Invalid Persistent Group Info (length %u)", 388e5b75505Sopenharmony_ci len); 389e5b75505Sopenharmony_ci return -1; 390e5b75505Sopenharmony_ci } 391e5b75505Sopenharmony_ci 392e5b75505Sopenharmony_ci msg->persistent_dev = data; 393e5b75505Sopenharmony_ci msg->persistent_ssid_len = len - ETH_ALEN; 394e5b75505Sopenharmony_ci msg->persistent_ssid = &data[ETH_ALEN]; 395e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s", 396e5b75505Sopenharmony_ci MAC2STR(msg->persistent_dev), 397e5b75505Sopenharmony_ci wpa_ssid_txt(msg->persistent_ssid, 398e5b75505Sopenharmony_ci msg->persistent_ssid_len)); 399e5b75505Sopenharmony_ci break; 400e5b75505Sopenharmony_ci } 401e5b75505Sopenharmony_ci default: 402e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " 403e5b75505Sopenharmony_ci "(length %d)", id, len); 404e5b75505Sopenharmony_ci break; 405e5b75505Sopenharmony_ci } 406e5b75505Sopenharmony_ci 407e5b75505Sopenharmony_ci return 0; 408e5b75505Sopenharmony_ci} 409e5b75505Sopenharmony_ci 410e5b75505Sopenharmony_ci 411e5b75505Sopenharmony_ci/** 412e5b75505Sopenharmony_ci * p2p_parse_p2p_ie - Parse P2P IE 413e5b75505Sopenharmony_ci * @buf: Concatenated P2P IE(s) payload 414e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes 415e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 416e5b75505Sopenharmony_ci * 417e5b75505Sopenharmony_ci * Note: Caller is responsible for clearing the msg data structure before 418e5b75505Sopenharmony_ci * calling this function. 419e5b75505Sopenharmony_ci */ 420e5b75505Sopenharmony_ciint p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg) 421e5b75505Sopenharmony_ci{ 422e5b75505Sopenharmony_ci const u8 *pos = wpabuf_head_u8(buf); 423e5b75505Sopenharmony_ci const u8 *end = pos + wpabuf_len(buf); 424e5b75505Sopenharmony_ci 425e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE"); 426e5b75505Sopenharmony_ci 427e5b75505Sopenharmony_ci while (pos < end) { 428e5b75505Sopenharmony_ci u16 attr_len; 429e5b75505Sopenharmony_ci u8 id; 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_ci if (end - pos < 3) { 432e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute"); 433e5b75505Sopenharmony_ci return -1; 434e5b75505Sopenharmony_ci } 435e5b75505Sopenharmony_ci id = *pos++; 436e5b75505Sopenharmony_ci attr_len = WPA_GET_LE16(pos); 437e5b75505Sopenharmony_ci pos += 2; 438e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u", 439e5b75505Sopenharmony_ci id, attr_len); 440e5b75505Sopenharmony_ci if (attr_len > end - pos) { 441e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Attribute underflow " 442e5b75505Sopenharmony_ci "(len=%u left=%d)", 443e5b75505Sopenharmony_ci attr_len, (int) (end - pos)); 444e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos); 445e5b75505Sopenharmony_ci return -1; 446e5b75505Sopenharmony_ci } 447e5b75505Sopenharmony_ci if (p2p_parse_attribute(id, pos, attr_len, msg)) 448e5b75505Sopenharmony_ci return -1; 449e5b75505Sopenharmony_ci pos += attr_len; 450e5b75505Sopenharmony_ci } 451e5b75505Sopenharmony_ci 452e5b75505Sopenharmony_ci return 0; 453e5b75505Sopenharmony_ci} 454e5b75505Sopenharmony_ci 455e5b75505Sopenharmony_ci 456e5b75505Sopenharmony_cistatic int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg) 457e5b75505Sopenharmony_ci{ 458e5b75505Sopenharmony_ci struct wps_parse_attr attr; 459e5b75505Sopenharmony_ci int i; 460e5b75505Sopenharmony_ci 461e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE"); 462e5b75505Sopenharmony_ci if (wps_parse_msg(buf, &attr)) 463e5b75505Sopenharmony_ci return -1; 464e5b75505Sopenharmony_ci if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) && 465e5b75505Sopenharmony_ci !msg->device_name[0]) 466e5b75505Sopenharmony_ci os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len); 467e5b75505Sopenharmony_ci if (attr.config_methods) { 468e5b75505Sopenharmony_ci msg->wps_config_methods = 469e5b75505Sopenharmony_ci WPA_GET_BE16(attr.config_methods); 470e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x", 471e5b75505Sopenharmony_ci msg->wps_config_methods); 472e5b75505Sopenharmony_ci } 473e5b75505Sopenharmony_ci if (attr.dev_password_id) { 474e5b75505Sopenharmony_ci msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id); 475e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d", 476e5b75505Sopenharmony_ci msg->dev_password_id); 477e5b75505Sopenharmony_ci msg->dev_password_id_present = 1; 478e5b75505Sopenharmony_ci } 479e5b75505Sopenharmony_ci if (attr.primary_dev_type) { 480e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 481e5b75505Sopenharmony_ci msg->wps_pri_dev_type = attr.primary_dev_type; 482e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s", 483e5b75505Sopenharmony_ci wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype, 484e5b75505Sopenharmony_ci sizeof(devtype))); 485e5b75505Sopenharmony_ci } 486e5b75505Sopenharmony_ci if (attr.sec_dev_type_list) { 487e5b75505Sopenharmony_ci msg->wps_sec_dev_type_list = attr.sec_dev_type_list; 488e5b75505Sopenharmony_ci msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len; 489e5b75505Sopenharmony_ci } 490e5b75505Sopenharmony_ci 491e5b75505Sopenharmony_ci for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 492e5b75505Sopenharmony_ci msg->wps_vendor_ext[i] = attr.vendor_ext[i]; 493e5b75505Sopenharmony_ci msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i]; 494e5b75505Sopenharmony_ci } 495e5b75505Sopenharmony_ci 496e5b75505Sopenharmony_ci msg->manufacturer = attr.manufacturer; 497e5b75505Sopenharmony_ci msg->manufacturer_len = attr.manufacturer_len; 498e5b75505Sopenharmony_ci msg->model_name = attr.model_name; 499e5b75505Sopenharmony_ci msg->model_name_len = attr.model_name_len; 500e5b75505Sopenharmony_ci msg->model_number = attr.model_number; 501e5b75505Sopenharmony_ci msg->model_number_len = attr.model_number_len; 502e5b75505Sopenharmony_ci msg->serial_number = attr.serial_number; 503e5b75505Sopenharmony_ci msg->serial_number_len = attr.serial_number_len; 504e5b75505Sopenharmony_ci 505e5b75505Sopenharmony_ci msg->oob_dev_password = attr.oob_dev_password; 506e5b75505Sopenharmony_ci msg->oob_dev_password_len = attr.oob_dev_password_len; 507e5b75505Sopenharmony_ci 508e5b75505Sopenharmony_ci return 0; 509e5b75505Sopenharmony_ci} 510e5b75505Sopenharmony_ci 511e5b75505Sopenharmony_ci 512e5b75505Sopenharmony_ci/** 513e5b75505Sopenharmony_ci * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) 514e5b75505Sopenharmony_ci * @data: IEs from the message 515e5b75505Sopenharmony_ci * @len: Length of data buffer in octets 516e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes 517e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 518e5b75505Sopenharmony_ci * 519e5b75505Sopenharmony_ci * Note: Caller is responsible for clearing the msg data structure before 520e5b75505Sopenharmony_ci * calling this function. 521e5b75505Sopenharmony_ci * 522e5b75505Sopenharmony_ci * Note: Caller must free temporary memory allocations by calling 523e5b75505Sopenharmony_ci * p2p_parse_free() when the parsed data is not needed anymore. 524e5b75505Sopenharmony_ci */ 525e5b75505Sopenharmony_ciint p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) 526e5b75505Sopenharmony_ci{ 527e5b75505Sopenharmony_ci struct ieee802_11_elems elems; 528e5b75505Sopenharmony_ci 529e5b75505Sopenharmony_ci ieee802_11_parse_elems(data, len, &elems, 0); 530e5b75505Sopenharmony_ci if (elems.ds_params) 531e5b75505Sopenharmony_ci msg->ds_params = elems.ds_params; 532e5b75505Sopenharmony_ci if (elems.ssid) 533e5b75505Sopenharmony_ci msg->ssid = elems.ssid - 2; 534e5b75505Sopenharmony_ci 535e5b75505Sopenharmony_ci msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, 536e5b75505Sopenharmony_ci WPS_DEV_OUI_WFA); 537e5b75505Sopenharmony_ci if (msg->wps_attributes && 538e5b75505Sopenharmony_ci p2p_parse_wps_ie(msg->wps_attributes, msg)) { 539e5b75505Sopenharmony_ci p2p_parse_free(msg); 540e5b75505Sopenharmony_ci return -1; 541e5b75505Sopenharmony_ci } 542e5b75505Sopenharmony_ci 543e5b75505Sopenharmony_ci msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, 544e5b75505Sopenharmony_ci P2P_IE_VENDOR_TYPE); 545e5b75505Sopenharmony_ci if (msg->p2p_attributes && 546e5b75505Sopenharmony_ci p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { 547e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); 548e5b75505Sopenharmony_ci if (msg->p2p_attributes) 549e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", 550e5b75505Sopenharmony_ci msg->p2p_attributes); 551e5b75505Sopenharmony_ci p2p_parse_free(msg); 552e5b75505Sopenharmony_ci return -1; 553e5b75505Sopenharmony_ci } 554e5b75505Sopenharmony_ci 555e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 556e5b75505Sopenharmony_ci if (elems.wfd) { 557e5b75505Sopenharmony_ci msg->wfd_subelems = ieee802_11_vendor_ie_concat( 558e5b75505Sopenharmony_ci data, len, WFD_IE_VENDOR_TYPE); 559e5b75505Sopenharmony_ci } 560e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 561e5b75505Sopenharmony_ci 562e5b75505Sopenharmony_ci msg->pref_freq_list = elems.pref_freq_list; 563e5b75505Sopenharmony_ci msg->pref_freq_list_len = elems.pref_freq_list_len; 564e5b75505Sopenharmony_ci 565e5b75505Sopenharmony_ci return 0; 566e5b75505Sopenharmony_ci} 567e5b75505Sopenharmony_ci 568e5b75505Sopenharmony_ci 569e5b75505Sopenharmony_ci/** 570e5b75505Sopenharmony_ci * p2p_parse - Parse a P2P Action frame contents 571e5b75505Sopenharmony_ci * @data: Action frame payload after Category and Code fields 572e5b75505Sopenharmony_ci * @len: Length of data buffer in octets 573e5b75505Sopenharmony_ci * @msg: Buffer for returning parsed attributes 574e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 575e5b75505Sopenharmony_ci * 576e5b75505Sopenharmony_ci * Note: Caller must free temporary memory allocations by calling 577e5b75505Sopenharmony_ci * p2p_parse_free() when the parsed data is not needed anymore. 578e5b75505Sopenharmony_ci */ 579e5b75505Sopenharmony_ciint p2p_parse(const u8 *data, size_t len, struct p2p_message *msg) 580e5b75505Sopenharmony_ci{ 581e5b75505Sopenharmony_ci os_memset(msg, 0, sizeof(*msg)); 582e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Parsing the received message"); 583e5b75505Sopenharmony_ci if (len < 1) { 584e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message"); 585e5b75505Sopenharmony_ci return -1; 586e5b75505Sopenharmony_ci } 587e5b75505Sopenharmony_ci msg->dialog_token = data[0]; 588e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token); 589e5b75505Sopenharmony_ci 590e5b75505Sopenharmony_ci return p2p_parse_ies(data + 1, len - 1, msg); 591e5b75505Sopenharmony_ci} 592e5b75505Sopenharmony_ci 593e5b75505Sopenharmony_ci 594e5b75505Sopenharmony_ciint p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p, 595e5b75505Sopenharmony_ci size_t p2p_len, struct p2p_message *msg) 596e5b75505Sopenharmony_ci{ 597e5b75505Sopenharmony_ci os_memset(msg, 0, sizeof(*msg)); 598e5b75505Sopenharmony_ci 599e5b75505Sopenharmony_ci msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len); 600e5b75505Sopenharmony_ci if (msg->wps_attributes && 601e5b75505Sopenharmony_ci p2p_parse_wps_ie(msg->wps_attributes, msg)) { 602e5b75505Sopenharmony_ci p2p_parse_free(msg); 603e5b75505Sopenharmony_ci return -1; 604e5b75505Sopenharmony_ci } 605e5b75505Sopenharmony_ci 606e5b75505Sopenharmony_ci msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len); 607e5b75505Sopenharmony_ci if (msg->p2p_attributes && 608e5b75505Sopenharmony_ci p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { 609e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); 610e5b75505Sopenharmony_ci if (msg->p2p_attributes) 611e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", 612e5b75505Sopenharmony_ci msg->p2p_attributes); 613e5b75505Sopenharmony_ci p2p_parse_free(msg); 614e5b75505Sopenharmony_ci return -1; 615e5b75505Sopenharmony_ci } 616e5b75505Sopenharmony_ci 617e5b75505Sopenharmony_ci return 0; 618e5b75505Sopenharmony_ci} 619e5b75505Sopenharmony_ci 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_ci/** 622e5b75505Sopenharmony_ci * p2p_parse_free - Free temporary data from P2P parsing 623e5b75505Sopenharmony_ci * @msg: Parsed attributes 624e5b75505Sopenharmony_ci */ 625e5b75505Sopenharmony_civoid p2p_parse_free(struct p2p_message *msg) 626e5b75505Sopenharmony_ci{ 627e5b75505Sopenharmony_ci wpabuf_free(msg->p2p_attributes); 628e5b75505Sopenharmony_ci msg->p2p_attributes = NULL; 629e5b75505Sopenharmony_ci wpabuf_free(msg->wps_attributes); 630e5b75505Sopenharmony_ci msg->wps_attributes = NULL; 631e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 632e5b75505Sopenharmony_ci wpabuf_free(msg->wfd_subelems); 633e5b75505Sopenharmony_ci msg->wfd_subelems = NULL; 634e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 635e5b75505Sopenharmony_ci} 636e5b75505Sopenharmony_ci 637e5b75505Sopenharmony_ci 638e5b75505Sopenharmony_ciint p2p_group_info_parse(const u8 *gi, size_t gi_len, 639e5b75505Sopenharmony_ci struct p2p_group_info *info) 640e5b75505Sopenharmony_ci{ 641e5b75505Sopenharmony_ci const u8 *g, *gend; 642e5b75505Sopenharmony_ci 643e5b75505Sopenharmony_ci os_memset(info, 0, sizeof(*info)); 644e5b75505Sopenharmony_ci if (gi == NULL) 645e5b75505Sopenharmony_ci return 0; 646e5b75505Sopenharmony_ci 647e5b75505Sopenharmony_ci g = gi; 648e5b75505Sopenharmony_ci gend = gi + gi_len; 649e5b75505Sopenharmony_ci while (g < gend) { 650e5b75505Sopenharmony_ci struct p2p_client_info *cli; 651e5b75505Sopenharmony_ci const u8 *cend; 652e5b75505Sopenharmony_ci u16 count; 653e5b75505Sopenharmony_ci u8 len; 654e5b75505Sopenharmony_ci 655e5b75505Sopenharmony_ci cli = &info->client[info->num_clients]; 656e5b75505Sopenharmony_ci len = *g++; 657e5b75505Sopenharmony_ci if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1) 658e5b75505Sopenharmony_ci return -1; /* invalid data */ 659e5b75505Sopenharmony_ci cend = g + len; 660e5b75505Sopenharmony_ci /* g at start of P2P Client Info Descriptor */ 661e5b75505Sopenharmony_ci cli->p2p_device_addr = g; 662e5b75505Sopenharmony_ci g += ETH_ALEN; 663e5b75505Sopenharmony_ci cli->p2p_interface_addr = g; 664e5b75505Sopenharmony_ci g += ETH_ALEN; 665e5b75505Sopenharmony_ci cli->dev_capab = *g++; 666e5b75505Sopenharmony_ci 667e5b75505Sopenharmony_ci cli->config_methods = WPA_GET_BE16(g); 668e5b75505Sopenharmony_ci g += 2; 669e5b75505Sopenharmony_ci cli->pri_dev_type = g; 670e5b75505Sopenharmony_ci g += 8; 671e5b75505Sopenharmony_ci 672e5b75505Sopenharmony_ci /* g at Number of Secondary Device Types */ 673e5b75505Sopenharmony_ci len = *g++; 674e5b75505Sopenharmony_ci if (8 * len > cend - g) 675e5b75505Sopenharmony_ci return -1; /* invalid data */ 676e5b75505Sopenharmony_ci cli->num_sec_dev_types = len; 677e5b75505Sopenharmony_ci cli->sec_dev_types = g; 678e5b75505Sopenharmony_ci g += 8 * len; 679e5b75505Sopenharmony_ci 680e5b75505Sopenharmony_ci /* g at Device Name in WPS TLV format */ 681e5b75505Sopenharmony_ci if (cend - g < 2 + 2) 682e5b75505Sopenharmony_ci return -1; /* invalid data */ 683e5b75505Sopenharmony_ci if (WPA_GET_BE16(g) != ATTR_DEV_NAME) 684e5b75505Sopenharmony_ci return -1; /* invalid Device Name TLV */ 685e5b75505Sopenharmony_ci g += 2; 686e5b75505Sopenharmony_ci count = WPA_GET_BE16(g); 687e5b75505Sopenharmony_ci g += 2; 688e5b75505Sopenharmony_ci if (count > cend - g) 689e5b75505Sopenharmony_ci return -1; /* invalid Device Name TLV */ 690e5b75505Sopenharmony_ci if (count >= WPS_DEV_NAME_MAX_LEN) 691e5b75505Sopenharmony_ci count = WPS_DEV_NAME_MAX_LEN; 692e5b75505Sopenharmony_ci cli->dev_name = (const char *) g; 693e5b75505Sopenharmony_ci cli->dev_name_len = count; 694e5b75505Sopenharmony_ci 695e5b75505Sopenharmony_ci g = cend; 696e5b75505Sopenharmony_ci 697e5b75505Sopenharmony_ci info->num_clients++; 698e5b75505Sopenharmony_ci if (info->num_clients == P2P_MAX_GROUP_ENTRIES) 699e5b75505Sopenharmony_ci return -1; 700e5b75505Sopenharmony_ci } 701e5b75505Sopenharmony_ci 702e5b75505Sopenharmony_ci return 0; 703e5b75505Sopenharmony_ci} 704e5b75505Sopenharmony_ci 705e5b75505Sopenharmony_ci 706e5b75505Sopenharmony_cistatic int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf, 707e5b75505Sopenharmony_ci char *end) 708e5b75505Sopenharmony_ci{ 709e5b75505Sopenharmony_ci char *pos = buf; 710e5b75505Sopenharmony_ci int ret; 711e5b75505Sopenharmony_ci struct p2p_group_info info; 712e5b75505Sopenharmony_ci unsigned int i; 713e5b75505Sopenharmony_ci 714e5b75505Sopenharmony_ci if (p2p_group_info_parse(gi, gi_len, &info) < 0) 715e5b75505Sopenharmony_ci return 0; 716e5b75505Sopenharmony_ci 717e5b75505Sopenharmony_ci for (i = 0; i < info.num_clients; i++) { 718e5b75505Sopenharmony_ci struct p2p_client_info *cli; 719e5b75505Sopenharmony_ci char name[WPS_DEV_NAME_MAX_LEN + 1]; 720e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 721e5b75505Sopenharmony_ci u8 s; 722e5b75505Sopenharmony_ci int count; 723e5b75505Sopenharmony_ci 724e5b75505Sopenharmony_ci cli = &info.client[i]; 725e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, "p2p_group_client: " 726e5b75505Sopenharmony_ci "dev=" MACSTR " iface=" MACSTR, 727e5b75505Sopenharmony_ci MAC2STR(cli->p2p_device_addr), 728e5b75505Sopenharmony_ci MAC2STR(cli->p2p_interface_addr)); 729e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 730e5b75505Sopenharmony_ci return pos - buf; 731e5b75505Sopenharmony_ci pos += ret; 732e5b75505Sopenharmony_ci 733e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 734e5b75505Sopenharmony_ci " dev_capab=0x%x config_methods=0x%x " 735e5b75505Sopenharmony_ci "dev_type=%s", 736e5b75505Sopenharmony_ci cli->dev_capab, cli->config_methods, 737e5b75505Sopenharmony_ci wps_dev_type_bin2str(cli->pri_dev_type, 738e5b75505Sopenharmony_ci devtype, 739e5b75505Sopenharmony_ci sizeof(devtype))); 740e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 741e5b75505Sopenharmony_ci return pos - buf; 742e5b75505Sopenharmony_ci pos += ret; 743e5b75505Sopenharmony_ci 744e5b75505Sopenharmony_ci for (s = 0; s < cli->num_sec_dev_types; s++) { 745e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, " dev_type=%s", 746e5b75505Sopenharmony_ci wps_dev_type_bin2str( 747e5b75505Sopenharmony_ci &cli->sec_dev_types[s * 8], 748e5b75505Sopenharmony_ci devtype, sizeof(devtype))); 749e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 750e5b75505Sopenharmony_ci return pos - buf; 751e5b75505Sopenharmony_ci pos += ret; 752e5b75505Sopenharmony_ci } 753e5b75505Sopenharmony_ci 754e5b75505Sopenharmony_ci os_memcpy(name, cli->dev_name, cli->dev_name_len); 755e5b75505Sopenharmony_ci name[cli->dev_name_len] = '\0'; 756e5b75505Sopenharmony_ci count = (int) cli->dev_name_len - 1; 757e5b75505Sopenharmony_ci while (count >= 0) { 758e5b75505Sopenharmony_ci if (is_ctrl_char(name[count])) 759e5b75505Sopenharmony_ci name[count] = '_'; 760e5b75505Sopenharmony_ci count--; 761e5b75505Sopenharmony_ci } 762e5b75505Sopenharmony_ci 763e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name); 764e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 765e5b75505Sopenharmony_ci return pos - buf; 766e5b75505Sopenharmony_ci pos += ret; 767e5b75505Sopenharmony_ci } 768e5b75505Sopenharmony_ci 769e5b75505Sopenharmony_ci return pos - buf; 770e5b75505Sopenharmony_ci} 771e5b75505Sopenharmony_ci 772e5b75505Sopenharmony_ci 773e5b75505Sopenharmony_ci/** 774e5b75505Sopenharmony_ci * p2p_attr_text - Build text format description of P2P IE attributes 775e5b75505Sopenharmony_ci * @data: P2P IE contents 776e5b75505Sopenharmony_ci * @buf: Buffer for returning text 777e5b75505Sopenharmony_ci * @end: Pointer to the end of the buf area 778e5b75505Sopenharmony_ci * Returns: Number of octets written to the buffer or -1 on faikure 779e5b75505Sopenharmony_ci * 780e5b75505Sopenharmony_ci * This function can be used to parse P2P IE contents into text format 781e5b75505Sopenharmony_ci * field=value lines. 782e5b75505Sopenharmony_ci */ 783e5b75505Sopenharmony_ciint p2p_attr_text(struct wpabuf *data, char *buf, char *end) 784e5b75505Sopenharmony_ci{ 785e5b75505Sopenharmony_ci struct p2p_message msg; 786e5b75505Sopenharmony_ci char *pos = buf; 787e5b75505Sopenharmony_ci int ret; 788e5b75505Sopenharmony_ci 789e5b75505Sopenharmony_ci os_memset(&msg, 0, sizeof(msg)); 790e5b75505Sopenharmony_ci if (p2p_parse_p2p_ie(data, &msg)) 791e5b75505Sopenharmony_ci return -1; 792e5b75505Sopenharmony_ci 793e5b75505Sopenharmony_ci if (msg.capability) { 794e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 795e5b75505Sopenharmony_ci "p2p_dev_capab=0x%x\n" 796e5b75505Sopenharmony_ci "p2p_group_capab=0x%x\n", 797e5b75505Sopenharmony_ci msg.capability[0], msg.capability[1]); 798e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 799e5b75505Sopenharmony_ci return pos - buf; 800e5b75505Sopenharmony_ci pos += ret; 801e5b75505Sopenharmony_ci } 802e5b75505Sopenharmony_ci 803e5b75505Sopenharmony_ci if (msg.pri_dev_type) { 804e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 805e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, 806e5b75505Sopenharmony_ci "p2p_primary_device_type=%s\n", 807e5b75505Sopenharmony_ci wps_dev_type_bin2str(msg.pri_dev_type, 808e5b75505Sopenharmony_ci devtype, 809e5b75505Sopenharmony_ci sizeof(devtype))); 810e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 811e5b75505Sopenharmony_ci return pos - buf; 812e5b75505Sopenharmony_ci pos += ret; 813e5b75505Sopenharmony_ci } 814e5b75505Sopenharmony_ci 815e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n", 816e5b75505Sopenharmony_ci msg.device_name); 817e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 818e5b75505Sopenharmony_ci return pos - buf; 819e5b75505Sopenharmony_ci pos += ret; 820e5b75505Sopenharmony_ci 821e5b75505Sopenharmony_ci if (msg.p2p_device_addr) { 822e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR 823e5b75505Sopenharmony_ci "\n", 824e5b75505Sopenharmony_ci MAC2STR(msg.p2p_device_addr)); 825e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 826e5b75505Sopenharmony_ci return pos - buf; 827e5b75505Sopenharmony_ci pos += ret; 828e5b75505Sopenharmony_ci } 829e5b75505Sopenharmony_ci 830e5b75505Sopenharmony_ci ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n", 831e5b75505Sopenharmony_ci msg.config_methods); 832e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, ret)) 833e5b75505Sopenharmony_ci return pos - buf; 834e5b75505Sopenharmony_ci pos += ret; 835e5b75505Sopenharmony_ci 836e5b75505Sopenharmony_ci ret = p2p_group_info_text(msg.group_info, msg.group_info_len, 837e5b75505Sopenharmony_ci pos, end); 838e5b75505Sopenharmony_ci if (ret < 0) 839e5b75505Sopenharmony_ci return pos - buf; 840e5b75505Sopenharmony_ci pos += ret; 841e5b75505Sopenharmony_ci 842e5b75505Sopenharmony_ci return pos - buf; 843e5b75505Sopenharmony_ci} 844e5b75505Sopenharmony_ci 845e5b75505Sopenharmony_ci 846e5b75505Sopenharmony_ciint p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie) 847e5b75505Sopenharmony_ci{ 848e5b75505Sopenharmony_ci struct p2p_message msg; 849e5b75505Sopenharmony_ci 850e5b75505Sopenharmony_ci os_memset(&msg, 0, sizeof(msg)); 851e5b75505Sopenharmony_ci if (p2p_parse_p2p_ie(p2p_ie, &msg)) 852e5b75505Sopenharmony_ci return 0; 853e5b75505Sopenharmony_ci 854e5b75505Sopenharmony_ci if (!msg.manageability) 855e5b75505Sopenharmony_ci return 0; 856e5b75505Sopenharmony_ci 857e5b75505Sopenharmony_ci return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED); 858e5b75505Sopenharmony_ci} 859e5b75505Sopenharmony_ci 860e5b75505Sopenharmony_ci 861e5b75505Sopenharmony_ciu8 p2p_get_group_capab(const struct wpabuf *p2p_ie) 862e5b75505Sopenharmony_ci{ 863e5b75505Sopenharmony_ci struct p2p_message msg; 864e5b75505Sopenharmony_ci 865e5b75505Sopenharmony_ci os_memset(&msg, 0, sizeof(msg)); 866e5b75505Sopenharmony_ci if (p2p_parse_p2p_ie(p2p_ie, &msg)) 867e5b75505Sopenharmony_ci return 0; 868e5b75505Sopenharmony_ci 869e5b75505Sopenharmony_ci if (!msg.capability) 870e5b75505Sopenharmony_ci return 0; 871e5b75505Sopenharmony_ci 872e5b75505Sopenharmony_ci return msg.capability[1]; 873e5b75505Sopenharmony_ci} 874e5b75505Sopenharmony_ci 875e5b75505Sopenharmony_ci 876e5b75505Sopenharmony_ciconst u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie) 877e5b75505Sopenharmony_ci{ 878e5b75505Sopenharmony_ci struct p2p_message msg; 879e5b75505Sopenharmony_ci 880e5b75505Sopenharmony_ci os_memset(&msg, 0, sizeof(msg)); 881e5b75505Sopenharmony_ci if (p2p_parse_p2p_ie(p2p_ie, &msg)) 882e5b75505Sopenharmony_ci return NULL; 883e5b75505Sopenharmony_ci 884e5b75505Sopenharmony_ci if (msg.p2p_device_addr) 885e5b75505Sopenharmony_ci return msg.p2p_device_addr; 886e5b75505Sopenharmony_ci if (msg.device_id) 887e5b75505Sopenharmony_ci return msg.device_id; 888e5b75505Sopenharmony_ci 889e5b75505Sopenharmony_ci return NULL; 890e5b75505Sopenharmony_ci} 891