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