wifi_display.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * wpa_supplicant - Wi-Fi Display
  3. * Copyright (c) 2011, Atheros Communications, Inc.
  4. * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
  5. *
  6. * This software may be distributed under the terms of the BSD license.
  7. * See README for more details.
  8. */
  9. #include "includes.h"
  10. #include "common.h"
  11. #include "p2p/p2p.h"
  12. #include "common/ieee802_11_defs.h"
  13. #include "wpa_supplicant_i.h"
  14. #include "wifi_display.h"
  15. #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
  16. int wifi_display_init(struct wpa_global *global)
  17. {
  18. global->wifi_display = 1;
  19. return 0;
  20. }
  21. void wifi_display_deinit(struct wpa_global *global)
  22. {
  23. int i;
  24. for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
  25. wpabuf_free(global->wfd_subelem[i]);
  26. global->wfd_subelem[i] = NULL;
  27. }
  28. }
  29. static int wifi_display_update_wfd_ie(struct wpa_global *global)
  30. {
  31. struct wpabuf *ie, *buf;
  32. size_t len, plen;
  33. wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
  34. if (!global->wifi_display) {
  35. wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
  36. "include WFD IE");
  37. p2p_set_wfd_ie_beacon(global->p2p, NULL);
  38. p2p_set_wfd_ie_probe_req(global->p2p, NULL);
  39. p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
  40. p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
  41. p2p_set_wfd_ie_invitation(global->p2p, NULL);
  42. p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
  43. p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
  44. p2p_set_wfd_ie_go_neg(global->p2p, NULL);
  45. p2p_set_wfd_dev_info(global->p2p, NULL);
  46. p2p_set_wfd_assoc_bssid(global->p2p, NULL);
  47. p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
  48. return 0;
  49. }
  50. p2p_set_wfd_dev_info(global->p2p,
  51. global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
  52. p2p_set_wfd_assoc_bssid(
  53. global->p2p,
  54. global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
  55. p2p_set_wfd_coupled_sink_info(
  56. global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
  57. /*
  58. * WFD IE is included in number of management frames. Two different
  59. * sets of subelements are included depending on the frame:
  60. *
  61. * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
  62. * Provision Discovery Req:
  63. * WFD Device Info
  64. * [Associated BSSID]
  65. * [Coupled Sink Info]
  66. *
  67. * Probe Request:
  68. * WFD Device Info
  69. * [Associated BSSID]
  70. * [Coupled Sink Info]
  71. * [WFD Extended Capability]
  72. *
  73. * Probe Response:
  74. * WFD Device Info
  75. * [Associated BSSID]
  76. * [Coupled Sink Info]
  77. * [WFD Extended Capability]
  78. * [WFD Session Info]
  79. *
  80. * (Re)Association Response, P2P Invitation Req/Resp,
  81. * Provision Discovery Resp:
  82. * WFD Device Info
  83. * [Associated BSSID]
  84. * [Coupled Sink Info]
  85. * [WFD Session Info]
  86. */
  87. len = 0;
  88. if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
  89. len += wpabuf_len(global->wfd_subelem[
  90. WFD_SUBELEM_DEVICE_INFO]);
  91. if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
  92. len += wpabuf_len(global->wfd_subelem[
  93. WFD_SUBELEM_ASSOCIATED_BSSID]);
  94. if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
  95. len += wpabuf_len(global->wfd_subelem[
  96. WFD_SUBELEM_COUPLED_SINK]);
  97. if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
  98. len += wpabuf_len(global->wfd_subelem[
  99. WFD_SUBELEM_SESSION_INFO]);
  100. if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
  101. len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
  102. buf = wpabuf_alloc(len);
  103. if (buf == NULL)
  104. return -1;
  105. if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
  106. wpabuf_put_buf(buf,
  107. global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
  108. if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
  109. wpabuf_put_buf(buf, global->wfd_subelem[
  110. WFD_SUBELEM_ASSOCIATED_BSSID]);
  111. if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
  112. wpabuf_put_buf(buf,
  113. global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
  114. ie = wifi_display_encaps(buf);
  115. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
  116. p2p_set_wfd_ie_beacon(global->p2p, ie);
  117. ie = wifi_display_encaps(buf);
  118. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
  119. ie);
  120. p2p_set_wfd_ie_assoc_req(global->p2p, ie);
  121. ie = wifi_display_encaps(buf);
  122. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
  123. p2p_set_wfd_ie_go_neg(global->p2p, ie);
  124. ie = wifi_display_encaps(buf);
  125. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
  126. "Request", ie);
  127. p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
  128. plen = buf->used;
  129. if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
  130. wpabuf_put_buf(buf,
  131. global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
  132. ie = wifi_display_encaps(buf);
  133. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
  134. p2p_set_wfd_ie_probe_req(global->p2p, ie);
  135. if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
  136. wpabuf_put_buf(buf,
  137. global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
  138. ie = wifi_display_encaps(buf);
  139. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
  140. p2p_set_wfd_ie_probe_resp(global->p2p, ie);
  141. /* Remove WFD Extended Capability from buffer */
  142. buf->used = plen;
  143. if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
  144. wpabuf_put_buf(buf,
  145. global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
  146. ie = wifi_display_encaps(buf);
  147. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
  148. p2p_set_wfd_ie_invitation(global->p2p, ie);
  149. ie = wifi_display_encaps(buf);
  150. wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
  151. "Response", ie);
  152. p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
  153. wpabuf_free(buf);
  154. return 0;
  155. }
  156. void wifi_display_enable(struct wpa_global *global, int enabled)
  157. {
  158. wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
  159. enabled ? "enabled" : "disabled");
  160. global->wifi_display = enabled;
  161. wifi_display_update_wfd_ie(global);
  162. }
  163. int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
  164. {
  165. char *pos;
  166. int subelem;
  167. size_t len;
  168. struct wpabuf *e;
  169. pos = os_strchr(cmd, ' ');
  170. if (pos == NULL)
  171. return -1;
  172. *pos++ = '\0';
  173. subelem = atoi(cmd);
  174. if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
  175. return -1;
  176. len = os_strlen(pos);
  177. if (len & 1)
  178. return -1;
  179. len /= 2;
  180. if (len == 0) {
  181. /* Clear subelement */
  182. e = NULL;
  183. wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
  184. } else {
  185. e = wpabuf_alloc(1 + len);
  186. if (e == NULL)
  187. return -1;
  188. wpabuf_put_u8(e, subelem);
  189. if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
  190. wpabuf_free(e);
  191. return -1;
  192. }
  193. wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
  194. }
  195. wpabuf_free(global->wfd_subelem[subelem]);
  196. global->wfd_subelem[subelem] = e;
  197. wifi_display_update_wfd_ie(global);
  198. return 0;
  199. }
  200. int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
  201. char *buf, size_t buflen)
  202. {
  203. int subelem;
  204. subelem = atoi(cmd);
  205. if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
  206. return -1;
  207. if (global->wfd_subelem[subelem] == NULL)
  208. return 0;
  209. return wpa_snprintf_hex(buf, buflen,
  210. wpabuf_head_u8(global->wfd_subelem[subelem]) +
  211. 1,
  212. wpabuf_len(global->wfd_subelem[subelem]) - 1);
  213. }
  214. char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
  215. {
  216. char *subelem = NULL;
  217. const u8 *buf;
  218. size_t buflen;
  219. size_t i = 0;
  220. u16 elen;
  221. if (!wfd_subelems)
  222. return NULL;
  223. buf = wpabuf_head_u8(wfd_subelems);
  224. if (!buf)
  225. return NULL;
  226. buflen = wpabuf_len(wfd_subelems);
  227. while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
  228. elen = WPA_GET_BE16(buf + i + 1);
  229. if (buf[i] == id) {
  230. subelem = os_zalloc(2 * elen + 1);
  231. if (!subelem)
  232. return NULL;
  233. wpa_snprintf_hex(subelem, 2 * elen + 1,
  234. buf + i +
  235. WIFI_DISPLAY_SUBELEM_HEADER_LEN,
  236. elen);
  237. break;
  238. }
  239. i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
  240. }
  241. return subelem;
  242. }