123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- /*
- * wpa_supplicant - Wi-Fi Display
- * Copyright (c) 2011, Atheros Communications, Inc.
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "includes.h"
- #include "common.h"
- #include "p2p/p2p.h"
- #include "common/ieee802_11_defs.h"
- #include "wpa_supplicant_i.h"
- #include "wifi_display.h"
- #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
- int wifi_display_init(struct wpa_global *global)
- {
- global->wifi_display = 1;
- return 0;
- }
- void wifi_display_deinit(struct wpa_global *global)
- {
- int i;
- for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
- wpabuf_free(global->wfd_subelem[i]);
- global->wfd_subelem[i] = NULL;
- }
- }
- struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
- {
- struct wpabuf *ie;
- size_t len;
- int i;
- if (global->p2p == NULL)
- return NULL;
- len = 0;
- for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
- if (global->wfd_subelem[i])
- len += wpabuf_len(global->wfd_subelem[i]);
- }
- ie = wpabuf_alloc(len);
- if (ie == NULL)
- return NULL;
- for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
- if (global->wfd_subelem[i])
- wpabuf_put_buf(ie, global->wfd_subelem[i]);
- }
- return ie;
- }
- static int wifi_display_update_wfd_ie(struct wpa_global *global)
- {
- struct wpabuf *ie, *buf;
- size_t len, plen;
- if (global->p2p == NULL)
- return 0;
- wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
- if (!global->wifi_display) {
- wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
- "include WFD IE");
- p2p_set_wfd_ie_beacon(global->p2p, NULL);
- p2p_set_wfd_ie_probe_req(global->p2p, NULL);
- p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
- p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
- p2p_set_wfd_ie_invitation(global->p2p, NULL);
- p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
- p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
- p2p_set_wfd_ie_go_neg(global->p2p, NULL);
- p2p_set_wfd_dev_info(global->p2p, NULL);
- p2p_set_wfd_r2_dev_info(global->p2p, NULL);
- p2p_set_wfd_assoc_bssid(global->p2p, NULL);
- p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
- return 0;
- }
- p2p_set_wfd_dev_info(global->p2p,
- global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
- p2p_set_wfd_r2_dev_info(
- global->p2p, global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
- p2p_set_wfd_assoc_bssid(
- global->p2p,
- global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
- p2p_set_wfd_coupled_sink_info(
- global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
- /*
- * WFD IE is included in number of management frames. Two different
- * sets of subelements are included depending on the frame:
- *
- * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
- * Provision Discovery Req:
- * WFD Device Info
- * [Associated BSSID]
- * [Coupled Sink Info]
- *
- * Probe Request:
- * WFD Device Info
- * [Associated BSSID]
- * [Coupled Sink Info]
- * [WFD Extended Capability]
- *
- * Probe Response:
- * WFD Device Info
- * [Associated BSSID]
- * [Coupled Sink Info]
- * [WFD Extended Capability]
- * [WFD Session Info]
- *
- * (Re)Association Response, P2P Invitation Req/Resp,
- * Provision Discovery Resp:
- * WFD Device Info
- * [Associated BSSID]
- * [Coupled Sink Info]
- * [WFD Session Info]
- */
- len = 0;
- if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
- len += wpabuf_len(global->wfd_subelem[
- WFD_SUBELEM_DEVICE_INFO]);
- if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
- len += wpabuf_len(global->wfd_subelem[
- WFD_SUBELEM_R2_DEVICE_INFO]);
- if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
- len += wpabuf_len(global->wfd_subelem[
- WFD_SUBELEM_ASSOCIATED_BSSID]);
- if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
- len += wpabuf_len(global->wfd_subelem[
- WFD_SUBELEM_COUPLED_SINK]);
- if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
- len += wpabuf_len(global->wfd_subelem[
- WFD_SUBELEM_SESSION_INFO]);
- if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
- len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
- buf = wpabuf_alloc(len);
- if (buf == NULL)
- return -1;
- if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
- if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
- if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
- wpabuf_put_buf(buf, global->wfd_subelem[
- WFD_SUBELEM_ASSOCIATED_BSSID]);
- if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
- p2p_set_wfd_ie_beacon(global->p2p, ie);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
- ie);
- p2p_set_wfd_ie_assoc_req(global->p2p, ie);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
- p2p_set_wfd_ie_go_neg(global->p2p, ie);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
- "Request", ie);
- p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
- plen = buf->used;
- if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
- p2p_set_wfd_ie_probe_req(global->p2p, ie);
- if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
- p2p_set_wfd_ie_probe_resp(global->p2p, ie);
- /* Remove WFD Extended Capability from buffer */
- buf->used = plen;
- if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
- wpabuf_put_buf(buf,
- global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
- p2p_set_wfd_ie_invitation(global->p2p, ie);
- ie = wifi_display_encaps(buf);
- wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
- "Response", ie);
- p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
- wpabuf_free(buf);
- return 0;
- }
- void wifi_display_enable(struct wpa_global *global, int enabled)
- {
- wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
- enabled ? "enabled" : "disabled");
- global->wifi_display = enabled;
- wifi_display_update_wfd_ie(global);
- }
- int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
- {
- char *pos;
- int subelem;
- size_t len;
- struct wpabuf *e;
- pos = os_strchr(cmd, ' ');
- if (pos == NULL)
- return -1;
- *pos++ = '\0';
- len = os_strlen(pos);
- if (len & 1)
- return -1;
- len /= 2;
- if (os_strcmp(cmd, "all") == 0) {
- int res;
- e = wpabuf_alloc(len);
- if (e == NULL)
- return -1;
- if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
- wpabuf_free(e);
- return -1;
- }
- res = wifi_display_subelem_set_from_ies(global, e);
- wpabuf_free(e);
- return res;
- }
- subelem = atoi(cmd);
- if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
- return -1;
- if (len == 0) {
- /* Clear subelement */
- e = NULL;
- wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
- } else {
- e = wpabuf_alloc(1 + len);
- if (e == NULL)
- return -1;
- wpabuf_put_u8(e, subelem);
- if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
- wpabuf_free(e);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
- }
- wpabuf_free(global->wfd_subelem[subelem]);
- global->wfd_subelem[subelem] = e;
- wifi_display_update_wfd_ie(global);
- return 0;
- }
- int wifi_display_subelem_set_from_ies(struct wpa_global *global,
- struct wpabuf *ie)
- {
- int subelements[MAX_WFD_SUBELEMS] = {};
- const u8 *pos, *end;
- unsigned int len, subelem;
- struct wpabuf *e;
- wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
- ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
- if (ie == NULL || wpabuf_len(ie) < 6)
- return -1;
- pos = wpabuf_head(ie);
- end = pos + wpabuf_len(ie);
- while (end > pos) {
- if (pos + 3 > end)
- break;
- len = WPA_GET_BE16(pos + 1) + 3;
- wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
- *pos, len - 3);
- if (len > (unsigned int) (end - pos))
- break;
- subelem = *pos;
- if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
- e = wpabuf_alloc_copy(pos, len);
- if (e == NULL)
- return -1;
- wpabuf_free(global->wfd_subelem[subelem]);
- global->wfd_subelem[subelem] = e;
- subelements[subelem] = 1;
- }
- pos += len;
- }
- for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
- if (subelements[subelem] == 0) {
- wpabuf_free(global->wfd_subelem[subelem]);
- global->wfd_subelem[subelem] = NULL;
- }
- }
- return wifi_display_update_wfd_ie(global);
- }
- int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
- char *buf, size_t buflen)
- {
- int subelem;
- if (os_strcmp(cmd, "all") == 0) {
- struct wpabuf *ie;
- int res;
- ie = wifi_display_get_wfd_ie(global);
- if (ie == NULL)
- return 0;
- res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
- wpabuf_len(ie));
- wpabuf_free(ie);
- return res;
- }
- subelem = atoi(cmd);
- if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
- return -1;
- if (global->wfd_subelem[subelem] == NULL)
- return 0;
- return wpa_snprintf_hex(buf, buflen,
- wpabuf_head_u8(global->wfd_subelem[subelem]) +
- 1,
- wpabuf_len(global->wfd_subelem[subelem]) - 1);
- }
- char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
- {
- char *subelem = NULL;
- const u8 *buf;
- size_t buflen;
- size_t i = 0;
- u16 elen;
- if (!wfd_subelems)
- return NULL;
- buf = wpabuf_head_u8(wfd_subelems);
- if (!buf)
- return NULL;
- buflen = wpabuf_len(wfd_subelems);
- while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
- elen = WPA_GET_BE16(buf + i + 1);
- if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen)
- break; /* truncated subelement */
- if (buf[i] == id) {
- /*
- * Limit explicitly to an arbitrary length to avoid
- * unnecessarily large allocations. In practice, this
- * is limited to maximum frame length anyway, so the
- * maximum memory allocation here is not really that
- * large. Anyway, the Wi-Fi Display subelements that
- * are fetched with this function are even shorter.
- */
- if (elen > 1000)
- break;
- subelem = os_zalloc(2 * elen + 1);
- if (!subelem)
- return NULL;
- wpa_snprintf_hex(subelem, 2 * elen + 1,
- buf + i +
- WIFI_DISPLAY_SUBELEM_HEADER_LEN,
- elen);
- break;
- }
- i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
- }
- return subelem;
- }
|