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 int wifi_display_init(struct wpa_global *global) 20 { 21 global->wifi_display = 1; 22 return 0; 23 } 24 25 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 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 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 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 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