1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * wpa_supplicant - Wi-Fi Display 3f05cddf9SRui Paulo * Copyright (c) 2011, Atheros Communications, Inc. 4f05cddf9SRui Paulo * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. 5f05cddf9SRui Paulo * 6f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 7f05cddf9SRui Paulo * See README for more details. 8f05cddf9SRui Paulo */ 9f05cddf9SRui Paulo 10f05cddf9SRui Paulo #include "includes.h" 11f05cddf9SRui Paulo 12f05cddf9SRui Paulo #include "common.h" 13f05cddf9SRui Paulo #include "p2p/p2p.h" 14f05cddf9SRui Paulo #include "common/ieee802_11_defs.h" 15f05cddf9SRui Paulo #include "wpa_supplicant_i.h" 16f05cddf9SRui Paulo #include "wifi_display.h" 17f05cddf9SRui Paulo 18f05cddf9SRui Paulo 19*5b9c547cSRui Paulo #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3 20*5b9c547cSRui Paulo 21*5b9c547cSRui Paulo 22f05cddf9SRui Paulo int wifi_display_init(struct wpa_global *global) 23f05cddf9SRui Paulo { 24f05cddf9SRui Paulo global->wifi_display = 1; 25f05cddf9SRui Paulo return 0; 26f05cddf9SRui Paulo } 27f05cddf9SRui Paulo 28f05cddf9SRui Paulo 29f05cddf9SRui Paulo void wifi_display_deinit(struct wpa_global *global) 30f05cddf9SRui Paulo { 31f05cddf9SRui Paulo int i; 32f05cddf9SRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) { 33f05cddf9SRui Paulo wpabuf_free(global->wfd_subelem[i]); 34f05cddf9SRui Paulo global->wfd_subelem[i] = NULL; 35f05cddf9SRui Paulo } 36f05cddf9SRui Paulo } 37f05cddf9SRui Paulo 38f05cddf9SRui Paulo 39*5b9c547cSRui Paulo struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global) 40*5b9c547cSRui Paulo { 41*5b9c547cSRui Paulo struct wpabuf *ie; 42*5b9c547cSRui Paulo size_t len; 43*5b9c547cSRui Paulo int i; 44*5b9c547cSRui Paulo 45*5b9c547cSRui Paulo if (global->p2p == NULL) 46*5b9c547cSRui Paulo return NULL; 47*5b9c547cSRui Paulo 48*5b9c547cSRui Paulo len = 0; 49*5b9c547cSRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) { 50*5b9c547cSRui Paulo if (global->wfd_subelem[i]) 51*5b9c547cSRui Paulo len += wpabuf_len(global->wfd_subelem[i]); 52*5b9c547cSRui Paulo } 53*5b9c547cSRui Paulo 54*5b9c547cSRui Paulo ie = wpabuf_alloc(len); 55*5b9c547cSRui Paulo if (ie == NULL) 56*5b9c547cSRui Paulo return NULL; 57*5b9c547cSRui Paulo 58*5b9c547cSRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) { 59*5b9c547cSRui Paulo if (global->wfd_subelem[i]) 60*5b9c547cSRui Paulo wpabuf_put_buf(ie, global->wfd_subelem[i]); 61*5b9c547cSRui Paulo } 62*5b9c547cSRui Paulo 63*5b9c547cSRui Paulo return ie; 64*5b9c547cSRui Paulo } 65*5b9c547cSRui Paulo 66*5b9c547cSRui Paulo 67f05cddf9SRui Paulo static int wifi_display_update_wfd_ie(struct wpa_global *global) 68f05cddf9SRui Paulo { 69f05cddf9SRui Paulo struct wpabuf *ie, *buf; 70f05cddf9SRui Paulo size_t len, plen; 71f05cddf9SRui Paulo 72*5b9c547cSRui Paulo if (global->p2p == NULL) 73*5b9c547cSRui Paulo return 0; 74*5b9c547cSRui Paulo 75f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Update WFD IE"); 76f05cddf9SRui Paulo 77f05cddf9SRui Paulo if (!global->wifi_display) { 78f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not " 79f05cddf9SRui Paulo "include WFD IE"); 80f05cddf9SRui Paulo p2p_set_wfd_ie_beacon(global->p2p, NULL); 81f05cddf9SRui Paulo p2p_set_wfd_ie_probe_req(global->p2p, NULL); 82f05cddf9SRui Paulo p2p_set_wfd_ie_probe_resp(global->p2p, NULL); 83f05cddf9SRui Paulo p2p_set_wfd_ie_assoc_req(global->p2p, NULL); 84f05cddf9SRui Paulo p2p_set_wfd_ie_invitation(global->p2p, NULL); 85f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL); 86f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL); 87f05cddf9SRui Paulo p2p_set_wfd_ie_go_neg(global->p2p, NULL); 88f05cddf9SRui Paulo p2p_set_wfd_dev_info(global->p2p, NULL); 89f05cddf9SRui Paulo p2p_set_wfd_assoc_bssid(global->p2p, NULL); 90f05cddf9SRui Paulo p2p_set_wfd_coupled_sink_info(global->p2p, NULL); 91f05cddf9SRui Paulo return 0; 92f05cddf9SRui Paulo } 93f05cddf9SRui Paulo 94f05cddf9SRui Paulo p2p_set_wfd_dev_info(global->p2p, 95f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); 96f05cddf9SRui Paulo p2p_set_wfd_assoc_bssid( 97f05cddf9SRui Paulo global->p2p, 98f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]); 99f05cddf9SRui Paulo p2p_set_wfd_coupled_sink_info( 100f05cddf9SRui Paulo global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); 101f05cddf9SRui Paulo 102f05cddf9SRui Paulo /* 103f05cddf9SRui Paulo * WFD IE is included in number of management frames. Two different 104f05cddf9SRui Paulo * sets of subelements are included depending on the frame: 105f05cddf9SRui Paulo * 106f05cddf9SRui Paulo * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf, 107f05cddf9SRui Paulo * Provision Discovery Req: 108f05cddf9SRui Paulo * WFD Device Info 109f05cddf9SRui Paulo * [Associated BSSID] 110f05cddf9SRui Paulo * [Coupled Sink Info] 111f05cddf9SRui Paulo * 112f05cddf9SRui Paulo * Probe Request: 113f05cddf9SRui Paulo * WFD Device Info 114f05cddf9SRui Paulo * [Associated BSSID] 115f05cddf9SRui Paulo * [Coupled Sink Info] 116f05cddf9SRui Paulo * [WFD Extended Capability] 117f05cddf9SRui Paulo * 118f05cddf9SRui Paulo * Probe Response: 119f05cddf9SRui Paulo * WFD Device Info 120f05cddf9SRui Paulo * [Associated BSSID] 121f05cddf9SRui Paulo * [Coupled Sink Info] 122f05cddf9SRui Paulo * [WFD Extended Capability] 123f05cddf9SRui Paulo * [WFD Session Info] 124f05cddf9SRui Paulo * 125f05cddf9SRui Paulo * (Re)Association Response, P2P Invitation Req/Resp, 126f05cddf9SRui Paulo * Provision Discovery Resp: 127f05cddf9SRui Paulo * WFD Device Info 128f05cddf9SRui Paulo * [Associated BSSID] 129f05cddf9SRui Paulo * [Coupled Sink Info] 130f05cddf9SRui Paulo * [WFD Session Info] 131f05cddf9SRui Paulo */ 132f05cddf9SRui Paulo len = 0; 133f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) 134f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[ 135f05cddf9SRui Paulo WFD_SUBELEM_DEVICE_INFO]); 136f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) 137f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[ 138f05cddf9SRui Paulo WFD_SUBELEM_ASSOCIATED_BSSID]); 139f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) 140f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[ 141f05cddf9SRui Paulo WFD_SUBELEM_COUPLED_SINK]); 142f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 143f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[ 144f05cddf9SRui Paulo WFD_SUBELEM_SESSION_INFO]); 145f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) 146f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); 147f05cddf9SRui Paulo buf = wpabuf_alloc(len); 148f05cddf9SRui Paulo if (buf == NULL) 149f05cddf9SRui Paulo return -1; 150f05cddf9SRui Paulo 151f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) 152f05cddf9SRui Paulo wpabuf_put_buf(buf, 153f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); 154f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) 155f05cddf9SRui Paulo wpabuf_put_buf(buf, global->wfd_subelem[ 156f05cddf9SRui Paulo WFD_SUBELEM_ASSOCIATED_BSSID]); 157f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) 158f05cddf9SRui Paulo wpabuf_put_buf(buf, 159f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); 160f05cddf9SRui Paulo 161f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 162f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie); 163f05cddf9SRui Paulo p2p_set_wfd_ie_beacon(global->p2p, ie); 164f05cddf9SRui Paulo 165f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 166f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request", 167f05cddf9SRui Paulo ie); 168f05cddf9SRui Paulo p2p_set_wfd_ie_assoc_req(global->p2p, ie); 169f05cddf9SRui Paulo 170f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 171f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie); 172f05cddf9SRui Paulo p2p_set_wfd_ie_go_neg(global->p2p, ie); 173f05cddf9SRui Paulo 174f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 175f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " 176f05cddf9SRui Paulo "Request", ie); 177f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_req(global->p2p, ie); 178f05cddf9SRui Paulo 179f05cddf9SRui Paulo plen = buf->used; 180f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) 181f05cddf9SRui Paulo wpabuf_put_buf(buf, 182f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); 183f05cddf9SRui Paulo 184f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 185f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie); 186f05cddf9SRui Paulo p2p_set_wfd_ie_probe_req(global->p2p, ie); 187f05cddf9SRui Paulo 188f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 189f05cddf9SRui Paulo wpabuf_put_buf(buf, 190f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); 191f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 192f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie); 193f05cddf9SRui Paulo p2p_set_wfd_ie_probe_resp(global->p2p, ie); 194f05cddf9SRui Paulo 195f05cddf9SRui Paulo /* Remove WFD Extended Capability from buffer */ 196f05cddf9SRui Paulo buf->used = plen; 197f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) 198f05cddf9SRui Paulo wpabuf_put_buf(buf, 199f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); 200f05cddf9SRui Paulo 201f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 202f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie); 203f05cddf9SRui Paulo p2p_set_wfd_ie_invitation(global->p2p, ie); 204f05cddf9SRui Paulo 205f05cddf9SRui Paulo ie = wifi_display_encaps(buf); 206f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " 207f05cddf9SRui Paulo "Response", ie); 208f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie); 209f05cddf9SRui Paulo 210f05cddf9SRui Paulo wpabuf_free(buf); 211f05cddf9SRui Paulo 212f05cddf9SRui Paulo return 0; 213f05cddf9SRui Paulo } 214f05cddf9SRui Paulo 215f05cddf9SRui Paulo 216f05cddf9SRui Paulo void wifi_display_enable(struct wpa_global *global, int enabled) 217f05cddf9SRui Paulo { 218f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s", 219f05cddf9SRui Paulo enabled ? "enabled" : "disabled"); 220f05cddf9SRui Paulo global->wifi_display = enabled; 221f05cddf9SRui Paulo wifi_display_update_wfd_ie(global); 222f05cddf9SRui Paulo } 223f05cddf9SRui Paulo 224f05cddf9SRui Paulo 225f05cddf9SRui Paulo int wifi_display_subelem_set(struct wpa_global *global, char *cmd) 226f05cddf9SRui Paulo { 227f05cddf9SRui Paulo char *pos; 228f05cddf9SRui Paulo int subelem; 229f05cddf9SRui Paulo size_t len; 230f05cddf9SRui Paulo struct wpabuf *e; 231f05cddf9SRui Paulo 232f05cddf9SRui Paulo pos = os_strchr(cmd, ' '); 233f05cddf9SRui Paulo if (pos == NULL) 234f05cddf9SRui Paulo return -1; 235f05cddf9SRui Paulo *pos++ = '\0'; 236f05cddf9SRui Paulo 237f05cddf9SRui Paulo len = os_strlen(pos); 238f05cddf9SRui Paulo if (len & 1) 239f05cddf9SRui Paulo return -1; 240f05cddf9SRui Paulo len /= 2; 241f05cddf9SRui Paulo 242*5b9c547cSRui Paulo if (os_strcmp(cmd, "all") == 0) { 243*5b9c547cSRui Paulo int res; 244*5b9c547cSRui Paulo 245*5b9c547cSRui Paulo e = wpabuf_alloc(len); 246*5b9c547cSRui Paulo if (e == NULL) 247*5b9c547cSRui Paulo return -1; 248*5b9c547cSRui Paulo if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) { 249*5b9c547cSRui Paulo wpabuf_free(e); 250*5b9c547cSRui Paulo return -1; 251*5b9c547cSRui Paulo } 252*5b9c547cSRui Paulo res = wifi_display_subelem_set_from_ies(global, e); 253*5b9c547cSRui Paulo wpabuf_free(e); 254*5b9c547cSRui Paulo return res; 255*5b9c547cSRui Paulo } 256*5b9c547cSRui Paulo 257*5b9c547cSRui Paulo subelem = atoi(cmd); 258*5b9c547cSRui Paulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) 259*5b9c547cSRui Paulo return -1; 260*5b9c547cSRui Paulo 261f05cddf9SRui Paulo if (len == 0) { 262f05cddf9SRui Paulo /* Clear subelement */ 263f05cddf9SRui Paulo e = NULL; 264f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem); 265f05cddf9SRui Paulo } else { 266f05cddf9SRui Paulo e = wpabuf_alloc(1 + len); 267f05cddf9SRui Paulo if (e == NULL) 268f05cddf9SRui Paulo return -1; 269f05cddf9SRui Paulo wpabuf_put_u8(e, subelem); 270f05cddf9SRui Paulo if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) { 271f05cddf9SRui Paulo wpabuf_free(e); 272f05cddf9SRui Paulo return -1; 273f05cddf9SRui Paulo } 274f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem); 275f05cddf9SRui Paulo } 276f05cddf9SRui Paulo 277f05cddf9SRui Paulo wpabuf_free(global->wfd_subelem[subelem]); 278f05cddf9SRui Paulo global->wfd_subelem[subelem] = e; 279f05cddf9SRui Paulo wifi_display_update_wfd_ie(global); 280f05cddf9SRui Paulo 281f05cddf9SRui Paulo return 0; 282f05cddf9SRui Paulo } 283f05cddf9SRui Paulo 284f05cddf9SRui Paulo 285*5b9c547cSRui Paulo int wifi_display_subelem_set_from_ies(struct wpa_global *global, 286*5b9c547cSRui Paulo struct wpabuf *ie) 287*5b9c547cSRui Paulo { 288*5b9c547cSRui Paulo int subelements[MAX_WFD_SUBELEMS] = {}; 289*5b9c547cSRui Paulo const u8 *pos, *end; 290*5b9c547cSRui Paulo unsigned int len, subelem; 291*5b9c547cSRui Paulo struct wpabuf *e; 292*5b9c547cSRui Paulo 293*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu", 294*5b9c547cSRui Paulo ie, ie ? (unsigned long) wpabuf_len(ie) : 0); 295*5b9c547cSRui Paulo 296*5b9c547cSRui Paulo if (ie == NULL || wpabuf_len(ie) < 6) 297*5b9c547cSRui Paulo return -1; 298*5b9c547cSRui Paulo 299*5b9c547cSRui Paulo pos = wpabuf_head(ie); 300*5b9c547cSRui Paulo end = pos + wpabuf_len(ie); 301*5b9c547cSRui Paulo 302*5b9c547cSRui Paulo while (end > pos) { 303*5b9c547cSRui Paulo if (pos + 3 > end) 304*5b9c547cSRui Paulo break; 305*5b9c547cSRui Paulo 306*5b9c547cSRui Paulo len = WPA_GET_BE16(pos + 1) + 3; 307*5b9c547cSRui Paulo 308*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d", 309*5b9c547cSRui Paulo *pos, len - 3); 310*5b9c547cSRui Paulo 311*5b9c547cSRui Paulo if (len > (unsigned int) (end - pos)) 312*5b9c547cSRui Paulo break; 313*5b9c547cSRui Paulo 314*5b9c547cSRui Paulo subelem = *pos; 315*5b9c547cSRui Paulo if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) { 316*5b9c547cSRui Paulo e = wpabuf_alloc_copy(pos, len); 317*5b9c547cSRui Paulo if (e == NULL) 318*5b9c547cSRui Paulo return -1; 319*5b9c547cSRui Paulo 320*5b9c547cSRui Paulo wpabuf_free(global->wfd_subelem[subelem]); 321*5b9c547cSRui Paulo global->wfd_subelem[subelem] = e; 322*5b9c547cSRui Paulo subelements[subelem] = 1; 323*5b9c547cSRui Paulo } 324*5b9c547cSRui Paulo 325*5b9c547cSRui Paulo pos += len; 326*5b9c547cSRui Paulo } 327*5b9c547cSRui Paulo 328*5b9c547cSRui Paulo for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) { 329*5b9c547cSRui Paulo if (subelements[subelem] == 0) { 330*5b9c547cSRui Paulo wpabuf_free(global->wfd_subelem[subelem]); 331*5b9c547cSRui Paulo global->wfd_subelem[subelem] = NULL; 332*5b9c547cSRui Paulo } 333*5b9c547cSRui Paulo } 334*5b9c547cSRui Paulo 335*5b9c547cSRui Paulo return wifi_display_update_wfd_ie(global); 336*5b9c547cSRui Paulo } 337*5b9c547cSRui Paulo 338*5b9c547cSRui Paulo 339f05cddf9SRui Paulo int wifi_display_subelem_get(struct wpa_global *global, char *cmd, 340f05cddf9SRui Paulo char *buf, size_t buflen) 341f05cddf9SRui Paulo { 342f05cddf9SRui Paulo int subelem; 343f05cddf9SRui Paulo 344*5b9c547cSRui Paulo if (os_strcmp(cmd, "all") == 0) { 345*5b9c547cSRui Paulo struct wpabuf *ie; 346*5b9c547cSRui Paulo int res; 347*5b9c547cSRui Paulo 348*5b9c547cSRui Paulo ie = wifi_display_get_wfd_ie(global); 349*5b9c547cSRui Paulo if (ie == NULL) 350*5b9c547cSRui Paulo return 0; 351*5b9c547cSRui Paulo res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie), 352*5b9c547cSRui Paulo wpabuf_len(ie)); 353*5b9c547cSRui Paulo wpabuf_free(ie); 354*5b9c547cSRui Paulo return res; 355*5b9c547cSRui Paulo } 356*5b9c547cSRui Paulo 357f05cddf9SRui Paulo subelem = atoi(cmd); 358f05cddf9SRui Paulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) 359f05cddf9SRui Paulo return -1; 360f05cddf9SRui Paulo 361f05cddf9SRui Paulo if (global->wfd_subelem[subelem] == NULL) 362f05cddf9SRui Paulo return 0; 363f05cddf9SRui Paulo 364f05cddf9SRui Paulo return wpa_snprintf_hex(buf, buflen, 365f05cddf9SRui Paulo wpabuf_head_u8(global->wfd_subelem[subelem]) + 366f05cddf9SRui Paulo 1, 367f05cddf9SRui Paulo wpabuf_len(global->wfd_subelem[subelem]) - 1); 368f05cddf9SRui Paulo } 369*5b9c547cSRui Paulo 370*5b9c547cSRui Paulo 371*5b9c547cSRui Paulo char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id) 372*5b9c547cSRui Paulo { 373*5b9c547cSRui Paulo char *subelem = NULL; 374*5b9c547cSRui Paulo const u8 *buf; 375*5b9c547cSRui Paulo size_t buflen; 376*5b9c547cSRui Paulo size_t i = 0; 377*5b9c547cSRui Paulo u16 elen; 378*5b9c547cSRui Paulo 379*5b9c547cSRui Paulo if (!wfd_subelems) 380*5b9c547cSRui Paulo return NULL; 381*5b9c547cSRui Paulo 382*5b9c547cSRui Paulo buf = wpabuf_head_u8(wfd_subelems); 383*5b9c547cSRui Paulo if (!buf) 384*5b9c547cSRui Paulo return NULL; 385*5b9c547cSRui Paulo 386*5b9c547cSRui Paulo buflen = wpabuf_len(wfd_subelems); 387*5b9c547cSRui Paulo 388*5b9c547cSRui Paulo while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) { 389*5b9c547cSRui Paulo elen = WPA_GET_BE16(buf + i + 1); 390*5b9c547cSRui Paulo if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen) 391*5b9c547cSRui Paulo break; /* truncated subelement */ 392*5b9c547cSRui Paulo 393*5b9c547cSRui Paulo if (buf[i] == id) { 394*5b9c547cSRui Paulo /* 395*5b9c547cSRui Paulo * Limit explicitly to an arbitrary length to avoid 396*5b9c547cSRui Paulo * unnecessarily large allocations. In practice, this 397*5b9c547cSRui Paulo * is limited to maximum frame length anyway, so the 398*5b9c547cSRui Paulo * maximum memory allocation here is not really that 399*5b9c547cSRui Paulo * large. Anyway, the Wi-Fi Display subelements that 400*5b9c547cSRui Paulo * are fetched with this function are even shorter. 401*5b9c547cSRui Paulo */ 402*5b9c547cSRui Paulo if (elen > 1000) 403*5b9c547cSRui Paulo break; 404*5b9c547cSRui Paulo subelem = os_zalloc(2 * elen + 1); 405*5b9c547cSRui Paulo if (!subelem) 406*5b9c547cSRui Paulo return NULL; 407*5b9c547cSRui Paulo wpa_snprintf_hex(subelem, 2 * elen + 1, 408*5b9c547cSRui Paulo buf + i + 409*5b9c547cSRui Paulo WIFI_DISPLAY_SUBELEM_HEADER_LEN, 410*5b9c547cSRui Paulo elen); 411*5b9c547cSRui Paulo break; 412*5b9c547cSRui Paulo } 413*5b9c547cSRui Paulo 414*5b9c547cSRui Paulo i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN; 415*5b9c547cSRui Paulo } 416*5b9c547cSRui Paulo 417*5b9c547cSRui Paulo return subelem; 418*5b9c547cSRui Paulo } 419