1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Direct - P2P service discovery 3e5b75505Sopenharmony_ci * Copyright (c) 2009, Atheros Communications 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 13e5b75505Sopenharmony_ci#include "common/gas.h" 14e5b75505Sopenharmony_ci#include "p2p_i.h" 15e5b75505Sopenharmony_ci#include "p2p.h" 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 19e5b75505Sopenharmony_cistatic int wfd_wsd_supported(struct wpabuf *wfd) 20e5b75505Sopenharmony_ci{ 21e5b75505Sopenharmony_ci const u8 *pos, *end; 22e5b75505Sopenharmony_ci u8 subelem; 23e5b75505Sopenharmony_ci u16 len; 24e5b75505Sopenharmony_ci 25e5b75505Sopenharmony_ci if (wfd == NULL) 26e5b75505Sopenharmony_ci return 0; 27e5b75505Sopenharmony_ci 28e5b75505Sopenharmony_ci pos = wpabuf_head(wfd); 29e5b75505Sopenharmony_ci end = pos + wpabuf_len(wfd); 30e5b75505Sopenharmony_ci 31e5b75505Sopenharmony_ci while (end - pos >= 3) { 32e5b75505Sopenharmony_ci subelem = *pos++; 33e5b75505Sopenharmony_ci len = WPA_GET_BE16(pos); 34e5b75505Sopenharmony_ci pos += 2; 35e5b75505Sopenharmony_ci if (len > end - pos) 36e5b75505Sopenharmony_ci break; 37e5b75505Sopenharmony_ci 38e5b75505Sopenharmony_ci if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) { 39e5b75505Sopenharmony_ci u16 info = WPA_GET_BE16(pos); 40e5b75505Sopenharmony_ci return !!(info & 0x0040); 41e5b75505Sopenharmony_ci } 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci pos += len; 44e5b75505Sopenharmony_ci } 45e5b75505Sopenharmony_ci 46e5b75505Sopenharmony_ci return 0; 47e5b75505Sopenharmony_ci} 48e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 49e5b75505Sopenharmony_ci 50e5b75505Sopenharmony_cistruct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, 51e5b75505Sopenharmony_ci struct p2p_device *dev) 52e5b75505Sopenharmony_ci{ 53e5b75505Sopenharmony_ci struct p2p_sd_query *q; 54e5b75505Sopenharmony_ci int wsd = 0; 55e5b75505Sopenharmony_ci int count = 0; 56e5b75505Sopenharmony_ci 57e5b75505Sopenharmony_ci if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY)) 58e5b75505Sopenharmony_ci return NULL; /* peer does not support SD */ 59e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 60e5b75505Sopenharmony_ci if (wfd_wsd_supported(dev->info.wfd_subelems)) 61e5b75505Sopenharmony_ci wsd = 1; 62e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 63e5b75505Sopenharmony_ci 64e5b75505Sopenharmony_ci for (q = p2p->sd_queries; q; q = q->next) { 65e5b75505Sopenharmony_ci /* Use WSD only if the peer indicates support or it */ 66e5b75505Sopenharmony_ci if (q->wsd && !wsd) 67e5b75505Sopenharmony_ci continue; 68e5b75505Sopenharmony_ci /* if the query is a broadcast query */ 69e5b75505Sopenharmony_ci if (q->for_all_peers) { 70e5b75505Sopenharmony_ci /* 71e5b75505Sopenharmony_ci * check if there are any broadcast queries pending for 72e5b75505Sopenharmony_ci * this device 73e5b75505Sopenharmony_ci */ 74e5b75505Sopenharmony_ci if (dev->sd_pending_bcast_queries <= 0) 75e5b75505Sopenharmony_ci return NULL; 76e5b75505Sopenharmony_ci /* query number that needs to be send to the device */ 77e5b75505Sopenharmony_ci if (count == dev->sd_pending_bcast_queries - 1) 78e5b75505Sopenharmony_ci goto found; 79e5b75505Sopenharmony_ci count++; 80e5b75505Sopenharmony_ci } 81e5b75505Sopenharmony_ci if (!q->for_all_peers && 82e5b75505Sopenharmony_ci os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) == 83e5b75505Sopenharmony_ci 0) 84e5b75505Sopenharmony_ci goto found; 85e5b75505Sopenharmony_ci } 86e5b75505Sopenharmony_ci 87e5b75505Sopenharmony_ci return NULL; 88e5b75505Sopenharmony_ci 89e5b75505Sopenharmony_cifound: 90e5b75505Sopenharmony_ci if (dev->sd_reqs > 100) { 91e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too many SD request attempts to " MACSTR 92e5b75505Sopenharmony_ci " - skip remaining queries", 93e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 94e5b75505Sopenharmony_ci return NULL; 95e5b75505Sopenharmony_ci } 96e5b75505Sopenharmony_ci return q; 97e5b75505Sopenharmony_ci} 98e5b75505Sopenharmony_ci 99e5b75505Sopenharmony_ci 100e5b75505Sopenharmony_cistatic void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number) 101e5b75505Sopenharmony_ci{ 102e5b75505Sopenharmony_ci struct p2p_device *dev; 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_ci p2p->num_p2p_sd_queries--; 105e5b75505Sopenharmony_ci dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { 106e5b75505Sopenharmony_ci if (query_number <= dev->sd_pending_bcast_queries - 1) { 107e5b75505Sopenharmony_ci /* 108e5b75505Sopenharmony_ci * Query not yet sent to the device and it is to be 109e5b75505Sopenharmony_ci * removed, so update the pending count. 110e5b75505Sopenharmony_ci */ 111e5b75505Sopenharmony_ci dev->sd_pending_bcast_queries--; 112e5b75505Sopenharmony_ci } 113e5b75505Sopenharmony_ci } 114e5b75505Sopenharmony_ci} 115e5b75505Sopenharmony_ci 116e5b75505Sopenharmony_ci 117e5b75505Sopenharmony_cistatic int p2p_unlink_sd_query(struct p2p_data *p2p, 118e5b75505Sopenharmony_ci struct p2p_sd_query *query) 119e5b75505Sopenharmony_ci{ 120e5b75505Sopenharmony_ci struct p2p_sd_query *q, *prev; 121e5b75505Sopenharmony_ci int query_number = 0; 122e5b75505Sopenharmony_ci 123e5b75505Sopenharmony_ci q = p2p->sd_queries; 124e5b75505Sopenharmony_ci prev = NULL; 125e5b75505Sopenharmony_ci while (q) { 126e5b75505Sopenharmony_ci if (q == query) { 127e5b75505Sopenharmony_ci /* If the query is a broadcast query, decrease one from 128e5b75505Sopenharmony_ci * all the devices */ 129e5b75505Sopenharmony_ci if (query->for_all_peers) 130e5b75505Sopenharmony_ci p2p_decrease_sd_bc_queries(p2p, query_number); 131e5b75505Sopenharmony_ci if (prev) 132e5b75505Sopenharmony_ci prev->next = q->next; 133e5b75505Sopenharmony_ci else 134e5b75505Sopenharmony_ci p2p->sd_queries = q->next; 135e5b75505Sopenharmony_ci if (p2p->sd_query == query) 136e5b75505Sopenharmony_ci p2p->sd_query = NULL; 137e5b75505Sopenharmony_ci return 1; 138e5b75505Sopenharmony_ci } 139e5b75505Sopenharmony_ci if (q->for_all_peers) 140e5b75505Sopenharmony_ci query_number++; 141e5b75505Sopenharmony_ci prev = q; 142e5b75505Sopenharmony_ci q = q->next; 143e5b75505Sopenharmony_ci } 144e5b75505Sopenharmony_ci return 0; 145e5b75505Sopenharmony_ci} 146e5b75505Sopenharmony_ci 147e5b75505Sopenharmony_ci 148e5b75505Sopenharmony_cistatic void p2p_free_sd_query(struct p2p_sd_query *q) 149e5b75505Sopenharmony_ci{ 150e5b75505Sopenharmony_ci if (q == NULL) 151e5b75505Sopenharmony_ci return; 152e5b75505Sopenharmony_ci wpabuf_free(q->tlvs); 153e5b75505Sopenharmony_ci os_free(q); 154e5b75505Sopenharmony_ci} 155e5b75505Sopenharmony_ci 156e5b75505Sopenharmony_ci 157e5b75505Sopenharmony_civoid p2p_free_sd_queries(struct p2p_data *p2p) 158e5b75505Sopenharmony_ci{ 159e5b75505Sopenharmony_ci struct p2p_sd_query *q, *prev; 160e5b75505Sopenharmony_ci q = p2p->sd_queries; 161e5b75505Sopenharmony_ci p2p->sd_queries = NULL; 162e5b75505Sopenharmony_ci while (q) { 163e5b75505Sopenharmony_ci prev = q; 164e5b75505Sopenharmony_ci q = q->next; 165e5b75505Sopenharmony_ci p2p_free_sd_query(prev); 166e5b75505Sopenharmony_ci } 167e5b75505Sopenharmony_ci p2p->num_p2p_sd_queries = 0; 168e5b75505Sopenharmony_ci} 169e5b75505Sopenharmony_ci 170e5b75505Sopenharmony_ci 171e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_sd_query(u16 update_indic, 172e5b75505Sopenharmony_ci struct wpabuf *tlvs) 173e5b75505Sopenharmony_ci{ 174e5b75505Sopenharmony_ci struct wpabuf *buf; 175e5b75505Sopenharmony_ci u8 *len_pos; 176e5b75505Sopenharmony_ci 177e5b75505Sopenharmony_ci buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs)); 178e5b75505Sopenharmony_ci if (buf == NULL) 179e5b75505Sopenharmony_ci return NULL; 180e5b75505Sopenharmony_ci 181e5b75505Sopenharmony_ci /* ANQP Query Request Frame */ 182e5b75505Sopenharmony_ci len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 183e5b75505Sopenharmony_ci wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 184e5b75505Sopenharmony_ci wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */ 185e5b75505Sopenharmony_ci wpabuf_put_buf(buf, tlvs); 186e5b75505Sopenharmony_ci gas_anqp_set_element_len(buf, len_pos); 187e5b75505Sopenharmony_ci 188e5b75505Sopenharmony_ci gas_anqp_set_len(buf); 189e5b75505Sopenharmony_ci 190e5b75505Sopenharmony_ci return buf; 191e5b75505Sopenharmony_ci} 192e5b75505Sopenharmony_ci 193e5b75505Sopenharmony_ci 194e5b75505Sopenharmony_cistatic void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst, 195e5b75505Sopenharmony_ci u8 dialog_token, int freq) 196e5b75505Sopenharmony_ci{ 197e5b75505Sopenharmony_ci struct wpabuf *req; 198e5b75505Sopenharmony_ci 199e5b75505Sopenharmony_ci req = gas_build_comeback_req(dialog_token); 200e5b75505Sopenharmony_ci if (req == NULL) 201e5b75505Sopenharmony_ci return; 202e5b75505Sopenharmony_ci 203e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_NO_PENDING_ACTION; 204e5b75505Sopenharmony_ci if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst, 205e5b75505Sopenharmony_ci wpabuf_head(req), wpabuf_len(req), 200) < 0) 206e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 207e5b75505Sopenharmony_ci 208e5b75505Sopenharmony_ci wpabuf_free(req); 209e5b75505Sopenharmony_ci} 210e5b75505Sopenharmony_ci 211e5b75505Sopenharmony_ci 212e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, 213e5b75505Sopenharmony_ci u16 comeback_delay, 214e5b75505Sopenharmony_ci u16 update_indic, 215e5b75505Sopenharmony_ci const struct wpabuf *tlvs) 216e5b75505Sopenharmony_ci{ 217e5b75505Sopenharmony_ci struct wpabuf *buf; 218e5b75505Sopenharmony_ci u8 *len_pos; 219e5b75505Sopenharmony_ci 220e5b75505Sopenharmony_ci buf = gas_anqp_build_initial_resp(dialog_token, status_code, 221e5b75505Sopenharmony_ci comeback_delay, 222e5b75505Sopenharmony_ci 100 + (tlvs ? wpabuf_len(tlvs) : 0)); 223e5b75505Sopenharmony_ci if (buf == NULL) 224e5b75505Sopenharmony_ci return NULL; 225e5b75505Sopenharmony_ci 226e5b75505Sopenharmony_ci if (tlvs) { 227e5b75505Sopenharmony_ci /* ANQP Query Response Frame */ 228e5b75505Sopenharmony_ci len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); 229e5b75505Sopenharmony_ci wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 230e5b75505Sopenharmony_ci /* Service Update Indicator */ 231e5b75505Sopenharmony_ci wpabuf_put_le16(buf, update_indic); 232e5b75505Sopenharmony_ci wpabuf_put_buf(buf, tlvs); 233e5b75505Sopenharmony_ci gas_anqp_set_element_len(buf, len_pos); 234e5b75505Sopenharmony_ci } 235e5b75505Sopenharmony_ci 236e5b75505Sopenharmony_ci gas_anqp_set_len(buf); 237e5b75505Sopenharmony_ci 238e5b75505Sopenharmony_ci return buf; 239e5b75505Sopenharmony_ci} 240e5b75505Sopenharmony_ci 241e5b75505Sopenharmony_ci 242e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, 243e5b75505Sopenharmony_ci u16 status_code, 244e5b75505Sopenharmony_ci u16 update_indic, 245e5b75505Sopenharmony_ci const u8 *data, size_t len, 246e5b75505Sopenharmony_ci u8 frag_id, u8 more, 247e5b75505Sopenharmony_ci u16 total_len) 248e5b75505Sopenharmony_ci{ 249e5b75505Sopenharmony_ci struct wpabuf *buf; 250e5b75505Sopenharmony_ci 251e5b75505Sopenharmony_ci buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id, 252e5b75505Sopenharmony_ci more, 0, 100 + len); 253e5b75505Sopenharmony_ci if (buf == NULL) 254e5b75505Sopenharmony_ci return NULL; 255e5b75505Sopenharmony_ci 256e5b75505Sopenharmony_ci if (frag_id == 0) { 257e5b75505Sopenharmony_ci /* ANQP Query Response Frame */ 258e5b75505Sopenharmony_ci wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */ 259e5b75505Sopenharmony_ci wpabuf_put_le16(buf, 3 + 1 + 2 + total_len); 260e5b75505Sopenharmony_ci wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); 261e5b75505Sopenharmony_ci /* Service Update Indicator */ 262e5b75505Sopenharmony_ci wpabuf_put_le16(buf, update_indic); 263e5b75505Sopenharmony_ci } 264e5b75505Sopenharmony_ci 265e5b75505Sopenharmony_ci wpabuf_put_data(buf, data, len); 266e5b75505Sopenharmony_ci gas_anqp_set_len(buf); 267e5b75505Sopenharmony_ci 268e5b75505Sopenharmony_ci return buf; 269e5b75505Sopenharmony_ci} 270e5b75505Sopenharmony_ci 271e5b75505Sopenharmony_ci 272e5b75505Sopenharmony_ciint p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) 273e5b75505Sopenharmony_ci{ 274e5b75505Sopenharmony_ci struct wpabuf *req; 275e5b75505Sopenharmony_ci int ret = 0; 276e5b75505Sopenharmony_ci struct p2p_sd_query *query; 277e5b75505Sopenharmony_ci int freq; 278e5b75505Sopenharmony_ci unsigned int wait_time; 279e5b75505Sopenharmony_ci 280e5b75505Sopenharmony_ci freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; 281e5b75505Sopenharmony_ci if (freq <= 0) { 282e5b75505Sopenharmony_ci p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " 283e5b75505Sopenharmony_ci MACSTR " to send SD Request", 284e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 285e5b75505Sopenharmony_ci return -1; 286e5b75505Sopenharmony_ci } 287e5b75505Sopenharmony_ci 288e5b75505Sopenharmony_ci query = p2p_pending_sd_req(p2p, dev); 289e5b75505Sopenharmony_ci if (query == NULL) 290e5b75505Sopenharmony_ci return -1; 291e5b75505Sopenharmony_ci if (p2p->state == P2P_SEARCH && 292e5b75505Sopenharmony_ci os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr, 293e5b75505Sopenharmony_ci ETH_ALEN) == 0) { 294e5b75505Sopenharmony_ci p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR 295e5b75505Sopenharmony_ci " due to it being the first no-ACK peer in this search iteration", 296e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 297e5b75505Sopenharmony_ci return -2; 298e5b75505Sopenharmony_ci } 299e5b75505Sopenharmony_ci 300e5b75505Sopenharmony_ci p2p_dbg(p2p, "Start Service Discovery with " MACSTR, 301e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 302e5b75505Sopenharmony_ci 303e5b75505Sopenharmony_ci req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs); 304e5b75505Sopenharmony_ci if (req == NULL) 305e5b75505Sopenharmony_ci return -1; 306e5b75505Sopenharmony_ci 307e5b75505Sopenharmony_ci dev->sd_reqs++; 308e5b75505Sopenharmony_ci p2p->sd_peer = dev; 309e5b75505Sopenharmony_ci p2p->sd_query = query; 310e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_PENDING_SD; 311e5b75505Sopenharmony_ci 312e5b75505Sopenharmony_ci wait_time = 5000; 313e5b75505Sopenharmony_ci if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen) 314e5b75505Sopenharmony_ci wait_time = p2p->cfg->max_listen; 315e5b75505Sopenharmony_ci if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, 316e5b75505Sopenharmony_ci p2p->cfg->dev_addr, dev->info.p2p_device_addr, 317e5b75505Sopenharmony_ci wpabuf_head(req), wpabuf_len(req), wait_time) < 0) { 318e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 319e5b75505Sopenharmony_ci ret = -1; 320e5b75505Sopenharmony_ci } 321e5b75505Sopenharmony_ci 322e5b75505Sopenharmony_ci wpabuf_free(req); 323e5b75505Sopenharmony_ci 324e5b75505Sopenharmony_ci return ret; 325e5b75505Sopenharmony_ci} 326e5b75505Sopenharmony_ci 327e5b75505Sopenharmony_ci 328e5b75505Sopenharmony_civoid p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, 329e5b75505Sopenharmony_ci const u8 *data, size_t len, int rx_freq) 330e5b75505Sopenharmony_ci{ 331e5b75505Sopenharmony_ci const u8 *pos = data; 332e5b75505Sopenharmony_ci const u8 *end = data + len; 333e5b75505Sopenharmony_ci const u8 *next; 334e5b75505Sopenharmony_ci u8 dialog_token; 335e5b75505Sopenharmony_ci u16 slen; 336e5b75505Sopenharmony_ci int freq; 337e5b75505Sopenharmony_ci u16 update_indic; 338e5b75505Sopenharmony_ci 339e5b75505Sopenharmony_ci 340e5b75505Sopenharmony_ci if (p2p->cfg->sd_request == NULL) 341e5b75505Sopenharmony_ci return; 342e5b75505Sopenharmony_ci 343e5b75505Sopenharmony_ci if (rx_freq > 0) 344e5b75505Sopenharmony_ci freq = rx_freq; 345e5b75505Sopenharmony_ci else 346e5b75505Sopenharmony_ci freq = p2p_channel_to_freq(p2p->cfg->reg_class, 347e5b75505Sopenharmony_ci p2p->cfg->channel); 348e5b75505Sopenharmony_ci if (freq < 0) 349e5b75505Sopenharmony_ci return; 350e5b75505Sopenharmony_ci 351e5b75505Sopenharmony_ci if (len < 1 + 2) 352e5b75505Sopenharmony_ci return; 353e5b75505Sopenharmony_ci 354e5b75505Sopenharmony_ci dialog_token = *pos++; 355e5b75505Sopenharmony_ci p2p_dbg(p2p, "GAS Initial Request from " MACSTR 356e5b75505Sopenharmony_ci " (dialog token %u, freq %d)", 357e5b75505Sopenharmony_ci MAC2STR(sa), dialog_token, rx_freq); 358e5b75505Sopenharmony_ci 359e5b75505Sopenharmony_ci if (*pos != WLAN_EID_ADV_PROTO) { 360e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos); 361e5b75505Sopenharmony_ci return; 362e5b75505Sopenharmony_ci } 363e5b75505Sopenharmony_ci pos++; 364e5b75505Sopenharmony_ci 365e5b75505Sopenharmony_ci slen = *pos++; 366e5b75505Sopenharmony_ci if (slen > end - pos || slen < 2) { 367e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid IE in GAS Initial Request"); 368e5b75505Sopenharmony_ci return; 369e5b75505Sopenharmony_ci } 370e5b75505Sopenharmony_ci next = pos + slen; 371e5b75505Sopenharmony_ci pos++; /* skip QueryRespLenLimit and PAME-BI */ 372e5b75505Sopenharmony_ci 373e5b75505Sopenharmony_ci if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 374e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", 375e5b75505Sopenharmony_ci *pos); 376e5b75505Sopenharmony_ci return; 377e5b75505Sopenharmony_ci } 378e5b75505Sopenharmony_ci 379e5b75505Sopenharmony_ci pos = next; 380e5b75505Sopenharmony_ci /* Query Request */ 381e5b75505Sopenharmony_ci if (end - pos < 2) 382e5b75505Sopenharmony_ci return; 383e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 384e5b75505Sopenharmony_ci pos += 2; 385e5b75505Sopenharmony_ci if (slen > end - pos) 386e5b75505Sopenharmony_ci return; 387e5b75505Sopenharmony_ci end = pos + slen; 388e5b75505Sopenharmony_ci 389e5b75505Sopenharmony_ci /* ANQP Query Request */ 390e5b75505Sopenharmony_ci if (end - pos < 4) 391e5b75505Sopenharmony_ci return; 392e5b75505Sopenharmony_ci if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { 393e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); 394e5b75505Sopenharmony_ci return; 395e5b75505Sopenharmony_ci } 396e5b75505Sopenharmony_ci pos += 2; 397e5b75505Sopenharmony_ci 398e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 399e5b75505Sopenharmony_ci pos += 2; 400e5b75505Sopenharmony_ci if (slen > end - pos || slen < 3 + 1) { 401e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid ANQP Query Request length"); 402e5b75505Sopenharmony_ci return; 403e5b75505Sopenharmony_ci } 404e5b75505Sopenharmony_ci 405e5b75505Sopenharmony_ci if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { 406e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", 407e5b75505Sopenharmony_ci WPA_GET_BE32(pos)); 408e5b75505Sopenharmony_ci return; 409e5b75505Sopenharmony_ci } 410e5b75505Sopenharmony_ci pos += 4; 411e5b75505Sopenharmony_ci 412e5b75505Sopenharmony_ci if (end - pos < 2) 413e5b75505Sopenharmony_ci return; 414e5b75505Sopenharmony_ci update_indic = WPA_GET_LE16(pos); 415e5b75505Sopenharmony_ci p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); 416e5b75505Sopenharmony_ci pos += 2; 417e5b75505Sopenharmony_ci 418e5b75505Sopenharmony_ci p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token, 419e5b75505Sopenharmony_ci update_indic, pos, end - pos); 420e5b75505Sopenharmony_ci /* the response will be indicated with a call to p2p_sd_response() */ 421e5b75505Sopenharmony_ci} 422e5b75505Sopenharmony_ci 423e5b75505Sopenharmony_ci 424e5b75505Sopenharmony_civoid p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, 425e5b75505Sopenharmony_ci u8 dialog_token, const struct wpabuf *resp_tlvs) 426e5b75505Sopenharmony_ci{ 427e5b75505Sopenharmony_ci struct wpabuf *resp; 428e5b75505Sopenharmony_ci size_t max_len; 429e5b75505Sopenharmony_ci unsigned int wait_time = 200; 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_ci /* 432e5b75505Sopenharmony_ci * In the 60 GHz, we have a smaller maximum frame length for management 433e5b75505Sopenharmony_ci * frames. 434e5b75505Sopenharmony_ci */ 435e5b75505Sopenharmony_ci max_len = (freq > 56160) ? 928 : 1400; 436e5b75505Sopenharmony_ci 437e5b75505Sopenharmony_ci /* TODO: fix the length limit to match with the maximum frame length */ 438e5b75505Sopenharmony_ci if (wpabuf_len(resp_tlvs) > max_len) { 439e5b75505Sopenharmony_ci p2p_dbg(p2p, "SD response long enough to require fragmentation"); 440e5b75505Sopenharmony_ci if (p2p->sd_resp) { 441e5b75505Sopenharmony_ci /* 442e5b75505Sopenharmony_ci * TODO: Could consider storing the fragmented response 443e5b75505Sopenharmony_ci * separately for each peer to avoid having to drop old 444e5b75505Sopenharmony_ci * one if there is more than one pending SD query. 445e5b75505Sopenharmony_ci * Though, that would eat more memory, so there are 446e5b75505Sopenharmony_ci * also benefits to just using a single buffer. 447e5b75505Sopenharmony_ci */ 448e5b75505Sopenharmony_ci p2p_dbg(p2p, "Drop previous SD response"); 449e5b75505Sopenharmony_ci wpabuf_free(p2p->sd_resp); 450e5b75505Sopenharmony_ci } 451e5b75505Sopenharmony_ci p2p->sd_resp = wpabuf_dup(resp_tlvs); 452e5b75505Sopenharmony_ci if (p2p->sd_resp == NULL) { 453e5b75505Sopenharmony_ci p2p_err(p2p, "Failed to allocate SD response fragmentation area"); 454e5b75505Sopenharmony_ci return; 455e5b75505Sopenharmony_ci } 456e5b75505Sopenharmony_ci os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN); 457e5b75505Sopenharmony_ci p2p->sd_resp_dialog_token = dialog_token; 458e5b75505Sopenharmony_ci p2p->sd_resp_pos = 0; 459e5b75505Sopenharmony_ci p2p->sd_frag_id = 0; 460e5b75505Sopenharmony_ci resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS, 461e5b75505Sopenharmony_ci 1, p2p->srv_update_indic, NULL); 462e5b75505Sopenharmony_ci } else { 463e5b75505Sopenharmony_ci p2p_dbg(p2p, "SD response fits in initial response"); 464e5b75505Sopenharmony_ci wait_time = 0; /* no more SD frames in the sequence */ 465e5b75505Sopenharmony_ci resp = p2p_build_sd_response(dialog_token, 466e5b75505Sopenharmony_ci WLAN_STATUS_SUCCESS, 0, 467e5b75505Sopenharmony_ci p2p->srv_update_indic, resp_tlvs); 468e5b75505Sopenharmony_ci } 469e5b75505Sopenharmony_ci if (resp == NULL) 470e5b75505Sopenharmony_ci return; 471e5b75505Sopenharmony_ci 472e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_NO_PENDING_ACTION; 473e5b75505Sopenharmony_ci if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, 474e5b75505Sopenharmony_ci p2p->cfg->dev_addr, 475e5b75505Sopenharmony_ci wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0) 476e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 477e5b75505Sopenharmony_ci 478e5b75505Sopenharmony_ci wpabuf_free(resp); 479e5b75505Sopenharmony_ci} 480e5b75505Sopenharmony_ci 481e5b75505Sopenharmony_ci 482e5b75505Sopenharmony_civoid p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, 483e5b75505Sopenharmony_ci const u8 *data, size_t len, int rx_freq) 484e5b75505Sopenharmony_ci{ 485e5b75505Sopenharmony_ci const u8 *pos = data; 486e5b75505Sopenharmony_ci const u8 *end = data + len; 487e5b75505Sopenharmony_ci const u8 *next; 488e5b75505Sopenharmony_ci u8 dialog_token; 489e5b75505Sopenharmony_ci u16 status_code; 490e5b75505Sopenharmony_ci u16 comeback_delay; 491e5b75505Sopenharmony_ci u16 slen; 492e5b75505Sopenharmony_ci u16 update_indic; 493e5b75505Sopenharmony_ci 494e5b75505Sopenharmony_ci if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || 495e5b75505Sopenharmony_ci os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { 496e5b75505Sopenharmony_ci p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from " 497e5b75505Sopenharmony_ci MACSTR, MAC2STR(sa)); 498e5b75505Sopenharmony_ci return; 499e5b75505Sopenharmony_ci } 500e5b75505Sopenharmony_ci p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 501e5b75505Sopenharmony_ci p2p_clear_timeout(p2p); 502e5b75505Sopenharmony_ci 503e5b75505Sopenharmony_ci p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)", 504e5b75505Sopenharmony_ci MAC2STR(sa), (int) len); 505e5b75505Sopenharmony_ci 506e5b75505Sopenharmony_ci if (len < 5 + 2) { 507e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too short GAS Initial Response frame"); 508e5b75505Sopenharmony_ci return; 509e5b75505Sopenharmony_ci } 510e5b75505Sopenharmony_ci 511e5b75505Sopenharmony_ci dialog_token = *pos++; 512e5b75505Sopenharmony_ci /* TODO: check dialog_token match */ 513e5b75505Sopenharmony_ci status_code = WPA_GET_LE16(pos); 514e5b75505Sopenharmony_ci pos += 2; 515e5b75505Sopenharmony_ci comeback_delay = WPA_GET_LE16(pos); 516e5b75505Sopenharmony_ci pos += 2; 517e5b75505Sopenharmony_ci p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u", 518e5b75505Sopenharmony_ci dialog_token, status_code, comeback_delay); 519e5b75505Sopenharmony_ci if (status_code) { 520e5b75505Sopenharmony_ci p2p_dbg(p2p, "Service Discovery failed: status code %u", 521e5b75505Sopenharmony_ci status_code); 522e5b75505Sopenharmony_ci return; 523e5b75505Sopenharmony_ci } 524e5b75505Sopenharmony_ci 525e5b75505Sopenharmony_ci if (*pos != WLAN_EID_ADV_PROTO) { 526e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos); 527e5b75505Sopenharmony_ci return; 528e5b75505Sopenharmony_ci } 529e5b75505Sopenharmony_ci pos++; 530e5b75505Sopenharmony_ci 531e5b75505Sopenharmony_ci slen = *pos++; 532e5b75505Sopenharmony_ci if (slen > end - pos || slen < 2) { 533e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid IE in GAS Initial Response"); 534e5b75505Sopenharmony_ci return; 535e5b75505Sopenharmony_ci } 536e5b75505Sopenharmony_ci next = pos + slen; 537e5b75505Sopenharmony_ci pos++; /* skip QueryRespLenLimit and PAME-BI */ 538e5b75505Sopenharmony_ci 539e5b75505Sopenharmony_ci if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 540e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", 541e5b75505Sopenharmony_ci *pos); 542e5b75505Sopenharmony_ci return; 543e5b75505Sopenharmony_ci } 544e5b75505Sopenharmony_ci 545e5b75505Sopenharmony_ci pos = next; 546e5b75505Sopenharmony_ci /* Query Response */ 547e5b75505Sopenharmony_ci if (end - pos < 2) { 548e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too short Query Response"); 549e5b75505Sopenharmony_ci return; 550e5b75505Sopenharmony_ci } 551e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 552e5b75505Sopenharmony_ci pos += 2; 553e5b75505Sopenharmony_ci p2p_dbg(p2p, "Query Response Length: %d", slen); 554e5b75505Sopenharmony_ci if (slen > end - pos) { 555e5b75505Sopenharmony_ci p2p_dbg(p2p, "Not enough Query Response data"); 556e5b75505Sopenharmony_ci return; 557e5b75505Sopenharmony_ci } 558e5b75505Sopenharmony_ci end = pos + slen; 559e5b75505Sopenharmony_ci 560e5b75505Sopenharmony_ci if (comeback_delay) { 561e5b75505Sopenharmony_ci p2p_dbg(p2p, "Fragmented response - request fragments"); 562e5b75505Sopenharmony_ci if (p2p->sd_rx_resp) { 563e5b75505Sopenharmony_ci p2p_dbg(p2p, "Drop old SD reassembly buffer"); 564e5b75505Sopenharmony_ci wpabuf_free(p2p->sd_rx_resp); 565e5b75505Sopenharmony_ci p2p->sd_rx_resp = NULL; 566e5b75505Sopenharmony_ci } 567e5b75505Sopenharmony_ci p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); 568e5b75505Sopenharmony_ci return; 569e5b75505Sopenharmony_ci } 570e5b75505Sopenharmony_ci 571e5b75505Sopenharmony_ci /* ANQP Query Response */ 572e5b75505Sopenharmony_ci if (end - pos < 4) 573e5b75505Sopenharmony_ci return; 574e5b75505Sopenharmony_ci if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { 575e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); 576e5b75505Sopenharmony_ci return; 577e5b75505Sopenharmony_ci } 578e5b75505Sopenharmony_ci pos += 2; 579e5b75505Sopenharmony_ci 580e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 581e5b75505Sopenharmony_ci pos += 2; 582e5b75505Sopenharmony_ci if (slen > end - pos || slen < 3 + 1) { 583e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid ANQP Query Response length"); 584e5b75505Sopenharmony_ci return; 585e5b75505Sopenharmony_ci } 586e5b75505Sopenharmony_ci 587e5b75505Sopenharmony_ci if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { 588e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", 589e5b75505Sopenharmony_ci WPA_GET_BE32(pos)); 590e5b75505Sopenharmony_ci return; 591e5b75505Sopenharmony_ci } 592e5b75505Sopenharmony_ci pos += 4; 593e5b75505Sopenharmony_ci 594e5b75505Sopenharmony_ci if (end - pos < 2) 595e5b75505Sopenharmony_ci return; 596e5b75505Sopenharmony_ci update_indic = WPA_GET_LE16(pos); 597e5b75505Sopenharmony_ci p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); 598e5b75505Sopenharmony_ci pos += 2; 599e5b75505Sopenharmony_ci 600e5b75505Sopenharmony_ci p2p->sd_peer = NULL; 601e5b75505Sopenharmony_ci 602e5b75505Sopenharmony_ci if (p2p->sd_query) { 603e5b75505Sopenharmony_ci if (!p2p->sd_query->for_all_peers) { 604e5b75505Sopenharmony_ci struct p2p_sd_query *q; 605e5b75505Sopenharmony_ci p2p_dbg(p2p, "Remove completed SD query %p", 606e5b75505Sopenharmony_ci p2p->sd_query); 607e5b75505Sopenharmony_ci q = p2p->sd_query; 608e5b75505Sopenharmony_ci p2p_unlink_sd_query(p2p, p2p->sd_query); 609e5b75505Sopenharmony_ci p2p_free_sd_query(q); 610e5b75505Sopenharmony_ci } 611e5b75505Sopenharmony_ci p2p->sd_query = NULL; 612e5b75505Sopenharmony_ci } 613e5b75505Sopenharmony_ci 614e5b75505Sopenharmony_ci if (p2p->cfg->sd_response) 615e5b75505Sopenharmony_ci p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic, 616e5b75505Sopenharmony_ci pos, end - pos); 617e5b75505Sopenharmony_ci p2p_continue_find(p2p); 618e5b75505Sopenharmony_ci} 619e5b75505Sopenharmony_ci 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_civoid p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, 622e5b75505Sopenharmony_ci const u8 *data, size_t len, int rx_freq) 623e5b75505Sopenharmony_ci{ 624e5b75505Sopenharmony_ci struct wpabuf *resp; 625e5b75505Sopenharmony_ci u8 dialog_token; 626e5b75505Sopenharmony_ci size_t frag_len, max_len; 627e5b75505Sopenharmony_ci int more = 0; 628e5b75505Sopenharmony_ci unsigned int wait_time = 200; 629e5b75505Sopenharmony_ci 630e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len); 631e5b75505Sopenharmony_ci if (len < 1) 632e5b75505Sopenharmony_ci return; 633e5b75505Sopenharmony_ci dialog_token = *data; 634e5b75505Sopenharmony_ci p2p_dbg(p2p, "Dialog Token: %u", dialog_token); 635e5b75505Sopenharmony_ci if (dialog_token != p2p->sd_resp_dialog_token) { 636e5b75505Sopenharmony_ci p2p_dbg(p2p, "No pending SD response fragment for dialog token %u", 637e5b75505Sopenharmony_ci dialog_token); 638e5b75505Sopenharmony_ci return; 639e5b75505Sopenharmony_ci } 640e5b75505Sopenharmony_ci 641e5b75505Sopenharmony_ci if (p2p->sd_resp == NULL) { 642e5b75505Sopenharmony_ci p2p_dbg(p2p, "No pending SD response fragment available"); 643e5b75505Sopenharmony_ci return; 644e5b75505Sopenharmony_ci } 645e5b75505Sopenharmony_ci if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) { 646e5b75505Sopenharmony_ci p2p_dbg(p2p, "No pending SD response fragment for " MACSTR, 647e5b75505Sopenharmony_ci MAC2STR(sa)); 648e5b75505Sopenharmony_ci return; 649e5b75505Sopenharmony_ci } 650e5b75505Sopenharmony_ci 651e5b75505Sopenharmony_ci /* 652e5b75505Sopenharmony_ci * In the 60 GHz, we have a smaller maximum frame length for management 653e5b75505Sopenharmony_ci * frames. 654e5b75505Sopenharmony_ci */ 655e5b75505Sopenharmony_ci max_len = (rx_freq > 56160) ? 928 : 1400; 656e5b75505Sopenharmony_ci frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos; 657e5b75505Sopenharmony_ci if (frag_len > max_len) { 658e5b75505Sopenharmony_ci frag_len = max_len; 659e5b75505Sopenharmony_ci more = 1; 660e5b75505Sopenharmony_ci } 661e5b75505Sopenharmony_ci resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS, 662e5b75505Sopenharmony_ci p2p->srv_update_indic, 663e5b75505Sopenharmony_ci wpabuf_head_u8(p2p->sd_resp) + 664e5b75505Sopenharmony_ci p2p->sd_resp_pos, frag_len, 665e5b75505Sopenharmony_ci p2p->sd_frag_id, more, 666e5b75505Sopenharmony_ci wpabuf_len(p2p->sd_resp)); 667e5b75505Sopenharmony_ci if (resp == NULL) 668e5b75505Sopenharmony_ci return; 669e5b75505Sopenharmony_ci p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)", 670e5b75505Sopenharmony_ci p2p->sd_frag_id, more, (int) frag_len); 671e5b75505Sopenharmony_ci p2p->sd_frag_id++; 672e5b75505Sopenharmony_ci p2p->sd_resp_pos += frag_len; 673e5b75505Sopenharmony_ci 674e5b75505Sopenharmony_ci if (more) { 675e5b75505Sopenharmony_ci p2p_dbg(p2p, "%d more bytes remain to be sent", 676e5b75505Sopenharmony_ci (int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos)); 677e5b75505Sopenharmony_ci } else { 678e5b75505Sopenharmony_ci p2p_dbg(p2p, "All fragments of SD response sent"); 679e5b75505Sopenharmony_ci wpabuf_free(p2p->sd_resp); 680e5b75505Sopenharmony_ci p2p->sd_resp = NULL; 681e5b75505Sopenharmony_ci wait_time = 0; /* no more SD frames in the sequence */ 682e5b75505Sopenharmony_ci } 683e5b75505Sopenharmony_ci 684e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_NO_PENDING_ACTION; 685e5b75505Sopenharmony_ci if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr, 686e5b75505Sopenharmony_ci p2p->cfg->dev_addr, 687e5b75505Sopenharmony_ci wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0) 688e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 689e5b75505Sopenharmony_ci 690e5b75505Sopenharmony_ci wpabuf_free(resp); 691e5b75505Sopenharmony_ci} 692e5b75505Sopenharmony_ci 693e5b75505Sopenharmony_ci 694e5b75505Sopenharmony_civoid p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, 695e5b75505Sopenharmony_ci const u8 *data, size_t len, int rx_freq) 696e5b75505Sopenharmony_ci{ 697e5b75505Sopenharmony_ci const u8 *pos = data; 698e5b75505Sopenharmony_ci const u8 *end = data + len; 699e5b75505Sopenharmony_ci const u8 *next; 700e5b75505Sopenharmony_ci u8 dialog_token; 701e5b75505Sopenharmony_ci u16 status_code; 702e5b75505Sopenharmony_ci u8 frag_id; 703e5b75505Sopenharmony_ci u8 more_frags; 704e5b75505Sopenharmony_ci u16 comeback_delay; 705e5b75505Sopenharmony_ci u16 slen; 706e5b75505Sopenharmony_ci 707e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); 708e5b75505Sopenharmony_ci 709e5b75505Sopenharmony_ci if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || 710e5b75505Sopenharmony_ci os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { 711e5b75505Sopenharmony_ci p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from " 712e5b75505Sopenharmony_ci MACSTR, MAC2STR(sa)); 713e5b75505Sopenharmony_ci return; 714e5b75505Sopenharmony_ci } 715e5b75505Sopenharmony_ci p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 716e5b75505Sopenharmony_ci p2p_clear_timeout(p2p); 717e5b75505Sopenharmony_ci 718e5b75505Sopenharmony_ci p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)", 719e5b75505Sopenharmony_ci MAC2STR(sa), (int) len); 720e5b75505Sopenharmony_ci 721e5b75505Sopenharmony_ci if (len < 6 + 2) { 722e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too short GAS Comeback Response frame"); 723e5b75505Sopenharmony_ci return; 724e5b75505Sopenharmony_ci } 725e5b75505Sopenharmony_ci 726e5b75505Sopenharmony_ci dialog_token = *pos++; 727e5b75505Sopenharmony_ci /* TODO: check dialog_token match */ 728e5b75505Sopenharmony_ci status_code = WPA_GET_LE16(pos); 729e5b75505Sopenharmony_ci pos += 2; 730e5b75505Sopenharmony_ci frag_id = *pos & 0x7f; 731e5b75505Sopenharmony_ci more_frags = (*pos & 0x80) >> 7; 732e5b75505Sopenharmony_ci pos++; 733e5b75505Sopenharmony_ci comeback_delay = WPA_GET_LE16(pos); 734e5b75505Sopenharmony_ci pos += 2; 735e5b75505Sopenharmony_ci p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d " 736e5b75505Sopenharmony_ci "comeback_delay=%u", 737e5b75505Sopenharmony_ci dialog_token, status_code, frag_id, more_frags, 738e5b75505Sopenharmony_ci comeback_delay); 739e5b75505Sopenharmony_ci /* TODO: check frag_id match */ 740e5b75505Sopenharmony_ci if (status_code) { 741e5b75505Sopenharmony_ci p2p_dbg(p2p, "Service Discovery failed: status code %u", 742e5b75505Sopenharmony_ci status_code); 743e5b75505Sopenharmony_ci return; 744e5b75505Sopenharmony_ci } 745e5b75505Sopenharmony_ci 746e5b75505Sopenharmony_ci if (*pos != WLAN_EID_ADV_PROTO) { 747e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u", 748e5b75505Sopenharmony_ci *pos); 749e5b75505Sopenharmony_ci return; 750e5b75505Sopenharmony_ci } 751e5b75505Sopenharmony_ci pos++; 752e5b75505Sopenharmony_ci 753e5b75505Sopenharmony_ci slen = *pos++; 754e5b75505Sopenharmony_ci if (slen > end - pos || slen < 2) { 755e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid IE in GAS Comeback Response"); 756e5b75505Sopenharmony_ci return; 757e5b75505Sopenharmony_ci } 758e5b75505Sopenharmony_ci next = pos + slen; 759e5b75505Sopenharmony_ci pos++; /* skip QueryRespLenLimit and PAME-BI */ 760e5b75505Sopenharmony_ci 761e5b75505Sopenharmony_ci if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { 762e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", 763e5b75505Sopenharmony_ci *pos); 764e5b75505Sopenharmony_ci return; 765e5b75505Sopenharmony_ci } 766e5b75505Sopenharmony_ci 767e5b75505Sopenharmony_ci pos = next; 768e5b75505Sopenharmony_ci /* Query Response */ 769e5b75505Sopenharmony_ci if (end - pos < 2) { 770e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too short Query Response"); 771e5b75505Sopenharmony_ci return; 772e5b75505Sopenharmony_ci } 773e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 774e5b75505Sopenharmony_ci pos += 2; 775e5b75505Sopenharmony_ci p2p_dbg(p2p, "Query Response Length: %d", slen); 776e5b75505Sopenharmony_ci if (slen > end - pos) { 777e5b75505Sopenharmony_ci p2p_dbg(p2p, "Not enough Query Response data"); 778e5b75505Sopenharmony_ci return; 779e5b75505Sopenharmony_ci } 780e5b75505Sopenharmony_ci if (slen == 0) { 781e5b75505Sopenharmony_ci p2p_dbg(p2p, "No Query Response data"); 782e5b75505Sopenharmony_ci return; 783e5b75505Sopenharmony_ci } 784e5b75505Sopenharmony_ci end = pos + slen; 785e5b75505Sopenharmony_ci 786e5b75505Sopenharmony_ci if (p2p->sd_rx_resp) { 787e5b75505Sopenharmony_ci /* 788e5b75505Sopenharmony_ci * ANQP header is only included in the first fragment; rest of 789e5b75505Sopenharmony_ci * the fragments start with continue TLVs. 790e5b75505Sopenharmony_ci */ 791e5b75505Sopenharmony_ci goto skip_nqp_header; 792e5b75505Sopenharmony_ci } 793e5b75505Sopenharmony_ci 794e5b75505Sopenharmony_ci /* ANQP Query Response */ 795e5b75505Sopenharmony_ci if (end - pos < 4) 796e5b75505Sopenharmony_ci return; 797e5b75505Sopenharmony_ci if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { 798e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); 799e5b75505Sopenharmony_ci return; 800e5b75505Sopenharmony_ci } 801e5b75505Sopenharmony_ci pos += 2; 802e5b75505Sopenharmony_ci 803e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 804e5b75505Sopenharmony_ci pos += 2; 805e5b75505Sopenharmony_ci p2p_dbg(p2p, "ANQP Query Response length: %u", slen); 806e5b75505Sopenharmony_ci if (slen < 3 + 1) { 807e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid ANQP Query Response length"); 808e5b75505Sopenharmony_ci return; 809e5b75505Sopenharmony_ci } 810e5b75505Sopenharmony_ci if (end - pos < 4) 811e5b75505Sopenharmony_ci return; 812e5b75505Sopenharmony_ci 813e5b75505Sopenharmony_ci if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { 814e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", 815e5b75505Sopenharmony_ci WPA_GET_BE32(pos)); 816e5b75505Sopenharmony_ci return; 817e5b75505Sopenharmony_ci } 818e5b75505Sopenharmony_ci pos += 4; 819e5b75505Sopenharmony_ci 820e5b75505Sopenharmony_ci if (end - pos < 2) 821e5b75505Sopenharmony_ci return; 822e5b75505Sopenharmony_ci p2p->sd_rx_update_indic = WPA_GET_LE16(pos); 823e5b75505Sopenharmony_ci p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic); 824e5b75505Sopenharmony_ci pos += 2; 825e5b75505Sopenharmony_ci 826e5b75505Sopenharmony_ciskip_nqp_header: 827e5b75505Sopenharmony_ci if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) 828e5b75505Sopenharmony_ci return; 829e5b75505Sopenharmony_ci wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); 830e5b75505Sopenharmony_ci p2p_dbg(p2p, "Current SD reassembly buffer length: %u", 831e5b75505Sopenharmony_ci (unsigned int) wpabuf_len(p2p->sd_rx_resp)); 832e5b75505Sopenharmony_ci 833e5b75505Sopenharmony_ci if (more_frags) { 834e5b75505Sopenharmony_ci p2p_dbg(p2p, "More fragments remains"); 835e5b75505Sopenharmony_ci /* TODO: what would be a good size limit? */ 836e5b75505Sopenharmony_ci if (wpabuf_len(p2p->sd_rx_resp) > 64000) { 837e5b75505Sopenharmony_ci wpabuf_free(p2p->sd_rx_resp); 838e5b75505Sopenharmony_ci p2p->sd_rx_resp = NULL; 839e5b75505Sopenharmony_ci p2p_dbg(p2p, "Too long SD response - drop it"); 840e5b75505Sopenharmony_ci return; 841e5b75505Sopenharmony_ci } 842e5b75505Sopenharmony_ci p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); 843e5b75505Sopenharmony_ci return; 844e5b75505Sopenharmony_ci } 845e5b75505Sopenharmony_ci 846e5b75505Sopenharmony_ci p2p->sd_peer = NULL; 847e5b75505Sopenharmony_ci 848e5b75505Sopenharmony_ci if (p2p->sd_query) { 849e5b75505Sopenharmony_ci if (!p2p->sd_query->for_all_peers) { 850e5b75505Sopenharmony_ci struct p2p_sd_query *q; 851e5b75505Sopenharmony_ci p2p_dbg(p2p, "Remove completed SD query %p", 852e5b75505Sopenharmony_ci p2p->sd_query); 853e5b75505Sopenharmony_ci q = p2p->sd_query; 854e5b75505Sopenharmony_ci p2p_unlink_sd_query(p2p, p2p->sd_query); 855e5b75505Sopenharmony_ci p2p_free_sd_query(q); 856e5b75505Sopenharmony_ci } 857e5b75505Sopenharmony_ci p2p->sd_query = NULL; 858e5b75505Sopenharmony_ci } 859e5b75505Sopenharmony_ci 860e5b75505Sopenharmony_ci if (p2p->cfg->sd_response) 861e5b75505Sopenharmony_ci p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, 862e5b75505Sopenharmony_ci p2p->sd_rx_update_indic, 863e5b75505Sopenharmony_ci wpabuf_head(p2p->sd_rx_resp), 864e5b75505Sopenharmony_ci wpabuf_len(p2p->sd_rx_resp)); 865e5b75505Sopenharmony_ci wpabuf_free(p2p->sd_rx_resp); 866e5b75505Sopenharmony_ci p2p->sd_rx_resp = NULL; 867e5b75505Sopenharmony_ci 868e5b75505Sopenharmony_ci p2p_continue_find(p2p); 869e5b75505Sopenharmony_ci} 870e5b75505Sopenharmony_ci 871e5b75505Sopenharmony_ci 872e5b75505Sopenharmony_civoid * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, 873e5b75505Sopenharmony_ci const struct wpabuf *tlvs) 874e5b75505Sopenharmony_ci{ 875e5b75505Sopenharmony_ci struct p2p_sd_query *q; 876e5b75505Sopenharmony_ci 877e5b75505Sopenharmony_ci q = os_zalloc(sizeof(*q)); 878e5b75505Sopenharmony_ci if (q == NULL) 879e5b75505Sopenharmony_ci return NULL; 880e5b75505Sopenharmony_ci 881e5b75505Sopenharmony_ci if (dst) 882e5b75505Sopenharmony_ci os_memcpy(q->peer, dst, ETH_ALEN); 883e5b75505Sopenharmony_ci else 884e5b75505Sopenharmony_ci q->for_all_peers = 1; 885e5b75505Sopenharmony_ci 886e5b75505Sopenharmony_ci q->tlvs = wpabuf_dup(tlvs); 887e5b75505Sopenharmony_ci if (q->tlvs == NULL) { 888e5b75505Sopenharmony_ci p2p_free_sd_query(q); 889e5b75505Sopenharmony_ci return NULL; 890e5b75505Sopenharmony_ci } 891e5b75505Sopenharmony_ci 892e5b75505Sopenharmony_ci q->next = p2p->sd_queries; 893e5b75505Sopenharmony_ci p2p->sd_queries = q; 894e5b75505Sopenharmony_ci p2p_dbg(p2p, "Added SD Query %p", q); 895e5b75505Sopenharmony_ci 896e5b75505Sopenharmony_ci if (dst == NULL) { 897e5b75505Sopenharmony_ci struct p2p_device *dev; 898e5b75505Sopenharmony_ci 899e5b75505Sopenharmony_ci p2p->num_p2p_sd_queries++; 900e5b75505Sopenharmony_ci 901e5b75505Sopenharmony_ci /* Update all the devices for the newly added broadcast query */ 902e5b75505Sopenharmony_ci dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { 903e5b75505Sopenharmony_ci if (dev->sd_pending_bcast_queries <= 0) 904e5b75505Sopenharmony_ci dev->sd_pending_bcast_queries = 1; 905e5b75505Sopenharmony_ci else 906e5b75505Sopenharmony_ci dev->sd_pending_bcast_queries++; 907e5b75505Sopenharmony_ci } 908e5b75505Sopenharmony_ci } 909e5b75505Sopenharmony_ci 910e5b75505Sopenharmony_ci return q; 911e5b75505Sopenharmony_ci} 912e5b75505Sopenharmony_ci 913e5b75505Sopenharmony_ci 914e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 915e5b75505Sopenharmony_civoid * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst, 916e5b75505Sopenharmony_ci const struct wpabuf *tlvs) 917e5b75505Sopenharmony_ci{ 918e5b75505Sopenharmony_ci struct p2p_sd_query *q; 919e5b75505Sopenharmony_ci q = p2p_sd_request(p2p, dst, tlvs); 920e5b75505Sopenharmony_ci if (q) 921e5b75505Sopenharmony_ci q->wsd = 1; 922e5b75505Sopenharmony_ci return q; 923e5b75505Sopenharmony_ci} 924e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 925e5b75505Sopenharmony_ci 926e5b75505Sopenharmony_ci 927e5b75505Sopenharmony_civoid p2p_sd_service_update(struct p2p_data *p2p) 928e5b75505Sopenharmony_ci{ 929e5b75505Sopenharmony_ci p2p->srv_update_indic++; 930e5b75505Sopenharmony_ci} 931e5b75505Sopenharmony_ci 932e5b75505Sopenharmony_ci 933e5b75505Sopenharmony_ciint p2p_sd_cancel_request(struct p2p_data *p2p, void *req) 934e5b75505Sopenharmony_ci{ 935e5b75505Sopenharmony_ci if (p2p_unlink_sd_query(p2p, req)) { 936e5b75505Sopenharmony_ci p2p_dbg(p2p, "Cancel pending SD query %p", req); 937e5b75505Sopenharmony_ci p2p_free_sd_query(req); 938e5b75505Sopenharmony_ci return 0; 939e5b75505Sopenharmony_ci } 940e5b75505Sopenharmony_ci return -1; 941e5b75505Sopenharmony_ci} 942