1252190Srpaulo/* 2252190Srpaulo * wpa_supplicant - Wi-Fi Display 3252190Srpaulo * Copyright (c) 2011, Atheros Communications, Inc. 4252190Srpaulo * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. 5252190Srpaulo * 6252190Srpaulo * This software may be distributed under the terms of the BSD license. 7252190Srpaulo * See README for more details. 8252190Srpaulo */ 9252190Srpaulo 10252190Srpaulo#include "includes.h" 11252190Srpaulo 12252190Srpaulo#include "common.h" 13252190Srpaulo#include "p2p/p2p.h" 14252190Srpaulo#include "common/ieee802_11_defs.h" 15252190Srpaulo#include "wpa_supplicant_i.h" 16252190Srpaulo#include "wifi_display.h" 17252190Srpaulo 18252190Srpaulo 19252190Srpauloint wifi_display_init(struct wpa_global *global) 20252190Srpaulo{ 21252190Srpaulo global->wifi_display = 1; 22252190Srpaulo return 0; 23252190Srpaulo} 24252190Srpaulo 25252190Srpaulo 26252190Srpaulovoid wifi_display_deinit(struct wpa_global *global) 27252190Srpaulo{ 28252190Srpaulo int i; 29252190Srpaulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) { 30252190Srpaulo wpabuf_free(global->wfd_subelem[i]); 31252190Srpaulo global->wfd_subelem[i] = NULL; 32252190Srpaulo } 33252190Srpaulo} 34252190Srpaulo 35252190Srpaulo 36252190Srpaulostatic int wifi_display_update_wfd_ie(struct wpa_global *global) 37252190Srpaulo{ 38252190Srpaulo struct wpabuf *ie, *buf; 39252190Srpaulo size_t len, plen; 40252190Srpaulo 41252190Srpaulo wpa_printf(MSG_DEBUG, "WFD: Update WFD IE"); 42252190Srpaulo 43252190Srpaulo if (!global->wifi_display) { 44252190Srpaulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not " 45252190Srpaulo "include WFD IE"); 46252190Srpaulo p2p_set_wfd_ie_beacon(global->p2p, NULL); 47252190Srpaulo p2p_set_wfd_ie_probe_req(global->p2p, NULL); 48252190Srpaulo p2p_set_wfd_ie_probe_resp(global->p2p, NULL); 49252190Srpaulo p2p_set_wfd_ie_assoc_req(global->p2p, NULL); 50252190Srpaulo p2p_set_wfd_ie_invitation(global->p2p, NULL); 51252190Srpaulo p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL); 52252190Srpaulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL); 53252190Srpaulo p2p_set_wfd_ie_go_neg(global->p2p, NULL); 54252190Srpaulo p2p_set_wfd_dev_info(global->p2p, NULL); 55252190Srpaulo p2p_set_wfd_assoc_bssid(global->p2p, NULL); 56252190Srpaulo p2p_set_wfd_coupled_sink_info(global->p2p, NULL); 57252190Srpaulo return 0; 58252190Srpaulo } 59252190Srpaulo 60252190Srpaulo p2p_set_wfd_dev_info(global->p2p, 61252190Srpaulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); 62252190Srpaulo p2p_set_wfd_assoc_bssid( 63252190Srpaulo global->p2p, 64252190Srpaulo global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]); 65252190Srpaulo p2p_set_wfd_coupled_sink_info( 66252190Srpaulo global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); 67252190Srpaulo 68252190Srpaulo /* 69252190Srpaulo * WFD IE is included in number of management frames. Two different 70252190Srpaulo * sets of subelements are included depending on the frame: 71252190Srpaulo * 72252190Srpaulo * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf, 73252190Srpaulo * Provision Discovery Req: 74252190Srpaulo * WFD Device Info 75252190Srpaulo * [Associated BSSID] 76252190Srpaulo * [Coupled Sink Info] 77252190Srpaulo * 78252190Srpaulo * Probe Request: 79252190Srpaulo * WFD Device Info 80252190Srpaulo * [Associated BSSID] 81252190Srpaulo * [Coupled Sink Info] 82252190Srpaulo * [WFD Extended Capability] 83252190Srpaulo * 84252190Srpaulo * Probe Response: 85252190Srpaulo * WFD Device Info 86252190Srpaulo * [Associated BSSID] 87252190Srpaulo * [Coupled Sink Info] 88252190Srpaulo * [WFD Extended Capability] 89252190Srpaulo * [WFD Session Info] 90252190Srpaulo * 91252190Srpaulo * (Re)Association Response, P2P Invitation Req/Resp, 92252190Srpaulo * Provision Discovery Resp: 93252190Srpaulo * WFD Device Info 94252190Srpaulo * [Associated BSSID] 95252190Srpaulo * [Coupled Sink Info] 96252190Srpaulo * [WFD Session Info] 97252190Srpaulo */ 98252190Srpaulo len = 0; 99252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) 100252190Srpaulo len += wpabuf_len(global->wfd_subelem[ 101252190Srpaulo WFD_SUBELEM_DEVICE_INFO]); 102252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) 103252190Srpaulo len += wpabuf_len(global->wfd_subelem[ 104252190Srpaulo WFD_SUBELEM_ASSOCIATED_BSSID]); 105252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) 106252190Srpaulo len += wpabuf_len(global->wfd_subelem[ 107252190Srpaulo WFD_SUBELEM_COUPLED_SINK]); 108252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 109252190Srpaulo len += wpabuf_len(global->wfd_subelem[ 110252190Srpaulo WFD_SUBELEM_SESSION_INFO]); 111252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) 112252190Srpaulo len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); 113252190Srpaulo buf = wpabuf_alloc(len); 114252190Srpaulo if (buf == NULL) 115252190Srpaulo return -1; 116252190Srpaulo 117252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) 118252190Srpaulo wpabuf_put_buf(buf, 119252190Srpaulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); 120252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) 121252190Srpaulo wpabuf_put_buf(buf, global->wfd_subelem[ 122252190Srpaulo WFD_SUBELEM_ASSOCIATED_BSSID]); 123252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) 124252190Srpaulo wpabuf_put_buf(buf, 125252190Srpaulo global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); 126252190Srpaulo 127252190Srpaulo ie = wifi_display_encaps(buf); 128252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie); 129252190Srpaulo p2p_set_wfd_ie_beacon(global->p2p, ie); 130252190Srpaulo 131252190Srpaulo ie = wifi_display_encaps(buf); 132252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request", 133252190Srpaulo ie); 134252190Srpaulo p2p_set_wfd_ie_assoc_req(global->p2p, ie); 135252190Srpaulo 136252190Srpaulo ie = wifi_display_encaps(buf); 137252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie); 138252190Srpaulo p2p_set_wfd_ie_go_neg(global->p2p, ie); 139252190Srpaulo 140252190Srpaulo ie = wifi_display_encaps(buf); 141252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " 142252190Srpaulo "Request", ie); 143252190Srpaulo p2p_set_wfd_ie_prov_disc_req(global->p2p, ie); 144252190Srpaulo 145252190Srpaulo plen = buf->used; 146252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) 147252190Srpaulo wpabuf_put_buf(buf, 148252190Srpaulo global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); 149252190Srpaulo 150252190Srpaulo ie = wifi_display_encaps(buf); 151252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie); 152252190Srpaulo p2p_set_wfd_ie_probe_req(global->p2p, ie); 153252190Srpaulo 154252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 155252190Srpaulo wpabuf_put_buf(buf, 156252190Srpaulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); 157252190Srpaulo ie = wifi_display_encaps(buf); 158252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie); 159252190Srpaulo p2p_set_wfd_ie_probe_resp(global->p2p, ie); 160252190Srpaulo 161252190Srpaulo /* Remove WFD Extended Capability from buffer */ 162252190Srpaulo buf->used = plen; 163252190Srpaulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 164252190Srpaulo wpabuf_put_buf(buf, 165252190Srpaulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); 166252190Srpaulo 167252190Srpaulo ie = wifi_display_encaps(buf); 168252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie); 169252190Srpaulo p2p_set_wfd_ie_invitation(global->p2p, ie); 170252190Srpaulo 171252190Srpaulo ie = wifi_display_encaps(buf); 172252190Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " 173252190Srpaulo "Response", ie); 174252190Srpaulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie); 175252190Srpaulo 176252190Srpaulo wpabuf_free(buf); 177252190Srpaulo 178252190Srpaulo return 0; 179252190Srpaulo} 180252190Srpaulo 181252190Srpaulo 182252190Srpaulovoid wifi_display_enable(struct wpa_global *global, int enabled) 183252190Srpaulo{ 184252190Srpaulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s", 185252190Srpaulo enabled ? "enabled" : "disabled"); 186252190Srpaulo global->wifi_display = enabled; 187252190Srpaulo wifi_display_update_wfd_ie(global); 188252190Srpaulo} 189252190Srpaulo 190252190Srpaulo 191252190Srpauloint wifi_display_subelem_set(struct wpa_global *global, char *cmd) 192252190Srpaulo{ 193252190Srpaulo char *pos; 194252190Srpaulo int subelem; 195252190Srpaulo size_t len; 196252190Srpaulo struct wpabuf *e; 197252190Srpaulo 198252190Srpaulo pos = os_strchr(cmd, ' '); 199252190Srpaulo if (pos == NULL) 200252190Srpaulo return -1; 201252190Srpaulo *pos++ = '\0'; 202252190Srpaulo subelem = atoi(cmd); 203252190Srpaulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) 204252190Srpaulo return -1; 205252190Srpaulo 206252190Srpaulo len = os_strlen(pos); 207252190Srpaulo if (len & 1) 208252190Srpaulo return -1; 209252190Srpaulo len /= 2; 210252190Srpaulo 211252190Srpaulo if (len == 0) { 212252190Srpaulo /* Clear subelement */ 213252190Srpaulo e = NULL; 214252190Srpaulo wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem); 215252190Srpaulo } else { 216252190Srpaulo e = wpabuf_alloc(1 + len); 217252190Srpaulo if (e == NULL) 218252190Srpaulo return -1; 219252190Srpaulo wpabuf_put_u8(e, subelem); 220252190Srpaulo if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) { 221252190Srpaulo wpabuf_free(e); 222252190Srpaulo return -1; 223252190Srpaulo } 224252190Srpaulo wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem); 225252190Srpaulo } 226252190Srpaulo 227252190Srpaulo wpabuf_free(global->wfd_subelem[subelem]); 228252190Srpaulo global->wfd_subelem[subelem] = e; 229252190Srpaulo wifi_display_update_wfd_ie(global); 230252190Srpaulo 231252190Srpaulo return 0; 232252190Srpaulo} 233252190Srpaulo 234252190Srpaulo 235252190Srpauloint wifi_display_subelem_get(struct wpa_global *global, char *cmd, 236252190Srpaulo char *buf, size_t buflen) 237252190Srpaulo{ 238252190Srpaulo int subelem; 239252190Srpaulo 240252190Srpaulo subelem = atoi(cmd); 241252190Srpaulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) 242252190Srpaulo return -1; 243252190Srpaulo 244252190Srpaulo if (global->wfd_subelem[subelem] == NULL) 245252190Srpaulo return 0; 246252190Srpaulo 247252190Srpaulo return wpa_snprintf_hex(buf, buflen, 248252190Srpaulo wpabuf_head_u8(global->wfd_subelem[subelem]) + 249252190Srpaulo 1, 250252190Srpaulo wpabuf_len(global->wfd_subelem[subelem]) - 1); 251252190Srpaulo} 252