wifi_display.c 7.4 KB

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