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