wifi_display.c 6.7 KB

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