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