p2p_build.c revision 289549
133965Sjdp/* 238889Sjdp * P2P - IE builder 338889Sjdp * Copyright (c) 2009-2010, Atheros Communications 433965Sjdp * 533965Sjdp * This software may be distributed under the terms of the BSD license. 633965Sjdp * See README for more details. 733965Sjdp */ 833965Sjdp 933965Sjdp#include "includes.h" 1033965Sjdp 1133965Sjdp#include "common.h" 1233965Sjdp#include "common/ieee802_11_defs.h" 1333965Sjdp#include "common/qca-vendor.h" 1433965Sjdp#include "wps/wps_i.h" 1533965Sjdp#include "p2p_i.h" 1633965Sjdp 1733965Sjdp 1833965Sjdpvoid p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token) 1933965Sjdp{ 2033965Sjdp wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC); 2133965Sjdp wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 2233965Sjdp 2333965Sjdp wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 2433965Sjdp wpabuf_put_u8(buf, dialog_token); 2533965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 2633965Sjdp} 2733965Sjdp 2833965Sjdp 2933965Sjdpvoid p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, 3033965Sjdp u8 dialog_token) 3133965Sjdp{ 3233965Sjdp wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); 3333965Sjdp wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); 3433965Sjdp wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 3533965Sjdp 3633965Sjdp wpabuf_put_u8(buf, subtype); /* OUI Subtype */ 3733965Sjdp wpabuf_put_u8(buf, dialog_token); 3833965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); 3933965Sjdp} 4033965Sjdp 4133965Sjdp 4233965Sjdpu8 * p2p_buf_add_ie_hdr(struct wpabuf *buf) 4333965Sjdp{ 4433965Sjdp u8 *len; 4533965Sjdp 4633965Sjdp /* P2P IE header */ 4733965Sjdp wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 4833965Sjdp len = wpabuf_put(buf, 1); /* IE length to be filled */ 4933965Sjdp wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 5033965Sjdp wpa_printf(MSG_DEBUG, "P2P: * P2P IE header"); 5133965Sjdp return len; 5238889Sjdp} 5333965Sjdp 5433965Sjdp 5533965Sjdpvoid p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) 5633965Sjdp{ 5733965Sjdp /* Update P2P IE Length */ 5833965Sjdp *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 5960484Sobrien} 6033965Sjdp 6133965Sjdp 6233965Sjdpvoid p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) 6333965Sjdp{ 6433965Sjdp /* P2P Capability */ 6533965Sjdp wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY); 6633965Sjdp wpabuf_put_le16(buf, 2); 6733965Sjdp wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */ 6833965Sjdp wpabuf_put_u8(buf, group_capab); /* Group Capabilities */ 6933965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x", 7033965Sjdp dev_capab, group_capab); 7133965Sjdp} 7238889Sjdp 7338889Sjdp 7438889Sjdpvoid p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent) 7538889Sjdp{ 7638889Sjdp /* Group Owner Intent */ 7733965Sjdp wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT); 7833965Sjdp wpabuf_put_le16(buf, 1); 7933965Sjdp wpabuf_put_u8(buf, go_intent); 8033965Sjdp wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u", 8138889Sjdp go_intent >> 1, go_intent & 0x01); 8238889Sjdp} 8338889Sjdp 8438889Sjdp 8538889Sjdpvoid p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, 8638889Sjdp u8 reg_class, u8 channel) 8738889Sjdp{ 8833965Sjdp /* Listen Channel */ 8933965Sjdp wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL); 9038889Sjdp wpabuf_put_le16(buf, 5); 9138889Sjdp wpabuf_put_data(buf, country, 3); 9238889Sjdp wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 9338889Sjdp wpabuf_put_u8(buf, channel); /* Channel Number */ 9438889Sjdp wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u " 9538889Sjdp "Channel %u", reg_class, channel); 9638889Sjdp} 9738889Sjdp 9838889Sjdp 9938889Sjdpvoid p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, 10038889Sjdp u8 reg_class, u8 channel) 10138889Sjdp{ 10238889Sjdp /* Operating Channel */ 10338889Sjdp wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL); 10438889Sjdp wpabuf_put_le16(buf, 5); 10533965Sjdp wpabuf_put_data(buf, country, 3); 10633965Sjdp wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ 10733965Sjdp wpabuf_put_u8(buf, channel); /* Channel Number */ 10833965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u " 10933965Sjdp "Channel %u", reg_class, channel); 11033965Sjdp} 11133965Sjdp 11233965Sjdp 11333965Sjdpvoid p2p_buf_add_pref_channel_list(struct wpabuf *buf, 11438889Sjdp const u32 *preferred_freq_list, 11538889Sjdp unsigned int size) 11638889Sjdp{ 11738889Sjdp unsigned int i, count = 0; 11838889Sjdp u8 op_class, op_channel; 11938889Sjdp 12038889Sjdp if (!size) 12138889Sjdp return; 12233965Sjdp 12333965Sjdp /* 12433965Sjdp * First, determine the number of P2P supported channels in the 12533965Sjdp * pref_freq_list returned from driver. This is needed for calculations 12633965Sjdp * of the vendor IE size. 12733965Sjdp */ 12833965Sjdp for (i = 0; i < size; i++) { 12933965Sjdp if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, 13033965Sjdp &op_channel) == 0) 13133965Sjdp count++; 13233965Sjdp } 13333965Sjdp 13433965Sjdp wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 13533965Sjdp wpabuf_put_u8(buf, 4 + count * sizeof(u16)); 13633965Sjdp wpabuf_put_be24(buf, OUI_QCA); 13733965Sjdp wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST); 13833965Sjdp for (i = 0; i < size; i++) { 13933965Sjdp if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, 14033965Sjdp &op_channel) < 0) { 14133965Sjdp wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz", 14238889Sjdp preferred_freq_list[i]); 14338889Sjdp continue; 14438889Sjdp } 14538889Sjdp wpabuf_put_u8(buf, op_class); 14638889Sjdp wpabuf_put_u8(buf, op_channel); 14738889Sjdp } 14838889Sjdp} 14938889Sjdp 15038889Sjdp 15138889Sjdpvoid p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, 15238889Sjdp struct p2p_channels *chan) 15338889Sjdp{ 15438889Sjdp u8 *len; 15538889Sjdp size_t i; 15638889Sjdp 15738889Sjdp /* Channel List */ 15838889Sjdp wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); 15938889Sjdp len = wpabuf_put(buf, 2); /* IE length to be filled */ 16038889Sjdp wpabuf_put_data(buf, country, 3); /* Country String */ 16138889Sjdp 16233965Sjdp for (i = 0; i < chan->reg_classes; i++) { 16333965Sjdp struct p2p_reg_class *c = &chan->reg_class[i]; 16433965Sjdp wpabuf_put_u8(buf, c->reg_class); 16533965Sjdp wpabuf_put_u8(buf, c->channels); 16633965Sjdp wpabuf_put_data(buf, c->channel, c->channels); 16733965Sjdp } 16833965Sjdp 16933965Sjdp /* Update attribute length */ 17033965Sjdp WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 17133965Sjdp wpa_hexdump(MSG_DEBUG, "P2P: * Channel List", 17233965Sjdp len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2); 17333965Sjdp} 17433965Sjdp 17533965Sjdp 17633965Sjdpvoid p2p_buf_add_status(struct wpabuf *buf, u8 status) 17733965Sjdp{ 17833965Sjdp /* Status */ 17933965Sjdp wpabuf_put_u8(buf, P2P_ATTR_STATUS); 18033965Sjdp wpabuf_put_le16(buf, 1); 18133965Sjdp wpabuf_put_u8(buf, status); 18233965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status); 18333965Sjdp} 18433965Sjdp 18533965Sjdp 18633965Sjdpvoid p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, 18733965Sjdp struct p2p_device *peer) 18833965Sjdp{ 18933965Sjdp u8 *len; 19033965Sjdp u16 methods; 19133965Sjdp size_t nlen, i; 19233965Sjdp 19333965Sjdp /* P2P Device Info */ 19433965Sjdp wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); 19560484Sobrien len = wpabuf_put(buf, 2); /* IE length to be filled */ 19633965Sjdp 19733965Sjdp /* P2P Device address */ 19833965Sjdp wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 19933965Sjdp 20033965Sjdp /* Config Methods */ 20133965Sjdp methods = 0; 20233965Sjdp if (peer && peer->wps_method != WPS_NOT_READY) { 20333965Sjdp if (peer->wps_method == WPS_PBC) 20433965Sjdp methods |= WPS_CONFIG_PUSHBUTTON; 20533965Sjdp else if (peer->wps_method == WPS_PIN_DISPLAY || 20633965Sjdp peer->wps_method == WPS_PIN_KEYPAD) { 20733965Sjdp methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 20833965Sjdp methods |= WPS_CONFIG_P2PS; 20933965Sjdp } 21033965Sjdp } else if (p2p->cfg->config_methods) { 21133965Sjdp methods |= p2p->cfg->config_methods & 21233965Sjdp (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY | 21333965Sjdp WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS); 21433965Sjdp } else { 21533965Sjdp methods |= WPS_CONFIG_PUSHBUTTON; 21633965Sjdp methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 21733965Sjdp methods |= WPS_CONFIG_P2PS; 21833965Sjdp } 21933965Sjdp wpabuf_put_be16(buf, methods); 22033965Sjdp 22133965Sjdp /* Primary Device Type */ 22233965Sjdp wpabuf_put_data(buf, p2p->cfg->pri_dev_type, 22333965Sjdp sizeof(p2p->cfg->pri_dev_type)); 22433965Sjdp 22533965Sjdp /* Number of Secondary Device Types */ 22633965Sjdp wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); 22733965Sjdp 22833965Sjdp /* Secondary Device Type List */ 22933965Sjdp for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) 23033965Sjdp wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], 23133965Sjdp WPS_DEV_TYPE_LEN); 23233965Sjdp 23333965Sjdp /* Device Name */ 23433965Sjdp nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; 23533965Sjdp wpabuf_put_be16(buf, ATTR_DEV_NAME); 23633965Sjdp wpabuf_put_be16(buf, nlen); 23733965Sjdp wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); 23833965Sjdp 23933965Sjdp /* Update attribute length */ 24033965Sjdp WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); 24133965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Device Info"); 24233965Sjdp} 24333965Sjdp 24433965Sjdp 24533965Sjdpvoid p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr) 24633965Sjdp{ 24733965Sjdp /* P2P Device ID */ 24833965Sjdp wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID); 24933965Sjdp wpabuf_put_le16(buf, ETH_ALEN); 25033965Sjdp wpabuf_put_data(buf, dev_addr, ETH_ALEN); 25133965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr)); 25233965Sjdp} 25333965Sjdp 25433965Sjdp 25533965Sjdpvoid p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, 25633965Sjdp u8 client_timeout) 25733965Sjdp{ 25833965Sjdp /* Configuration Timeout */ 25933965Sjdp wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT); 26033965Sjdp wpabuf_put_le16(buf, 2); 26133965Sjdp wpabuf_put_u8(buf, go_timeout); 26233965Sjdp wpabuf_put_u8(buf, client_timeout); 26333965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) " 26433965Sjdp "client %d (*10ms)", go_timeout, client_timeout); 26533965Sjdp} 26633965Sjdp 26733965Sjdp 26833965Sjdpvoid p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr) 26933965Sjdp{ 27033965Sjdp /* Intended P2P Interface Address */ 27133965Sjdp wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR); 27233965Sjdp wpabuf_put_le16(buf, ETH_ALEN); 27333965Sjdp wpabuf_put_data(buf, interface_addr, ETH_ALEN); 27433965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR, 27533965Sjdp MAC2STR(interface_addr)); 27633965Sjdp} 27733965Sjdp 27833965Sjdp 27933965Sjdpvoid p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid) 28033965Sjdp{ 28133965Sjdp /* P2P Group BSSID */ 28233965Sjdp wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID); 28333965Sjdp wpabuf_put_le16(buf, ETH_ALEN); 28433965Sjdp wpabuf_put_data(buf, bssid, ETH_ALEN); 28533965Sjdp wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR, 28633965Sjdp MAC2STR(bssid)); 28733965Sjdp} 28833965Sjdp 28933965Sjdp 29033965Sjdpvoid p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, 29133965Sjdp const u8 *ssid, size_t ssid_len) 29233965Sjdp{ 29333965Sjdp /* P2P Group ID */ 29433965Sjdp wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID); 29533965Sjdp wpabuf_put_le16(buf, ETH_ALEN + ssid_len); 29633965Sjdp wpabuf_put_data(buf, dev_addr, ETH_ALEN); 29733965Sjdp wpabuf_put_data(buf, ssid, ssid_len); 29833965Sjdp wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, 29933965Sjdp MAC2STR(dev_addr)); 30033965Sjdp wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len); 30133965Sjdp} 30233965Sjdp 30333965Sjdp 30433965Sjdpvoid p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags) 30533965Sjdp{ 30633965Sjdp /* Invitation Flags */ 30733965Sjdp wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS); 30833965Sjdp wpabuf_put_le16(buf, 1); 30933965Sjdp wpabuf_put_u8(buf, flags); 31033965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags); 31133965Sjdp} 31233965Sjdp 31333965Sjdp 31433965Sjdpstatic void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc) 31533965Sjdp{ 31633965Sjdp if (desc == NULL) 31733965Sjdp return; 31833965Sjdp 31933965Sjdp wpabuf_put_u8(buf, desc->count_type); 32033965Sjdp wpabuf_put_le32(buf, desc->duration); 32133965Sjdp wpabuf_put_le32(buf, desc->interval); 32233965Sjdp wpabuf_put_le32(buf, desc->start_time); 32333965Sjdp} 32433965Sjdp 32533965Sjdp 32633965Sjdpvoid p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, 32733965Sjdp struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2) 32833965Sjdp{ 32933965Sjdp /* Notice of Absence */ 33033965Sjdp wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE); 33133965Sjdp wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0)); 33233965Sjdp wpabuf_put_u8(buf, noa_index); 33333965Sjdp wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f)); 33433965Sjdp p2p_buf_add_noa_desc(buf, desc1); 33533965Sjdp p2p_buf_add_noa_desc(buf, desc2); 33633965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); 33733965Sjdp} 33833965Sjdp 33933965Sjdp 34033965Sjdpvoid p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, 34133965Sjdp u16 interval) 34233965Sjdp{ 34333965Sjdp /* Extended Listen Timing */ 34433965Sjdp wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING); 34533965Sjdp wpabuf_put_le16(buf, 4); 34633965Sjdp wpabuf_put_le16(buf, period); 34733965Sjdp wpabuf_put_le16(buf, interval); 34833965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec " 34933965Sjdp "interval %u msec)", period, interval); 35033965Sjdp} 35133965Sjdp 35233965Sjdp 35333965Sjdpvoid p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p) 35433965Sjdp{ 35533965Sjdp /* P2P Interface */ 35633965Sjdp wpabuf_put_u8(buf, P2P_ATTR_INTERFACE); 35733965Sjdp wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN); 35833965Sjdp /* P2P Device address */ 35933965Sjdp wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 36033965Sjdp /* 36133965Sjdp * FIX: Fetch interface address list from driver. Do not include 36233965Sjdp * the P2P Device address if it is never used as interface address. 36333965Sjdp */ 36433965Sjdp /* P2P Interface Address Count */ 36560484Sobrien wpabuf_put_u8(buf, 1); 36633965Sjdp wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); 36733965Sjdp} 36833965Sjdp 36933965Sjdp 37033965Sjdpvoid p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country, 37133965Sjdp u8 oper_class, u8 channel, 37233965Sjdp enum p2p_role_indication role) 37333965Sjdp{ 37433965Sjdp /* OOB Group Owner Negotiation Channel */ 37533965Sjdp wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL); 37633965Sjdp wpabuf_put_le16(buf, 6); 37733965Sjdp wpabuf_put_data(buf, country, 3); 37833965Sjdp wpabuf_put_u8(buf, oper_class); /* Operating Class */ 37933965Sjdp wpabuf_put_u8(buf, channel); /* Channel Number */ 38033965Sjdp wpabuf_put_u8(buf, (u8) role); /* Role indication */ 38133965Sjdp wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating " 38233965Sjdp "Class %u Channel %u Role %d", 38333965Sjdp oper_class, channel, role); 38433965Sjdp} 38533965Sjdp 38633965Sjdp 38733965Sjdpvoid p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p) 38833965Sjdp{ 38933965Sjdp if (!p2p) 39033965Sjdp return; 39133965Sjdp 39233965Sjdp /* Service Hash */ 39333965Sjdp wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH); 39433965Sjdp wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN); 39533965Sjdp wpabuf_put_data(buf, p2p->p2ps_seek_hash, 39633965Sjdp p2p->p2ps_seek_count * P2PS_HASH_LEN); 39733965Sjdp wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash", 39833965Sjdp p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN); 39933965Sjdp} 40033965Sjdp 40133965Sjdp 40233965Sjdpvoid p2p_buf_add_session_info(struct wpabuf *buf, const char *info) 40333965Sjdp{ 40433965Sjdp size_t info_len = 0; 40533965Sjdp 40633965Sjdp if (info && info[0]) 40733965Sjdp info_len = os_strlen(info); 40833965Sjdp 40933965Sjdp /* Session Information Data Info */ 41033965Sjdp wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA); 41133965Sjdp wpabuf_put_le16(buf, (u16) info_len); 41233965Sjdp 41333965Sjdp if (info) { 41433965Sjdp wpabuf_put_data(buf, info, info_len); 41533965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info); 41633965Sjdp } 41733965Sjdp} 41833965Sjdp 41933965Sjdp 42033965Sjdpvoid p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap) 42133965Sjdp{ 42233965Sjdp /* Connection Capability Info */ 42333965Sjdp wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY); 42433965Sjdp wpabuf_put_le16(buf, 1); 42533965Sjdp wpabuf_put_u8(buf, connection_cap); 42633965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x", 42733965Sjdp connection_cap); 42833965Sjdp} 42933965Sjdp 43033965Sjdp 43133965Sjdpvoid p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac) 43233965Sjdp{ 43333965Sjdp if (!buf || !mac) 43433965Sjdp return; 43533965Sjdp 43633965Sjdp /* Advertisement ID Info */ 43733965Sjdp wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID); 43833965Sjdp wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN)); 43933965Sjdp wpabuf_put_le32(buf, id); 44033965Sjdp wpabuf_put_data(buf, mac, ETH_ALEN); 44133965Sjdp wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR, 44233965Sjdp id, MAC2STR(mac)); 44333965Sjdp} 44433965Sjdp 44533965Sjdp 44633965Sjdpstatic int p2ps_wildcard_hash(struct p2p_data *p2p, 44733965Sjdp const u8 *hash, u8 hash_count) 44833965Sjdp{ 44933965Sjdp u8 i; 45033965Sjdp const u8 *test = hash; 45133965Sjdp 45233965Sjdp for (i = 0; i < hash_count; i++) { 45333965Sjdp if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0) 45433965Sjdp return 1; 45533965Sjdp test += P2PS_HASH_LEN; 45633965Sjdp } 45733965Sjdp 45833965Sjdp return 0; 45933965Sjdp} 46033965Sjdp 46133965Sjdp 46233965Sjdpstatic int p2p_wfa_service_adv(struct p2p_data *p2p) 46333965Sjdp{ 46433965Sjdp struct p2ps_advertisement *adv; 46533965Sjdp 46633965Sjdp for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) { 46733965Sjdp if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR, 46833965Sjdp os_strlen(P2PS_WILD_HASH_STR)) == 0) 46933965Sjdp return 1; 47033965Sjdp } 47133965Sjdp 47233965Sjdp return 0; 47333965Sjdp} 47433965Sjdp 47533965Sjdp 47633965Sjdpstatic int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p, 47733965Sjdp u32 adv_id, u16 config_methods, 47833965Sjdp const char *svc_name, u8 **ie_len, u8 **pos, 47933965Sjdp size_t *total_len, u8 *attr_len) 48033965Sjdp{ 48133965Sjdp size_t svc_len; 48233965Sjdp size_t remaining; 48333965Sjdp size_t info_len; 48433965Sjdp 48533965Sjdp p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id); 48633965Sjdp svc_len = os_strlen(svc_name); 48733965Sjdp info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) + 48833965Sjdp svc_len; 48933965Sjdp 49033965Sjdp if (info_len + *total_len > MAX_SVC_ADV_LEN) { 49133965Sjdp p2p_dbg(p2p, 49233965Sjdp "Unsufficient buffer, failed to add advertised service info"); 49333965Sjdp return -1; 49433965Sjdp } 49533965Sjdp 49633965Sjdp if (svc_len > 255) { 49733965Sjdp p2p_dbg(p2p, 49833965Sjdp "Invalid service name length (%u bytes), failed to add advertised service info", 49933965Sjdp (unsigned int) svc_len); 50033965Sjdp return -1; 50133965Sjdp } 50233965Sjdp 50333965Sjdp if (*ie_len) { 50433965Sjdp int ie_data_len = (*pos - *ie_len) - 1; 50533965Sjdp 50633965Sjdp if (ie_data_len < 0 || ie_data_len > 255) { 50733965Sjdp p2p_dbg(p2p, 50833965Sjdp "Invalid IE length, failed to add advertised service info"); 50933965Sjdp return -1; 51033965Sjdp } 51133965Sjdp remaining = 255 - ie_data_len; 51233965Sjdp } else { 51333965Sjdp /* 51433965Sjdp * Adding new P2P IE header takes 6 extra bytes: 51533965Sjdp * - 2 byte IE header (1 byte IE id and 1 byte length) 51633965Sjdp * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below 51733965Sjdp */ 51833965Sjdp *ie_len = p2p_buf_add_ie_hdr(buf); 51933965Sjdp remaining = 255 - 4; 52033965Sjdp } 52133965Sjdp 52233965Sjdp if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) { 52333965Sjdp /* 52433965Sjdp * Split adv_id, config_methods, and svc_name_len between two 52533965Sjdp * IEs. 52660484Sobrien */ 52733965Sjdp size_t front = remaining; 52833965Sjdp size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front; 52933965Sjdp u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)]; 53033965Sjdp 531 WPA_PUT_LE32(holder, adv_id); 532 WPA_PUT_BE16(&holder[sizeof(u32)], config_methods); 533 holder[sizeof(u32) + sizeof(u16)] = svc_len; 534 535 if (front) 536 wpabuf_put_data(buf, holder, front); 537 538 p2p_buf_update_ie_hdr(buf, *ie_len); 539 *ie_len = p2p_buf_add_ie_hdr(buf); 540 541 wpabuf_put_data(buf, &holder[front], back); 542 remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) - 543 back; 544 } else { 545 wpabuf_put_le32(buf, adv_id); 546 wpabuf_put_be16(buf, config_methods); 547 wpabuf_put_u8(buf, svc_len); 548 remaining -= sizeof(adv_id) + sizeof(config_methods) + 549 sizeof(u8); 550 } 551 552 if (remaining < svc_len) { 553 /* split svc_name between two or three IEs */ 554 size_t front = remaining; 555 size_t back = svc_len - front; 556 557 if (front) 558 wpabuf_put_data(buf, svc_name, front); 559 560 p2p_buf_update_ie_hdr(buf, *ie_len); 561 *ie_len = p2p_buf_add_ie_hdr(buf); 562 563 /* In rare cases, we must split across 3 attributes */ 564 if (back > 255 - 4) { 565 wpabuf_put_data(buf, &svc_name[front], 255 - 4); 566 back -= 255 - 4; 567 front += 255 - 4; 568 p2p_buf_update_ie_hdr(buf, *ie_len); 569 *ie_len = p2p_buf_add_ie_hdr(buf); 570 } 571 572 wpabuf_put_data(buf, &svc_name[front], back); 573 remaining = 255 - 4 - back; 574 } else { 575 wpabuf_put_data(buf, svc_name, svc_len); 576 remaining -= svc_len; 577 } 578 579 p2p_buf_update_ie_hdr(buf, *ie_len); 580 581 /* set *ie_len to NULL if a new IE has to be added on the next call */ 582 if (!remaining) 583 *ie_len = NULL; 584 585 /* set *pos to point to the next byte to update */ 586 *pos = wpabuf_put(buf, 0); 587 588 *total_len += info_len; 589 WPA_PUT_LE16(attr_len, (u16) *total_len); 590 return 0; 591} 592 593 594void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p, 595 u8 hash_count, const u8 *hash, 596 struct p2ps_advertisement *adv_list) 597{ 598 struct p2ps_advertisement *adv; 599 int p2ps_wildcard; 600 size_t total_len; 601 struct wpabuf *tmp_buf = NULL; 602 u8 *pos, *attr_len, *ie_len = NULL; 603 604 if (!adv_list || !hash || !hash_count) 605 return; 606 607 wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values", 608 hash, hash_count * P2PS_HASH_LEN); 609 p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) && 610 p2p_wfa_service_adv(p2p); 611 612 /* Allocate temp buffer, allowing for overflow of 1 instance */ 613 tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN); 614 if (!tmp_buf) 615 return; 616 617 /* 618 * Attribute data can be split into a number of IEs. Start with the 619 * first IE and the attribute headers here. 620 */ 621 ie_len = p2p_buf_add_ie_hdr(tmp_buf); 622 623 total_len = 0; 624 625 wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE); 626 attr_len = wpabuf_put(tmp_buf, sizeof(u16)); 627 WPA_PUT_LE16(attr_len, (u16) total_len); 628 p2p_buf_update_ie_hdr(tmp_buf, ie_len); 629 pos = wpabuf_put(tmp_buf, 0); 630 631 if (p2ps_wildcard) { 632 /* org.wi-fi.wfds match found */ 633 p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR, 634 &ie_len, &pos, &total_len, attr_len); 635 } 636 637 /* add advertised service info of matching services */ 638 for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN; 639 adv = adv->next) { 640 const u8 *test = hash; 641 u8 i; 642 643 for (i = 0; i < hash_count; i++) { 644 /* exact name hash match */ 645 if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 && 646 p2p_buf_add_service_info(tmp_buf, p2p, 647 adv->id, 648 adv->config_methods, 649 adv->svc_name, 650 &ie_len, &pos, 651 &total_len, 652 attr_len)) 653 break; 654 655 test += P2PS_HASH_LEN; 656 } 657 } 658 659 if (total_len) 660 wpabuf_put_buf(buf, tmp_buf); 661 wpabuf_free(tmp_buf); 662} 663 664 665void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac) 666{ 667 if (!buf || !mac) 668 return; 669 670 /* Session ID Info */ 671 wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID); 672 wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN)); 673 wpabuf_put_le32(buf, id); 674 wpabuf_put_data(buf, mac, ETH_ALEN); 675 wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR, 676 id, MAC2STR(mac)); 677} 678 679 680void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask) 681{ 682 if (!buf || !len || !mask) 683 return; 684 685 /* Feature Capability */ 686 wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY); 687 wpabuf_put_le16(buf, len); 688 wpabuf_put_data(buf, mask, len); 689 wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len); 690} 691 692 693void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, 694 const u8 *ssid, size_t ssid_len) 695{ 696 /* P2P Group ID */ 697 wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP); 698 wpabuf_put_le16(buf, ETH_ALEN + ssid_len); 699 wpabuf_put_data(buf, dev_addr, ETH_ALEN); 700 wpabuf_put_data(buf, ssid, ssid_len); 701 wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, 702 MAC2STR(dev_addr)); 703} 704 705 706static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, 707 const char *val) 708{ 709 size_t len; 710 711 len = val ? os_strlen(val) : 0; 712 if (wpabuf_tailroom(buf) < 4 + len) 713 return -1; 714 wpabuf_put_be16(buf, attr); 715#ifndef CONFIG_WPS_STRICT 716 if (len == 0) { 717 /* 718 * Some deployed WPS implementations fail to parse zeor-length 719 * attributes. As a workaround, send a space character if the 720 * device attribute string is empty. 721 */ 722 if (wpabuf_tailroom(buf) < 3) 723 return -1; 724 wpabuf_put_be16(buf, 1); 725 wpabuf_put_u8(buf, ' '); 726 return 0; 727 } 728#endif /* CONFIG_WPS_STRICT */ 729 wpabuf_put_be16(buf, len); 730 if (val) 731 wpabuf_put_data(buf, val, len); 732 return 0; 733} 734 735 736int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, 737 int all_attr) 738{ 739 u8 *len; 740 int i; 741 742 if (wpabuf_tailroom(buf) < 6) 743 return -1; 744 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 745 len = wpabuf_put(buf, 1); 746 wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); 747 748 if (wps_build_version(buf) < 0) 749 return -1; 750 751 if (all_attr) { 752 if (wpabuf_tailroom(buf) < 5) 753 return -1; 754 wpabuf_put_be16(buf, ATTR_WPS_STATE); 755 wpabuf_put_be16(buf, 1); 756 wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED); 757 } 758 759 if (pw_id >= 0) { 760 if (wpabuf_tailroom(buf) < 6) 761 return -1; 762 /* Device Password ID */ 763 wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID); 764 wpabuf_put_be16(buf, 2); 765 wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", 766 pw_id); 767 wpabuf_put_be16(buf, pw_id); 768 } 769 770 if (all_attr) { 771 if (wpabuf_tailroom(buf) < 5) 772 return -1; 773 wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE); 774 wpabuf_put_be16(buf, 1); 775 wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO); 776 777 if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 || 778 p2p_add_wps_string(buf, ATTR_MANUFACTURER, 779 p2p->cfg->manufacturer) < 0 || 780 p2p_add_wps_string(buf, ATTR_MODEL_NAME, 781 p2p->cfg->model_name) < 0 || 782 p2p_add_wps_string(buf, ATTR_MODEL_NUMBER, 783 p2p->cfg->model_number) < 0 || 784 p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER, 785 p2p->cfg->serial_number) < 0) 786 return -1; 787 788 if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN) 789 return -1; 790 wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE); 791 wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN); 792 wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN); 793 794 if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name) 795 < 0) 796 return -1; 797 798 if (wpabuf_tailroom(buf) < 6) 799 return -1; 800 wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); 801 wpabuf_put_be16(buf, 2); 802 wpabuf_put_be16(buf, p2p->cfg->config_methods); 803 } 804 805 if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) 806 return -1; 807 808 if (all_attr && p2p->cfg->num_sec_dev_types) { 809 if (wpabuf_tailroom(buf) < 810 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types) 811 return -1; 812 wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST); 813 wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN * 814 p2p->cfg->num_sec_dev_types); 815 wpabuf_put_data(buf, p2p->cfg->sec_dev_type, 816 WPS_DEV_TYPE_LEN * 817 p2p->cfg->num_sec_dev_types); 818 } 819 820 /* Add the WPS vendor extensions */ 821 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 822 if (p2p->wps_vendor_ext[i] == NULL) 823 break; 824 if (wpabuf_tailroom(buf) < 825 4 + wpabuf_len(p2p->wps_vendor_ext[i])) 826 continue; 827 wpabuf_put_be16(buf, ATTR_VENDOR_EXT); 828 wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i])); 829 wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]); 830 } 831 832 p2p_buf_update_ie_hdr(buf, len); 833 834 return 0; 835} 836