static void wpas_stop_listen(void *ctx);
static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type);
/*
}
+/* Find an interface for a P2P group where we are the GO */
+static struct wpa_supplicant *
+wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *save = NULL;
+ struct wpa_ssid *s;
+
+ if (!wpa_s)
+ return NULL;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled || !s->p2p_group ||
+ s->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ /* Prefer a group with connected clients */
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return wpa_s;
+ save = wpa_s;
+ }
+ }
+
+ /* No group with connected clients, so pick the one without (if any) */
+ return save;
+}
+
+
+/* Find an active P2P group where we are the GO */
+static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
+ u8 *bssid)
+{
+ struct wpa_ssid *s, *empty = NULL;
+
+ if (!wpa_s)
+ return 0;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled || !s->p2p_group ||
+ s->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return s;
+ empty = s;
+ }
+ }
+
+ return empty;
+}
+
+
+/* Find a persistent group where we are the GO */
+static struct wpa_ssid *
+wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *s;
+
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled == 2 && s->mode == WPAS_MODE_P2P_GO)
+ return s;
+ }
+
+ return NULL;
+}
+
+
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+{
+ struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+ struct wpa_ssid *s;
+ u8 conncap = P2PS_SETUP_NONE;
+ unsigned int owned_members = 0;
+ unsigned int owner = 0;
+ unsigned int client = 0;
+ struct wpa_supplicant *go_wpa_s;
+ struct wpa_ssid *persistent_go;
+ int p2p_no_group_iface;
+
+ wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+
+ /*
+ * For non-concurrent capable devices:
+ * If persistent_go, then no new.
+ * If GO, then no client.
+ * If client, then no GO.
+ */
+ go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+ p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
+
+ wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
+ go_wpa_s, persistent_go);
+
+ for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
+ tmp_wpa_s = tmp_wpa_s->next) {
+ for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+ tmp_wpa_s, s, s->disabled,
+ s->p2p_group, s->mode);
+ if (!s->disabled && s->p2p_group) {
+ if (s->mode == WPAS_MODE_P2P_GO) {
+ owned_members +=
+ p2p_get_group_num_members(
+ tmp_wpa_s->p2p_group);
+ owner++;
+ } else
+ client++;
+ }
+ }
+ }
+
+ /* If not concurrent, restrict our choices */
+ if (p2p_no_group_iface) {
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
+
+ if (client)
+ return P2PS_SETUP_NONE;
+
+ if (go_wpa_s) {
+ if (role == P2PS_SETUP_CLIENT ||
+ incoming == P2PS_SETUP_GROUP_OWNER ||
+ p2p_client_limit_reached(go_wpa_s->p2p_group))
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+
+ if (persistent_go) {
+ if (role == P2PS_SETUP_NONE || role == P2PS_SETUP_NEW) {
+ if (!incoming)
+ return P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_CLIENT;
+ if (incoming == P2PS_SETUP_NEW) {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ return P2PS_SETUP_CLIENT;
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+ }
+ }
+ }
+
+ /* If a required role has been specified, handle it here */
+ if (role && role != P2PS_SETUP_NEW) {
+ switch (incoming) {
+ case P2PS_SETUP_NONE:
+ case P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ conncap = role;
+ goto grp_owner;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ /*
+ * Must be a complimentary role - cannot be a client to
+ * more than one peer.
+ */
+ if (incoming == role || client)
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_CLIENT;
+
+ case P2PS_SETUP_CLIENT:
+ /* Must be a complimentary role */
+ if (incoming != role) {
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ goto grp_owner;
+ }
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+ }
+
+ /*
+ * For now, we only will support ownership of one group, and being a
+ * client of one group. Therefore, if we have either an existing GO
+ * group, or an existing client group, we will not do a new GO
+ * negotiation, but rather try to re-use the existing groups.
+ */
+ switch (incoming) {
+ case P2PS_SETUP_NONE:
+ case P2PS_SETUP_NEW:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else if (!owned_members)
+ conncap = P2PS_SETUP_NEW;
+ else if (incoming == P2PS_SETUP_NONE)
+ conncap = P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_CLIENT:
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ if (!client)
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ conncap = P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ }
+ break;
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+
+grp_owner:
+ if ((conncap & P2PS_SETUP_GROUP_OWNER) ||
+ (!incoming && (conncap & P2PS_SETUP_NEW))) {
+ if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
+ conncap &= ~P2PS_SETUP_GROUP_OWNER;
+ wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
+ owner, owned_members, conncap);
+
+ s = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (!s && !owner && p2p_no_group_iface) {
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->own_addr);
+ } else if (!s && !owner) {
+ if (wpas_p2p_add_group_interface(wpa_s,
+ WPA_IF_P2P_GO) < 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to allocate a new interface for the group");
+ return P2PS_SETUP_NONE;
+ }
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->pending_interface_addr);
+ }
+ }
+
+ return conncap;
+}
+
+
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason)
{
WFD_SUBELEM_DEVICE_INFO);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (info->p2ps_instance) {
+ char str[256];
+ const u8 *buf = wpabuf_head(info->p2ps_instance);
+ size_t len = wpabuf_len(info->p2ps_instance);
+
+ while (len) {
+ u32 id;
+ u16 methods;
+ u8 str_len;
+
+ if (len < 4 + 2 + 1)
+ break;
+ id = WPA_GET_LE32(buf);
+ buf += sizeof(u32);
+ methods = WPA_GET_BE16(buf);
+ buf += sizeof(u16);
+ str_len = *buf++;
+ if (str_len > len - 4 - 2 - 1)
+ break;
+ os_memcpy(str, buf, str_len);
+ str[str_len] = '\0';
+ buf += str_len;
+ len -= str_len + sizeof(u32) + sizeof(u16) + sizeof(u8);
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_DEVICE_FOUND MACSTR
+ " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s'"
+ " config_methods=0x%x"
+ " dev_capab=0x%x"
+ " group_capab=0x%x"
+ " adv_id=%x asp_svc=%s%s",
+ MAC2STR(addr),
+ MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(
+ info->pri_dev_type,
+ devtype, sizeof(devtype)),
+ info->device_name, methods,
+ info->dev_capab, info->group_capab,
+ id, str,
+ info->vendor_elems ?
+ " vendor_elems=1" : "");
+ }
+ goto done;
+ }
+
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
info->vendor_elems ? " vendor_elems=1" : "",
new_device);
+done:
os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
-static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
- u8 srv_trans_id)
+static void wpas_sd_add_empty(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id, u8 status)
{
u8 *len_pos;
wpabuf_put_u8(resp, srv_proto);
wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
- wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
+ wpabuf_put_u8(resp, status);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_PROTO_NOT_AVAILABLE);
+}
+
+
+static void wpas_sd_add_bad_request(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id, P2P_SD_BAD_REQUEST);
+}
+
+
+static void wpas_sd_add_not_found(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+}
+
+
static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id)
{
#endif /* CONFIG_WIFI_DISPLAY */
+static int find_p2ps_substr(struct p2ps_advertisement *adv_data,
+ const u8 *needle, size_t needle_len)
+{
+ const u8 *haystack = (const u8 *) adv_data->svc_info;
+ size_t haystack_len, i;
+
+ /* Allow search term to be empty */
+ if (!needle || !needle_len)
+ return 1;
+
+ if (!haystack)
+ return 0;
+
+ haystack_len = os_strlen(adv_data->svc_info);
+ for (i = 0; i < haystack_len; i++) {
+ if (haystack_len - i < needle_len)
+ break;
+ if (os_memcmp(haystack + i, needle, needle_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_sd_req_asp(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ struct p2ps_advertisement *adv_data;
+ const u8 *svc = &query[1];
+ const u8 *info = NULL;
+ size_t svc_len = query[0];
+ size_t info_len = 0;
+ int prefix = 0;
+ u8 *count_pos = NULL;
+ u8 *len_pos = NULL;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
+
+ if (!wpa_s->global->p2p) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Info block is optional */
+ if (svc_len + 1 < query_len) {
+ info = &svc[svc_len];
+ info_len = *info++;
+ }
+
+ /* Range check length of svc string and info block */
+ if (svc_len + (info_len ? info_len + 2 : 1) > query_len) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+ wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Detect and correct for prefix search */
+ if (svc_len && svc[svc_len - 1] == '*') {
+ prefix = 1;
+ svc_len--;
+ }
+
+ for (adv_data = p2p_get_p2ps_adv_list(wpa_s->global->p2p);
+ adv_data; adv_data = adv_data->next) {
+ /* If not a prefix match, reject length mismatches */
+ if (!prefix && svc_len != os_strlen(adv_data->svc_name))
+ continue;
+
+ /* Search each service for request */
+ if (os_memcmp(adv_data->svc_name, svc, svc_len) == 0 &&
+ find_p2ps_substr(adv_data, info, info_len)) {
+ size_t len = os_strlen(adv_data->svc_name);
+ size_t svc_info_len = 0;
+
+ if (adv_data->svc_info)
+ svc_info_len = os_strlen(adv_data->svc_info);
+
+ if (len > 0xff || svc_info_len > 0xffff)
+ return;
+
+ /* Length & Count to be filled as we go */
+ if (!len_pos && !count_pos) {
+ if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 16)
+ return;
+
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_P2PS);
+ wpabuf_put_u8(resp, srv_trans_id);
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ count_pos = wpabuf_put(resp, 1);
+ *count_pos = 0;
+ } else if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 10)
+ return;
+
+ if (svc_info_len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add Svc: %s info: %s",
+ adv_data->svc_name,
+ adv_data->svc_info);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Add Svc: %s",
+ adv_data->svc_name);
+ }
+
+ /* Advertisement ID */
+ wpabuf_put_le32(resp, adv_data->id);
+
+ /* Config Methods */
+ wpabuf_put_be16(resp, adv_data->config_methods);
+
+ /* Service Name */
+ wpabuf_put_u8(resp, (u8) len);
+ wpabuf_put_data(resp, adv_data->svc_name, len);
+
+ /* Service State */
+ wpabuf_put_u8(resp, adv_data->state);
+
+ /* Service Information */
+ wpabuf_put_le16(resp, (u16) svc_info_len);
+ wpabuf_put_data(resp, adv_data->svc_info, svc_info_len);
+
+ /* Update length and count */
+ (*count_pos)++;
+ WPA_PUT_LE16(len_pos,
+ (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
+ }
+
+ /* Return error if no matching svc found */
+ if (count_pos == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP service not found");
+ wpas_sd_add_not_found(resp, P2P_SERV_P2PS, srv_trans_id);
+ }
+}
+
+
static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
pos, tlv_end - pos);
break;
#endif /* CONFIG_WIFI_DISPLAY */
+ case P2P_SERV_P2PS:
+ wpas_sd_req_asp(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
}
+static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u8 srv_trans_id,
+ const u8 *pos, const u8 *tlv_end)
+{
+ u8 left = *pos++;
+ u32 adv_id;
+ u8 svc_status;
+ u16 config_methods;
+ char svc_str[256];
+
+ while (left-- && pos < tlv_end) {
+ char *buf = NULL;
+ size_t buf_len;
+ u8 svc_len;
+
+ /* Sanity check fixed length+svc_str */
+ if (pos + 6 >= tlv_end)
+ break;
+ svc_len = pos[6];
+ if (pos + svc_len + 10 > tlv_end)
+ break;
+
+ /* Advertisement ID */
+ adv_id = WPA_GET_LE32(pos);
+ pos += sizeof(u32);
+
+ /* Config Methods */
+ config_methods = WPA_GET_BE16(pos);
+ pos += sizeof(u16);
+
+ /* Service Name */
+ pos++; /* svc_len */
+ os_memcpy(svc_str, pos, svc_len);
+ svc_str[svc_len] = '\0';
+ pos += svc_len;
+
+ /* Service Status */
+ svc_status = *pos++;
+
+ /* Service Information Length */
+ buf_len = WPA_GET_LE16(pos);
+ pos += sizeof(u16);
+
+ /* Sanity check buffer length */
+ if (buf_len > (unsigned int) (tlv_end - pos))
+ break;
+
+ if (buf_len) {
+ buf = os_zalloc(2 * buf_len + 1);
+ if (buf) {
+ utf8_escape((const char *) pos, buf_len, buf,
+ 2 * buf_len + 1);
+ }
+ }
+
+ pos += buf_len;
+
+ if (buf) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s '%s'",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str,
+ buf);
+ os_free(buf);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str);
+ }
+ }
+}
+
+
static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len)
{
wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
pos, tlv_end - pos);
+ if (srv_proto == P2P_SERV_P2PS && pos < tlv_end) {
+ wpas_sd_p2ps_serv_response(wpa_s, sa, srv_trans_id,
+ pos, tlv_end);
+ }
+
pos = tlv_end;
}
}
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+ const char *svc_str, const char *info_substr)
+{
+ struct wpabuf *tlvs;
+ size_t plen, svc_len, substr_len = 0;
+ u64 ret;
+
+ svc_len = os_strlen(svc_str);
+ if (info_substr)
+ substr_len = os_strlen(info_substr);
+
+ if (svc_len > 0xff || substr_len > 0xff)
+ return 0;
+
+ plen = 1 + 1 + 1 + svc_len + 1 + substr_len;
+ tlvs = wpabuf_alloc(2 + plen);
+ if (tlvs == NULL)
+ return 0;
+
+ wpabuf_put_le16(tlvs, plen);
+ wpabuf_put_u8(tlvs, P2P_SERV_P2PS);
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+ wpabuf_put_u8(tlvs, (u8) svc_len); /* Service String Length */
+ wpabuf_put_data(tlvs, svc_str, svc_len);
+ wpabuf_put_u8(tlvs, (u8) substr_len); /* Info Substring Length */
+ wpabuf_put_data(tlvs, info_substr, substr_len);
+ ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+
+ return ret;
+}
+
+
#ifdef CONFIG_WIFI_DISPLAY
static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
}
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ if (adv_id == 0)
+ return 1;
+
+ if (p2p_service_p2ps_id(wpa_s->global->p2p, adv_id))
+ return 1;
+
+ return 0;
+}
+
+
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ return p2p_service_del_asp(wpa_s->global->p2p, adv_id);
+}
+
+
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s,
+ int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info)
+{
+ return p2p_service_add_asp(wpa_s->global->p2p, auto_accept, adv_id,
+ adv_str, svc_state, config_methods,
+ svc_info);
+}
+
+
int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *query, struct wpabuf *resp)
{
}
+static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
+ size_t ssid_len, u8 *go_dev_addr,
+ u8 *ret_ssid, size_t *ret_ssid_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+
+ s = wpas_p2p_get_persistent(wpa_s, addr, ssid, ssid_len);
+ if (s) {
+ os_memcpy(ret_ssid, s->ssid, s->ssid_len);
+ *ret_ssid_len = s->ssid_len;
+ os_memcpy(go_dev_addr, s->bssid, ETH_ALEN);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_get_go_info(void *ctx, u8 *intended_addr,
+ u8 *ssid, size_t *ssid_len, int *group_iface)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+ u8 bssid[ETH_ALEN];
+
+ s = wpas_p2p_group_go_ssid(wpa_s, bssid);
+ if (!s) {
+ s = wpas_p2p_get_persistent_go(wpa_s);
+ if (s)
+ os_memcpy(bssid, s->bssid, ETH_ALEN);
+ }
+
+ *group_iface = wpas_p2p_create_iface(wpa_s);
+ if (!s)
+ return 0;
+
+ os_memcpy(intended_addr, bssid, ETH_ALEN);
+ os_memcpy(ssid, s->ssid, s->ssid_len);
+ *ssid_len = s->ssid_len;
+
+ return 1;
+}
+
+
static int _wpas_p2p_in_progress(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
p2p.presence_resp = wpas_presence_resp;
p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
p2p.is_p2p_in_progress = _wpas_p2p_in_progress;
+ p2p.get_persistent_group = wpas_get_persistent_group;
+ p2p.get_go_info = wpas_get_go_info;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
MAC2STR(wpa_s->pending_join_dev_addr), join);
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr,
+ wpa_s->pending_join_dev_addr, NULL,
wpa_s->pending_pd_config_methods, join,
0, wpa_s->user_initiated_pd) < 0) {
wpa_s->p2p_auto_pd = 0;
}
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr, method, 1,
+ wpa_s->pending_join_dev_addr,
+ NULL, method, 1,
freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *config_method,
- enum wpas_p2p_prov_disc_use use)
+ enum wpas_p2p_prov_disc_use use,
+ struct p2ps_provision *p2ps_prov)
{
u16 config_methods;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->pending_pd_use = NORMAL_PD;
- if (os_strncmp(config_method, "display", 7) == 0)
+ if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
+ p2ps_prov->conncap = p2ps_group_capability(
+ wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
+ __func__, p2ps_prov->conncap,
+ p2ps_prov->adv_id, p2ps_prov->conncap,
+ p2ps_prov->status, p2ps_prov->info);
+
+ config_methods = 0;
+ } else if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
config_methods = WPS_CONFIG_KEYPAD;
config_methods = WPS_CONFIG_PUSHBUTTON;
else {
wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+ os_free(p2ps_prov);
return -1;
}
return 0;
}
- if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+ if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
+ os_free(p2ps_prov);
return -1;
+ }
- return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
+ return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, p2ps_prov,
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
0, 1);
}