static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
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);
/*
work->ctx = NULL;
if (ret) {
radio_work_done(work);
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
return;
}
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
}
+static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_24ghz_social_channels &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * Search all social channels regardless of whether these have
+ * been disabled for P2P operating channel use to avoid missing
+ * peers.
+ */
+ return 1;
+ }
+ return p2p_supported_freq(wpa_s->global->p2p, freq);
+}
+
+
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
if (params->freqs == NULL)
goto fail;
for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
- if (p2p_supported_freq(wpa_s->global->p2p,
- social_channels_freq[i]))
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
params->freqs[num_channels++] =
social_channels_freq[i];
}
if (params->freqs == NULL)
goto fail;
for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
- if (p2p_supported_freq(wpa_s->global->p2p,
- social_channels_freq[i]))
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
params->freqs[num_channels++] =
social_channels_freq[i];
}
}
+static void run_wpas_p2p_disconnect(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Complete previously requested removal of %s",
+ wpa_s->ifname);
+ wpas_p2p_disconnect(wpa_s);
+}
+
+
+static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
+ struct wpa_supplicant *calling_wpa_s)
+{
+ if (calling_wpa_s == wpa_s && wpa_s &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * The calling wpa_s instance is going to be removed. Do that
+ * from an eloop callback to keep the instance available until
+ * the caller has returned. This my be needed, e.g., to provide
+ * control interface responses on the per-interface socket.
+ */
+ if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
+ wpa_s, NULL) < 0)
+ return -1;
+ return 0;
+ }
+
+ return wpas_p2p_disconnect(wpa_s);
+}
+
+
+/* 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)
{
global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+ eloop_cancel_timeout(run_wpas_p2p_disconnect, wpa_s, NULL);
wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces;
if (wpa_s && ifname)
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = NULL;
+ wpa_s->p2p_group_common_freqs_num = 0;
+
wpa_s->waiting_presence_resp = 0;
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
return;
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr,
ETH_ALEN) != 0)
continue;
return; /* already the most recent entry */
/* move the entry to mark it most recent */
- os_memmove(s->p2p_client_list + i * ETH_ALEN,
- s->p2p_client_list + (i + 1) * ETH_ALEN,
- (s->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
found = 1;
break;
}
if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
n = os_realloc_array(s->p2p_client_list,
- s->num_p2p_clients + 1, ETH_ALEN);
+ s->num_p2p_clients + 1, 2 * ETH_ALEN);
if (n == NULL)
return;
- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
s->p2p_client_list = n;
s->num_p2p_clients++;
} else if (!found && s->p2p_client_list) {
/* Not enough room for an additional entry - drop the oldest
* entry */
os_memmove(s->p2p_client_list,
- s->p2p_client_list + ETH_ALEN,
- (s->num_p2p_clients - 1) * ETH_ALEN);
+ s->p2p_client_list + 2 * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN,
addr, ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
}
if (wpa_s->parent->conf->update_config &&
#endif /* CONFIG_WPS_NFC */
} else {
u16 dev_pw_id = DEV_PW_DEFAULT;
+ if (wpa_s->p2p_wps_method == WPS_P2PS)
+ dev_pw_id = DEV_PW_P2PS_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
}
+static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
+ wpa_s->p2p_group_common_freqs_num);
+
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
+ wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
+ i, wpa_s->p2p_group_common_freqs[i]);
+}
+
+
+static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ unsigned int i, len = int_array_len(wpa_s->go_params->freq_list);
+
+ wpa_s->p2p_group_common_freqs_num = 0;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = os_calloc(len, sizeof(int));
+ if (!wpa_s->p2p_group_common_freqs)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if (!wpa_s->go_params->freq_list[i])
+ break;
+ wpa_s->p2p_group_common_freqs[i] =
+ wpa_s->go_params->freq_list[i];
+ }
+ wpa_s->p2p_group_common_freqs_num = i;
+}
+
+
static void p2p_go_configured(void *ctx, void *data)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
int network_id = -1;
+ p2p_go_save_group_common_freqs(wpa_s, params);
+ p2p_go_dump_common_freqs(wpa_s);
+
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ ssid->group_cipher = WPA_CIPHER_CCMP;
+ if (params->freq > 56160) {
+ /*
+ * Enable GCMP instead of CCMP as pairwise_cipher and
+ * group_cipher in 60 GHz.
+ */
+ ssid->pairwise_cipher = WPA_CIPHER_GCMP;
+ ssid->group_cipher = WPA_CIPHER_GCMP;
+ }
if (os_strlen(params->passphrase) > 0) {
ssid->passphrase = os_strdup(params->passphrase);
if (ssid->passphrase == NULL) {
d->dtim_period = s->dtim_period;
d->disassoc_low_ack = s->disassoc_low_ack;
d->disable_scan_offload = s->disable_scan_offload;
+ d->passive_scan = s->passive_scan;
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
if (os_strlen(ifname) >= IFNAMSIZ &&
os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+ int res;
+
/* Try to avoid going over the IFNAMSIZ length limit */
- os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ res = os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ if (os_snprintf_error(len, res) && len)
+ ifname[len - 1] = '\0';
}
}
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 */
{
struct wpa_supplicant *wpa_s = work->wpa_s;
struct wpas_p2p_listen_work *lwork = work->ctx;
+ unsigned int duration;
if (deinit) {
if (work->started) {
wpa_s->pending_listen_freq = lwork->freq;
wpa_s->pending_listen_duration = lwork->duration;
- if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
- {
+ duration = lwork->duration;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ duration, duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
"state", lwork->freq);
}
-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)
{
u8 empty_dev_type[8];
unsigned int generated_pin = 0;
struct wpa_supplicant *group = NULL;
+ int res;
if (group_id) {
for (group = wpa_s->global->ifaces; group; group = group->next)
os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
pri_dev_type = empty_dev_type;
}
- os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s",
- MAC2STR(dev_addr),
- wps_dev_type_bin2str(pri_dev_type, devtype,
- sizeof(devtype)),
- dev_name, supp_config_methods, dev_capab, group_capab,
- group ? " group=" : "",
- group ? group->ifname : "");
+ res = os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s' config_methods=0x%x "
+ "dev_capab=0x%x group_capab=0x%x%s%s",
+ MAC2STR(dev_addr),
+ wps_dev_type_bin2str(pri_dev_type, devtype,
+ sizeof(devtype)),
+ dev_name, supp_config_methods, dev_capab, group_capab,
+ group ? " group=" : "",
+ group ? group->ifname : "");
+ if (os_snprintf_error(sizeof(params), res))
+ wpa_printf(MSG_DEBUG, "P2P: PD Request event truncated");
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
}
if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
- wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
- os_snprintf(params, sizeof(params), " peer_go=%d",
- wpa_s->pending_pd_use == AUTO_PD_JOIN);
- else
+ wpa_s->pending_pd_use == AUTO_PD_GO_NEG) {
+ int res;
+
+ res = os_snprintf(params, sizeof(params), " peer_go=%d",
+ wpa_s->pending_pd_use == AUTO_PD_JOIN);
+ if (os_snprintf_error(sizeof(params), res))
+ params[sizeof(params) - 1] = '\0';
+ } else
params[0] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY)
}
#ifdef CONFIG_WPS_NFC
- if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
- dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+ if (dev_pw_id >= 0 && wpa_s->p2p_nfc_tag_enabled &&
+ dev_pw_id == wpa_s->p2p_oob_dev_pw_id) {
wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
- wpa_s->parent->p2p_wps_method = WPS_NFC;
- wpa_s->parent->pending_join_wps_method = WPS_NFC;
- os_memcpy(wpa_s->parent->pending_join_dev_addr,
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memcpy(wpa_s->pending_join_dev_addr,
go_dev_addr, ETH_ALEN);
- os_memcpy(wpa_s->parent->pending_join_iface_addr,
+ os_memcpy(wpa_s->pending_join_iface_addr,
bssid, ETH_ALEN);
goto accept_inv;
}
return;
for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
- if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+ if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer,
ETH_ALEN) == 0)
break;
}
"group %d client list%s",
MAC2STR(peer), ssid->id,
inv ? " due to invitation result" : "");
- os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
- ssid->p2p_client_list + (i + 1) * ETH_ALEN,
- (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN,
+ ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
ssid->num_p2p_clients--;
if (wpa_s->parent->conf->update_config &&
wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
{
int i, cla = 0;
+ wpa_s->global->p2p_24ghz_social_channels = 1;
+
os_memset(cli_chan, 0, sizeof(*cli_chan));
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
enum chan_allowed {
- NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+ NOT_ALLOWED, NO_IR, ALLOWED
};
static int has_channel(struct wpa_global *global,
(HOSTAPD_CHAN_DISABLED |
HOSTAPD_CHAN_RADAR))
return NOT_ALLOWED;
- if (mode->channels[i].flag &
- (HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_NO_IBSS))
- return PASSIVE_ONLY;
+ if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+ return NO_IR;
return ALLOWED;
}
}
res = has_channel(wpa_s->global, mode, adj_chan, &flags);
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
- if (res == PASSIVE_ONLY)
- ret = PASSIVE_ONLY;
+ if (res == NO_IR)
+ ret = NO_IR;
if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
return NOT_ALLOWED;
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
return NOT_ALLOWED;
- if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
- return PASSIVE_ONLY;
+ if (res == NO_IR || res2 == NO_IR)
+ return NO_IR;
return res;
}
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G)
+ wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
}
reg->channel[reg->channels] = ch;
reg->channels++;
- } else if (res == PASSIVE_ONLY &&
+ } else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
char force_name[100];
int ret;
- os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
- wpa_s->ifname);
+ ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+ wpa_s->ifname);
+ if (os_snprintf_error(sizeof(ifname), ret))
+ return -1;
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
return -1;
}
p2pdev_wpa_s->parent = wpa_s;
+ wpa_s->p2p_dev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0';
return 0;
}
+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);
wpabuf_free(wpa_s->p2p_oob_dev_pw);
wpa_s->p2p_oob_dev_pw = NULL;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = NULL;
+ wpa_s->p2p_group_common_freqs_num = 0;
+
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
}
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 "
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
else if (wps_method == WPS_PIN_DISPLAY) {
ret = wps_generate_pin();
- os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
- ret);
+ res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
+ "%08d", ret);
+ if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
+ wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
} else
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u duration=%u)",
+ wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+ wpa_s->roc_waiting_drv_freq, freq, duration);
+ if (wpa_s->off_channel_freq &&
+ wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
wpa_s->pending_listen_duration);
wpa_s->pending_listen_freq = 0;
}
-static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
- unsigned int timeout)
+int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout)
{
/* Limit maximum Listen state time based on driver limitation. */
if (timeout > wpa_s->max_remain_on_chan)
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
+ if (wpa_s->p2p_long_listen > 0)
+ wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (wpa_s->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
{
struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *calling_wpa_s = wpa_s;
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
prev->current_ssid->p2p_group))
- wpas_p2p_disconnect(prev);
+ wpas_p2p_disconnect_safely(prev, calling_wpa_s);
}
return 0;
}
break;
}
- return wpas_p2p_disconnect(wpa_s);
+ return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
}
wpa_s->p2p_fallback_to_go_neg = 0;
- if (force_freq > 0) {
- freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
- if (freq < 0)
- return -1;
+ if (ssid->mode == WPAS_MODE_P2P_GO) {
+ if (force_freq > 0) {
+ freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+ if (freq < 0)
+ return -1;
+ } else {
+ freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
} else {
- freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
- if (freq < 0 || (freq > 0 && !freq_included(channels, freq)))
+ freq = neg_freq;
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
freq = 0;
}
if (wpa_s == NULL)
return -1;
+ p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
+
wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, ¶ms, 0);
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);
}
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay)
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_cnt, const char **seek_string)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
return p2p_find(wpa_s->global->p2p, timeout, type,
num_req_dev_types, req_dev_types, dev_id,
- search_delay);
+ search_delay, seek_cnt, seek_string);
}
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ /*
+ * Indicate that results have been processed so that the P2P module can
+ * continue pending tasks.
+ */
+ p2p_scan_res_handled(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
- return 0;
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Do not consider the scan results after stop_find");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore_search;
+ }
}
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
{
- if (wpas_p2p_stop_find_oper(wpa_s) > 0)
- return;
+ wpas_p2p_stop_find_oper(wpa_s);
wpas_p2p_remove_pending_group_interface(wpa_s);
}
pref_freq = 0;
}
+ /*
+ * Stop any find/listen operations before invitation and possibly
+ * connection establishment.
+ */
+ wpas_p2p_stop_find_oper(wpa_s);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
1, pref_freq, -1);
ip_addr[0] = '\0';
if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
- os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u "
- "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
- ip[0], ip[1], ip[2], ip[3],
- ip[4], ip[5], ip[6], ip[7],
- ip[8], ip[9], ip[10], ip[11]);
+ int res;
+
+ res = os_snprintf(ip_addr, sizeof(ip_addr),
+ " ip_addr=%u.%u.%u.%u "
+ "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+ ip[0], ip[1], ip[2], ip[3],
+ ip[4], ip[5], ip[6], ip[7],
+ ip[8], ip[9], ip[10], ip[11]);
+ if (os_snprintf_error(sizeof(ip_addr), res))
+ ip_addr[0] = '\0';
}
wpas_p2p_group_started(wpa_s, 0, ssid, freq,
if (iface->drv_flags &
WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
continue;
- if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ iface != wpa_s->parent)
continue;
wpa_s->cross_connect_enabled = 1;
if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
continue;
for (i = 0; i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
addr, ETH_ALEN) == 0)
return s; /* peer is P2P client in persistent
* group */
void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
{
- if (wpa_s == wpa_s->parent)
- wpas_p2p_group_remove(wpa_s, "*");
if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
"the management interface is being removed");