1252190Srpaulo/* 2252190Srpaulo * P2P - IE builder 3252190Srpaulo * Copyright (c) 2009-2010, Atheros Communications 4252190Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7252190Srpaulo */ 8252190Srpaulo 9252190Srpaulo#include "includes.h" 10252190Srpaulo 11252190Srpaulo#include "common.h" 12252190Srpaulo#include "common/ieee802_11_defs.h" 13252190Srpaulo#include "wps/wps_i.h" 14252190Srpaulo#include "p2p_i.h" 15252190Srpaulo 16252190Srpaulo 17252190Srpaulovoid p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token) 18252190Srpaulo{ 19252190Srpaulo wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC); 20252190Srpaulo wpabuf_put_be24(buf, OUI_WFA); 21252190Srpaulo wpabuf_put_u8(buf, P2P_OUI_TYPE); 22252190Srpaulo 23252190Srpaulo wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 24252190Srpaulo wpabuf_put_u8(buf, dialog_token); 25252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 26252190Srpaulo} 27252190Srpaulo 28252190Srpaulo 29252190Srpaulovoid p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, 30252190Srpaulo u8 dialog_token) 31252190Srpaulo{ 32252190Srpaulo wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); 33252190Srpaulo wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); 34252190Srpaulo wpabuf_put_be24(buf, OUI_WFA); 35252190Srpaulo wpabuf_put_u8(buf, P2P_OUI_TYPE); 36252190Srpaulo 37252190Srpaulo wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 38252190Srpaulo wpabuf_put_u8(buf, dialog_token); 39252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 40252190Srpaulo} 41252190Srpaulo 42252190Srpaulo 43252190Srpaulou8 * p2p_buf_add_ie_hdr(struct wpabuf *buf) 44252190Srpaulo{ 45252190Srpaulo u8 *len; 46252190Srpaulo 47252190Srpaulo /* P2P IE header */ 48252190Srpaulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 49252190Srpaulo len = wpabuf_put(buf, 1); /* IE length to be filled */ 50252190Srpaulo wpabuf_put_be24(buf, OUI_WFA); 51252190Srpaulo wpabuf_put_u8(buf, P2P_OUI_TYPE); 52252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * P2P IE header"); 53252190Srpaulo return len; 54252190Srpaulo} 55252190Srpaulo 56252190Srpaulo 57252190Srpaulovoid p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) 58252190Srpaulo{ 59252190Srpaulo /* Update P2P IE Length */ 60252190Srpaulo *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 61252190Srpaulo} 62252190Srpaulo 63252190Srpaulo 64252190Srpaulovoid p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) 65252190Srpaulo{ 66252190Srpaulo /* P2P Capability */ 67252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY); 68252190Srpaulo wpabuf_put_le16(buf, 2); 69252190Srpaulo wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */ 70252190Srpaulo wpabuf_put_u8(buf, group_capab); /* Group Capabilities */ 71252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x", 72252190Srpaulo dev_capab, group_capab); 73252190Srpaulo} 74252190Srpaulo 75252190Srpaulo 76252190Srpaulovoid p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent) 77252190Srpaulo{ 78252190Srpaulo /* Group Owner Intent */ 79252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT); 80252190Srpaulo wpabuf_put_le16(buf, 1); 81252190Srpaulo wpabuf_put_u8(buf, go_intent); 82252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u", 83252190Srpaulo go_intent >> 1, go_intent & 0x01); 84252190Srpaulo} 85252190Srpaulo 86252190Srpaulo 87252190Srpaulovoid p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, 88252190Srpaulo u8 reg_class, u8 channel) 89252190Srpaulo{ 90252190Srpaulo /* Listen Channel */ 91252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL); 92252190Srpaulo wpabuf_put_le16(buf, 5); 93252190Srpaulo wpabuf_put_data(buf, country, 3); 94252190Srpaulo wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 95252190Srpaulo wpabuf_put_u8(buf, channel); /* Channel Number */ 96252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u " 97252190Srpaulo "Channel %u", reg_class, channel); 98252190Srpaulo} 99252190Srpaulo 100252190Srpaulo 101252190Srpaulovoid p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, 102252190Srpaulo u8 reg_class, u8 channel) 103252190Srpaulo{ 104252190Srpaulo /* Operating Channel */ 105252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL); 106252190Srpaulo wpabuf_put_le16(buf, 5); 107252190Srpaulo wpabuf_put_data(buf, country, 3); 108252190Srpaulo wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 109252190Srpaulo wpabuf_put_u8(buf, channel); /* Channel Number */ 110252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u " 111252190Srpaulo "Channel %u", reg_class, channel); 112252190Srpaulo} 113252190Srpaulo 114252190Srpaulo 115252190Srpaulovoid p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, 116252190Srpaulo struct p2p_channels *chan) 117252190Srpaulo{ 118252190Srpaulo u8 *len; 119252190Srpaulo size_t i; 120252190Srpaulo 121252190Srpaulo /* Channel List */ 122252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); 123252190Srpaulo len = wpabuf_put(buf, 2); /* IE length to be filled */ 124252190Srpaulo wpabuf_put_data(buf, country, 3); /* Country String */ 125252190Srpaulo 126252190Srpaulo for (i = 0; i < chan->reg_classes; i++) { 127252190Srpaulo struct p2p_reg_class *c = &chan->reg_class[i]; 128252190Srpaulo wpabuf_put_u8(buf, c->reg_class); 129252190Srpaulo wpabuf_put_u8(buf, c->channels); 130252190Srpaulo wpabuf_put_data(buf, c->channel, c->channels); 131252190Srpaulo } 132252190Srpaulo 133252190Srpaulo /* Update attribute length */ 134252190Srpaulo WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 135252190Srpaulo wpa_hexdump(MSG_DEBUG, "P2P: * Channel List", 136252190Srpaulo len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2); 137252190Srpaulo} 138252190Srpaulo 139252190Srpaulo 140252190Srpaulovoid p2p_buf_add_status(struct wpabuf *buf, u8 status) 141252190Srpaulo{ 142252190Srpaulo /* Status */ 143252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_STATUS); 144252190Srpaulo wpabuf_put_le16(buf, 1); 145252190Srpaulo wpabuf_put_u8(buf, status); 146252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status); 147252190Srpaulo} 148252190Srpaulo 149252190Srpaulo 150252190Srpaulovoid p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, 151252190Srpaulo struct p2p_device *peer) 152252190Srpaulo{ 153252190Srpaulo u8 *len; 154252190Srpaulo u16 methods; 155252190Srpaulo size_t nlen, i; 156252190Srpaulo 157252190Srpaulo /* P2P Device Info */ 158252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); 159252190Srpaulo len = wpabuf_put(buf, 2); /* IE length to be filled */ 160252190Srpaulo 161252190Srpaulo /* P2P Device address */ 162252190Srpaulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 163252190Srpaulo 164252190Srpaulo /* Config Methods */ 165252190Srpaulo methods = 0; 166252190Srpaulo if (peer && peer->wps_method != WPS_NOT_READY) { 167252190Srpaulo if (peer->wps_method == WPS_PBC) 168252190Srpaulo methods |= WPS_CONFIG_PUSHBUTTON; 169252190Srpaulo else if (peer->wps_method == WPS_PIN_DISPLAY || 170252190Srpaulo peer->wps_method == WPS_PIN_KEYPAD) 171252190Srpaulo methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 172252190Srpaulo } else if (p2p->cfg->config_methods) { 173252190Srpaulo methods |= p2p->cfg->config_methods & 174252190Srpaulo (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY | 175252190Srpaulo WPS_CONFIG_KEYPAD); 176252190Srpaulo } else { 177252190Srpaulo methods |= WPS_CONFIG_PUSHBUTTON; 178252190Srpaulo methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 179252190Srpaulo } 180252190Srpaulo wpabuf_put_be16(buf, methods); 181252190Srpaulo 182252190Srpaulo /* Primary Device Type */ 183252190Srpaulo wpabuf_put_data(buf, p2p->cfg->pri_dev_type, 184252190Srpaulo sizeof(p2p->cfg->pri_dev_type)); 185252190Srpaulo 186252190Srpaulo /* Number of Secondary Device Types */ 187252190Srpaulo wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); 188252190Srpaulo 189252190Srpaulo /* Secondary Device Type List */ 190252190Srpaulo for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) 191252190Srpaulo wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], 192252190Srpaulo WPS_DEV_TYPE_LEN); 193252190Srpaulo 194252190Srpaulo /* Device Name */ 195252190Srpaulo nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; 196252190Srpaulo wpabuf_put_be16(buf, ATTR_DEV_NAME); 197252190Srpaulo wpabuf_put_be16(buf, nlen); 198252190Srpaulo wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); 199252190Srpaulo 200252190Srpaulo /* Update attribute length */ 201252190Srpaulo WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 202252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Device Info"); 203252190Srpaulo} 204252190Srpaulo 205252190Srpaulo 206252190Srpaulovoid p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr) 207252190Srpaulo{ 208252190Srpaulo /* P2P Device ID */ 209252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID); 210252190Srpaulo wpabuf_put_le16(buf, ETH_ALEN); 211252190Srpaulo wpabuf_put_data(buf, dev_addr, ETH_ALEN); 212252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr)); 213252190Srpaulo} 214252190Srpaulo 215252190Srpaulo 216252190Srpaulovoid p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, 217252190Srpaulo u8 client_timeout) 218252190Srpaulo{ 219252190Srpaulo /* Configuration Timeout */ 220252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT); 221252190Srpaulo wpabuf_put_le16(buf, 2); 222252190Srpaulo wpabuf_put_u8(buf, go_timeout); 223252190Srpaulo wpabuf_put_u8(buf, client_timeout); 224252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) " 225252190Srpaulo "client %d (*10ms)", go_timeout, client_timeout); 226252190Srpaulo} 227252190Srpaulo 228252190Srpaulo 229252190Srpaulovoid p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr) 230252190Srpaulo{ 231252190Srpaulo /* Intended P2P Interface Address */ 232252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR); 233252190Srpaulo wpabuf_put_le16(buf, ETH_ALEN); 234252190Srpaulo wpabuf_put_data(buf, interface_addr, ETH_ALEN); 235252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR, 236252190Srpaulo MAC2STR(interface_addr)); 237252190Srpaulo} 238252190Srpaulo 239252190Srpaulo 240252190Srpaulovoid p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid) 241252190Srpaulo{ 242252190Srpaulo /* P2P Group BSSID */ 243252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID); 244252190Srpaulo wpabuf_put_le16(buf, ETH_ALEN); 245252190Srpaulo wpabuf_put_data(buf, bssid, ETH_ALEN); 246252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR, 247252190Srpaulo MAC2STR(bssid)); 248252190Srpaulo} 249252190Srpaulo 250252190Srpaulo 251252190Srpaulovoid p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, 252252190Srpaulo const u8 *ssid, size_t ssid_len) 253252190Srpaulo{ 254252190Srpaulo /* P2P Group ID */ 255252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID); 256252190Srpaulo wpabuf_put_le16(buf, ETH_ALEN + ssid_len); 257252190Srpaulo wpabuf_put_data(buf, dev_addr, ETH_ALEN); 258252190Srpaulo wpabuf_put_data(buf, ssid, ssid_len); 259252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, 260252190Srpaulo MAC2STR(dev_addr)); 261252190Srpaulo} 262252190Srpaulo 263252190Srpaulo 264252190Srpaulovoid p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags) 265252190Srpaulo{ 266252190Srpaulo /* Invitation Flags */ 267252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS); 268252190Srpaulo wpabuf_put_le16(buf, 1); 269252190Srpaulo wpabuf_put_u8(buf, flags); 270252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags); 271252190Srpaulo} 272252190Srpaulo 273252190Srpaulo 274252190Srpaulostatic void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc) 275252190Srpaulo{ 276252190Srpaulo if (desc == NULL) 277252190Srpaulo return; 278252190Srpaulo 279252190Srpaulo wpabuf_put_u8(buf, desc->count_type); 280252190Srpaulo wpabuf_put_le32(buf, desc->duration); 281252190Srpaulo wpabuf_put_le32(buf, desc->interval); 282252190Srpaulo wpabuf_put_le32(buf, desc->start_time); 283252190Srpaulo} 284252190Srpaulo 285252190Srpaulo 286252190Srpaulovoid p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, 287252190Srpaulo struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2) 288252190Srpaulo{ 289252190Srpaulo /* Notice of Absence */ 290252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE); 291252190Srpaulo wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0)); 292252190Srpaulo wpabuf_put_u8(buf, noa_index); 293252190Srpaulo wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f)); 294252190Srpaulo p2p_buf_add_noa_desc(buf, desc1); 295252190Srpaulo p2p_buf_add_noa_desc(buf, desc2); 296252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); 297252190Srpaulo} 298252190Srpaulo 299252190Srpaulo 300252190Srpaulovoid p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, 301252190Srpaulo u16 interval) 302252190Srpaulo{ 303252190Srpaulo /* Extended Listen Timing */ 304252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING); 305252190Srpaulo wpabuf_put_le16(buf, 4); 306252190Srpaulo wpabuf_put_le16(buf, period); 307252190Srpaulo wpabuf_put_le16(buf, interval); 308252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec " 309252190Srpaulo "interval %u msec)", period, interval); 310252190Srpaulo} 311252190Srpaulo 312252190Srpaulo 313252190Srpaulovoid p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p) 314252190Srpaulo{ 315252190Srpaulo /* P2P Interface */ 316252190Srpaulo wpabuf_put_u8(buf, P2P_ATTR_INTERFACE); 317252190Srpaulo wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN); 318252190Srpaulo /* P2P Device address */ 319252190Srpaulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 320252190Srpaulo /* 321252190Srpaulo * FIX: Fetch interface address list from driver. Do not include 322252190Srpaulo * the P2P Device address if it is never used as interface address. 323252190Srpaulo */ 324252190Srpaulo /* P2P Interface Address Count */ 325252190Srpaulo wpabuf_put_u8(buf, 1); 326252190Srpaulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 327252190Srpaulo} 328252190Srpaulo 329252190Srpaulo 330252190Srpaulostatic void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, 331252190Srpaulo const char *val) 332252190Srpaulo{ 333252190Srpaulo size_t len; 334252190Srpaulo 335252190Srpaulo wpabuf_put_be16(buf, attr); 336252190Srpaulo len = val ? os_strlen(val) : 0; 337252190Srpaulo#ifndef CONFIG_WPS_STRICT 338252190Srpaulo if (len == 0) { 339252190Srpaulo /* 340252190Srpaulo * Some deployed WPS implementations fail to parse zeor-length 341252190Srpaulo * attributes. As a workaround, send a space character if the 342252190Srpaulo * device attribute string is empty. 343252190Srpaulo */ 344252190Srpaulo wpabuf_put_be16(buf, 1); 345252190Srpaulo wpabuf_put_u8(buf, ' '); 346252190Srpaulo return; 347252190Srpaulo } 348252190Srpaulo#endif /* CONFIG_WPS_STRICT */ 349252190Srpaulo wpabuf_put_be16(buf, len); 350252190Srpaulo if (val) 351252190Srpaulo wpabuf_put_data(buf, val, len); 352252190Srpaulo} 353252190Srpaulo 354252190Srpaulo 355252190Srpaulovoid p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, 356252190Srpaulo int all_attr) 357252190Srpaulo{ 358252190Srpaulo u8 *len; 359252190Srpaulo int i; 360252190Srpaulo 361252190Srpaulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 362252190Srpaulo len = wpabuf_put(buf, 1); 363252190Srpaulo wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); 364252190Srpaulo 365252190Srpaulo wps_build_version(buf); 366252190Srpaulo 367252190Srpaulo if (all_attr) { 368252190Srpaulo wpabuf_put_be16(buf, ATTR_WPS_STATE); 369252190Srpaulo wpabuf_put_be16(buf, 1); 370252190Srpaulo wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED); 371252190Srpaulo } 372252190Srpaulo 373252190Srpaulo if (pw_id >= 0) { 374252190Srpaulo /* Device Password ID */ 375252190Srpaulo wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID); 376252190Srpaulo wpabuf_put_be16(buf, 2); 377252190Srpaulo wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", 378252190Srpaulo pw_id); 379252190Srpaulo wpabuf_put_be16(buf, pw_id); 380252190Srpaulo } 381252190Srpaulo 382252190Srpaulo if (all_attr) { 383252190Srpaulo wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE); 384252190Srpaulo wpabuf_put_be16(buf, 1); 385252190Srpaulo wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO); 386252190Srpaulo 387252190Srpaulo wps_build_uuid_e(buf, p2p->cfg->uuid); 388252190Srpaulo p2p_add_wps_string(buf, ATTR_MANUFACTURER, 389252190Srpaulo p2p->cfg->manufacturer); 390252190Srpaulo p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name); 391252190Srpaulo p2p_add_wps_string(buf, ATTR_MODEL_NUMBER, 392252190Srpaulo p2p->cfg->model_number); 393252190Srpaulo p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER, 394252190Srpaulo p2p->cfg->serial_number); 395252190Srpaulo 396252190Srpaulo wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE); 397252190Srpaulo wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN); 398252190Srpaulo wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN); 399252190Srpaulo 400252190Srpaulo p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name); 401252190Srpaulo 402252190Srpaulo wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); 403252190Srpaulo wpabuf_put_be16(buf, 2); 404252190Srpaulo wpabuf_put_be16(buf, p2p->cfg->config_methods); 405252190Srpaulo } 406252190Srpaulo 407252190Srpaulo wps_build_wfa_ext(buf, 0, NULL, 0); 408252190Srpaulo 409252190Srpaulo if (all_attr && p2p->cfg->num_sec_dev_types) { 410252190Srpaulo wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST); 411252190Srpaulo wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN * 412252190Srpaulo p2p->cfg->num_sec_dev_types); 413252190Srpaulo wpabuf_put_data(buf, p2p->cfg->sec_dev_type, 414252190Srpaulo WPS_DEV_TYPE_LEN * 415252190Srpaulo p2p->cfg->num_sec_dev_types); 416252190Srpaulo } 417252190Srpaulo 418252190Srpaulo /* Add the WPS vendor extensions */ 419252190Srpaulo for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 420252190Srpaulo if (p2p->wps_vendor_ext[i] == NULL) 421252190Srpaulo break; 422252190Srpaulo if (wpabuf_tailroom(buf) < 423252190Srpaulo 4 + wpabuf_len(p2p->wps_vendor_ext[i])) 424252190Srpaulo continue; 425252190Srpaulo wpabuf_put_be16(buf, ATTR_VENDOR_EXT); 426252190Srpaulo wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i])); 427252190Srpaulo wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]); 428252190Srpaulo } 429252190Srpaulo 430252190Srpaulo p2p_buf_update_ie_hdr(buf, len); 431252190Srpaulo} 432