* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "wps/wps_i.h"
#include "p2p/p2p.h"
#include "ap/hostapd.h"
+#include "ap/ap_config.h"
#include "ap/p2p_hostapd.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "ap.h"
#include "config_ssid.h"
#include "config.h"
-#include "mlme.h"
#include "notify.h"
#include "scan.h"
#include "bss.h"
+#include "offchannel.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
*/
#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+#ifndef P2P_MAX_CLIENT_IDLE
+/*
+ * How many seconds to try to reconnect to the GO when connection in P2P client
+ * role has been lost.
+ */
+#define P2P_MAX_CLIENT_IDLE 10
+#endif /* P2P_MAX_CLIENT_IDLE */
+
+#ifndef P2P_MAX_INITIAL_CONN_WAIT
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
static struct wpa_supplicant *
static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method);
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join);
+static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added);
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
}
-static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int 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)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_driver_scan_params params;
int ret;
struct wpabuf *wps_ie, *ies;
int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+ size_t ielen;
+ int was_in_p2p_scan;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE);
+ wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+ wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
+ num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
return -1;
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
if (ies == NULL) {
wpabuf_free(wps_ie);
return -1;
wpabuf_put_buf(ies, wps_ie);
wpabuf_free(wps_ie);
- p2p_scan_ie(wpa_s->global->p2p, ies);
+ p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
+ params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
break;
}
+ was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ret = ieee80211_sta_req_scan(wpa_s, ¶ms);
- else
- ret = wpa_drv_scan(wpa_s, ¶ms);
+ ret = wpa_drv_scan(wpa_s, ¶ms);
wpabuf_free(ies);
- return ret;
-}
-
-
-#ifdef CONFIG_CLIENT_MLME
-static void p2p_rx_action_mlme(void *ctx, const u8 *buf, size_t len, int freq)
-{
- struct wpa_supplicant *wpa_s = ctx;
- const struct ieee80211_mgmt *mgmt;
- size_t hdr_len;
+ if (ret) {
+ wpa_s->scan_res_handler = NULL;
+ if (wpa_s->scanning || was_in_p2p_scan) {
+ wpa_s->p2p_cb_on_scan_complete = 1;
+ ret = 1;
+ }
+ }
- if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
- return;
- mgmt = (const struct ieee80211_mgmt *) buf;
- hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
- if (hdr_len > len)
- return;
- p2p_rx_action(wpa_s->global->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
- mgmt->u.action.category,
- &mgmt->u.action.u.vs_public_action.action,
- len - hdr_len, freq);
+ return ret;
}
-#endif /* CONFIG_CLIENT_MLME */
static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
}
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
{
struct wpa_ssid *ssid;
char *gtype;
const char *reason;
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
-
ssid = wpa_s->current_ssid;
if (ssid == NULL) {
/*
case P2P_GROUP_REMOVAL_UNAVAILABLE:
reason = " reason=UNAVAILABLE";
break;
+ case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
+ reason = " reason=GO_ENDING_SESSION";
+ break;
default:
reason = "";
break;
}
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
- wpa_s->ifname, gtype, reason);
+ if (!silent) {
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_REMOVED "%s %s%s",
+ wpa_s->ifname, gtype, reason);
+ }
+
+ if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
- if (ssid)
+ if (!silent && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
- wpa_supplicant_remove_iface(wpa_s->global, wpa_s);
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces;
if (wpa_s && ifname)
wpa_drv_if_remove(wpa_s, type, ifname);
ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
(ssid->key_mgmt & WPA_KEY_MGMT_WPS))) {
int id = ssid->id;
- if (ssid == wpa_s->current_ssid)
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->current_ssid = NULL;
- wpas_notify_network_removed(wpa_s, ssid);
+ }
+ /*
+ * Networks objects created during any P2P activities are not
+ * exposed out as they might/will confuse certain non-P2P aware
+ * applications since these network objects won't behave like
+ * regular ones.
+ *
+ * Likewise, we don't send out network removed signals for such
+ * network objects.
+ */
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
+ wpa_supplicant_cancel_sched_scan(wpa_s);
} else {
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
}
- wpa_supplicant_ap_deinit(wpa_s);
+ if (wpa_s->ap_iface)
+ wpa_supplicant_ap_deinit(wpa_s);
+ else
+ wpa_drv_deinit_p2p_cli(wpa_s);
}
}
-static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- const u8 *go_dev_addr)
+static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *go_dev_addr)
{
struct wpa_ssid *s;
int changed = 0;
changed = 1;
s = wpa_config_add_network(wpa_s->conf);
if (s == NULL)
- return;
+ return -1;
+
+ /*
+ * Instead of network_added we emit persistent_group_added
+ * notification. Also to keep the defense checks in
+ * persistent_group obj registration method, we set the
+ * relevant flags in s to designate it as a persistent group.
+ */
+ s->p2p_group = 1;
+ s->p2p_persistent_group = 1;
+ wpas_notify_persistent_group_added(wpa_s, s);
wpa_config_set_network_defaults(s);
}
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
#endif /* CONFIG_NO_CONFIG_WRITE */
+
+ return s->id;
+}
+
+
+static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ struct wpa_ssid *ssid, *s;
+ u8 *n;
+ size_t i;
+
+ ssid = wpa_s->current_ssid;
+ if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+ !ssid->p2p_persistent_group)
+ return;
+
+ for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+ if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ if (s->ssid_len == ssid->ssid_len &&
+ os_memcmp(s->ssid, ssid->ssid, s->ssid_len) == 0)
+ break;
+ }
+
+ if (s == NULL)
+ 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,
+ ETH_ALEN) == 0)
+ return; /* already in list */
+ }
+
+ n = os_realloc(s->p2p_client_list,
+ (s->num_p2p_clients + 1) * ETH_ALEN);
+ if (n == NULL)
+ return;
+ os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ s->p2p_client_list = n;
+ s->num_p2p_clients++;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
}
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
+ int network_id = -1;
/*
* This callback is likely called for the main interface. Update wpa_s
if (!success) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
return;
}
client = ssid->mode == WPAS_MODE_INFRA;
if (ssid->mode == WPAS_MODE_P2P_GO) {
persistent = ssid->p2p_persistent_group;
- os_memcpy(go_dev_addr, wpa_s->parent->own_addr,
+ os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr,
ETH_ALEN);
} else
persistent = wpas_p2p_persistent_group(wpa_s,
ssid_txt = "";
client = wpa_s->p2p_group_interface ==
P2P_GROUP_INTERFACE_CLIENT;
+ os_memset(go_dev_addr, 0, ETH_ALEN);
}
wpa_s->show_group_started = 0;
}
if (persistent)
- wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
- go_dev_addr);
-}
-
-
-static struct wpa_supplicant *
-wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
-{
- struct wpa_supplicant *iface;
-
- if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
- return wpa_s;
-
- /*
- * Try to find a group interface that matches with the source address.
- */
- iface = wpa_s->global->ifaces;
- while (iface) {
- if (os_memcmp(wpa_s->pending_action_src,
- iface->own_addr, ETH_ALEN) == 0)
- break;
- iface = iface->next;
- }
- if (iface) {
- wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
- "instead of interface %s for Action TX",
- iface->ifname, wpa_s->ifname);
- return iface;
- }
-
- return wpa_s;
+ network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+ ssid, go_dev_addr);
+ if (network_id < 0 && ssid)
+ network_id = ssid->id;
+ if (!client)
+ wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
}
-static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result
+ result)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- struct wpa_supplicant *iface;
- int res;
- int without_roc;
-
- without_roc = wpa_s->pending_action_without_roc;
- wpa_s->pending_action_without_roc = 0;
- wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
- "pending_action_tx=%p)",
- without_roc, wpa_s->pending_action_tx);
-
- if (wpa_s->pending_action_tx == NULL)
- return;
-
- /*
- * This call is likely going to be on the P2P device instance if the
- * driver uses a separate interface for that purpose. However, some
- * Action frames are actually sent within a P2P Group and when that is
- * the case, we need to follow power saving (e.g., GO buffering the
- * frame for a client in PS mode or a client following the advertised
- * NoA from its GO). To make that easier for the driver, select the
- * correct group interface here.
- */
- iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
-
- if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
- wpa_s->pending_action_freq != 0 &&
- wpa_s->pending_action_freq != iface->assoc_freq) {
- wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
- "waiting for another freq=%u (off_channel_freq=%u "
- "assoc_freq=%u)",
- wpa_s->pending_action_freq,
- wpa_s->off_channel_freq,
- iface->assoc_freq);
- if (without_roc && wpa_s->off_channel_freq == 0) {
- /*
- * We may get here if wpas_send_action() found us to be
- * on the correct channel, but remain-on-channel cancel
- * event was received before getting here.
- */
- wpa_printf(MSG_DEBUG, "P2P: Schedule "
- "remain-on-channel to send Action frame");
- if (wpa_drv_remain_on_channel(
- wpa_s, wpa_s->pending_action_freq, 200) <
- 0) {
- wpa_printf(MSG_DEBUG, "P2P: Failed to request "
- "driver to remain on channel (%u "
- "MHz) for Action Frame TX",
- wpa_s->pending_action_freq);
- } else {
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq =
- wpa_s->pending_action_freq;
- }
- }
- return;
- }
+ enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
- wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
- MACSTR " using interface %s",
- MAC2STR(wpa_s->pending_action_dst), iface->ifname);
- res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
- wpa_s->pending_action_dst,
- wpa_s->pending_action_src,
- wpa_s->pending_action_bssid,
- wpabuf_head(wpa_s->pending_action_tx),
- wpabuf_len(wpa_s->pending_action_tx));
- if (res) {
- wpa_printf(MSG_DEBUG, "P2P: Failed to send the pending "
- "Action frame");
- /*
- * Use fake TX status event to allow P2P state machine to
- * continue.
- */
- wpas_send_action_tx_status(
- wpa_s, wpa_s->pending_action_dst,
- wpabuf_head(wpa_s->pending_action_tx),
- wpabuf_len(wpa_s->pending_action_tx),
- P2P_SEND_ACTION_FAILED);
- }
-}
-
-
-void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
- const u8 *data, size_t data_len,
- enum p2p_send_action_result result)
-{
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return;
- if (wpa_s->pending_action_tx == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - no "
- "pending operation");
- return;
- }
-
- if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - unknown "
- "destination address");
- return;
+ switch (result) {
+ case OFFCHANNEL_SEND_ACTION_SUCCESS:
+ res = P2P_SEND_ACTION_SUCCESS;
+ break;
+ case OFFCHANNEL_SEND_ACTION_NO_ACK:
+ res = P2P_SEND_ACTION_NO_ACK;
+ break;
+ case OFFCHANNEL_SEND_ACTION_FAILED:
+ res = P2P_SEND_ACTION_FAILED;
+ break;
}
- wpabuf_free(wpa_s->pending_action_tx);
- wpa_s->pending_action_tx = NULL;
-
- p2p_send_action_cb(wpa_s->global->p2p, wpa_s->pending_action_freq,
- wpa_s->pending_action_dst,
- wpa_s->pending_action_src,
- wpa_s->pending_action_bssid,
- result);
+ p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
- if (wpa_s->pending_pd_before_join &&
- (os_memcmp(wpa_s->pending_action_dst, wpa_s->pending_join_dev_addr,
- ETH_ALEN) == 0 ||
- os_memcmp(wpa_s->pending_action_dst,
- wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+ if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
+ wpa_s->pending_pd_before_join &&
+ (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+ os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
wpa_s->pending_pd_before_join = 0;
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+ "during p2p_connect-auto");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
- "join-existing-group operation");
+ "join-existing-group operation (no ACK for PD "
+ "Req)");
wpas_p2p_join_start(wpa_s);
}
}
size_t len, unsigned int wait_time)
{
struct wpa_supplicant *wpa_s = ctx;
-
- wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
- " src=" MACSTR " bssid=" MACSTR " len=%d",
- freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
- (int) len);
-
- if (wpa_s->pending_action_tx) {
- wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
- "to " MACSTR, MAC2STR(wpa_s->pending_action_dst));
- wpabuf_free(wpa_s->pending_action_tx);
- }
- wpa_s->pending_action_tx = wpabuf_alloc(len);
- if (wpa_s->pending_action_tx == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
- "TX buffer (len=%llu)", (unsigned long long) len);
- return -1;
- }
- wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
- os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
- os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
- os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
- wpa_s->pending_action_freq = freq;
-
- if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
- struct wpa_supplicant *iface;
-
- iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
- wpa_s->action_tx_wait_time = wait_time;
-
- return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
- wait_time, wpa_s->pending_action_dst,
- wpa_s->pending_action_src,
- wpa_s->pending_action_bssid,
- wpabuf_head(wpa_s->pending_action_tx),
- wpabuf_len(wpa_s->pending_action_tx));
- }
-
- if (freq) {
- struct wpa_supplicant *tx_iface;
- tx_iface = wpas_get_tx_interface(wpa_s, src);
- if (tx_iface->assoc_freq == freq) {
- wpa_printf(MSG_DEBUG, "P2P: Already on requested "
- "channel (TX interface operating channel)");
- freq = 0;
- }
- }
-
- if (wpa_s->off_channel_freq == freq || freq == 0) {
- wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
- "send Action frame immediately");
- /* TODO: Would there ever be need to extend the current
- * duration on the channel? */
- wpa_s->pending_action_without_roc = 1;
- eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
- eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
- return 0;
- }
- wpa_s->pending_action_without_roc = 0;
-
- if (wpa_s->roc_waiting_drv_freq == freq) {
- wpa_printf(MSG_DEBUG, "P2P: Already waiting for driver to get "
- "to frequency %u MHz; continue waiting to send the "
- "Action frame", freq);
- return 0;
- }
-
- wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
- "once the driver gets to the requested channel");
- if (wait_time > wpa_s->max_remain_on_chan)
- wait_time = wpa_s->max_remain_on_chan;
- if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
- wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
- "to remain on channel (%u MHz) for Action "
- "Frame TX", freq);
- return -1;
- }
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = freq;
-
- return 0;
+ return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
+ wait_time,
+ wpas_p2p_send_action_tx_status, 1);
}
static void wpas_send_action_done(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
- wpabuf_free(wpa_s->pending_action_tx);
- wpa_s->pending_action_tx = NULL;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
- if (wpa_s->action_tx_wait_time)
- wpa_drv_send_action_cancel_wait(wpa_s);
- wpa_s->off_channel_freq = 0;
- } else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
- wpa_drv_cancel_remain_on_channel(wpa_s);
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = 0;
- }
+ offchannel_send_action_done(wpa_s);
}
struct wpa_supplicant *wpa_s = ctx;
struct p2p_go_neg_results *params = data;
struct wpa_ssid *ssid;
+ int network_id = -1;
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
ssid->frequency,
params->passphrase ? params->passphrase : "",
- MAC2STR(wpa_s->parent->own_addr),
+ MAC2STR(wpa_s->global->p2p_dev_addr),
params->persistent_group ? " [PERSISTENT]" : "");
+
if (params->persistent_group)
- wpas_p2p_store_persistent_group(
+ network_id = wpas_p2p_store_persistent_group(
wpa_s->parent, ssid,
- wpa_s->parent->own_addr);
+ wpa_s->global->p2p_dev_addr);
+ if (network_id < 0)
+ network_id = ssid->id;
+ wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
return;
}
if (params->wps_method == WPS_PBC)
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
- NULL);
+ params->peer_device_addr);
else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
wpa_s->p2p_pin, NULL, 0);
if (ssid == NULL)
return;
- wpas_notify_network_added(wpa_s, ssid);
+ wpa_s->show_group_started = 0;
+
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
wpa_s->ap_configured_cb_data = wpa_s->go_params;
- wpa_s->connect_without_scan = 1;
+ wpa_s->connect_without_scan = ssid;
wpa_s->reassociate = 1;
wpa_s->disconnected = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
d->p2p_group_idle = s->p2p_group_idle;
d->p2p_intra_bss = s->p2p_intra_bss;
+ d->persistent_reconnect = s->persistent_reconnect;
+ d->max_num_sta = s->max_num_sta;
+ d->pbc_in_m1 = s->pbc_in_m1;
}
if (res->status) {
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
res->status);
- wpas_notify_p2p_go_neg_completed(wpa_s, res->status);
+ wpas_notify_p2p_go_neg_completed(wpa_s, res);
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
- wpas_notify_p2p_go_neg_completed(wpa_s, P2P_SC_SUCCESS);
+ wpas_notify_p2p_go_neg_completed(wpa_s, res);
+
+ if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
+ struct wpa_ssid *ssid;
+ ssid = wpa_config_get_network(wpa_s->conf,
+ wpa_s->p2p_persistent_id);
+ if (ssid && ssid->disabled == 2 &&
+ ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
+ size_t len = os_strlen(ssid->passphrase);
+ wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
+ "on requested persistent group");
+ os_memcpy(res->passphrase, ssid->passphrase, len);
+ res->passphrase[len] = '\0';
+ }
+ }
if (wpa_s->create_p2p_iface) {
struct wpa_supplicant *group_wpa_s =
const struct p2p_peer_info *info,
int new_device)
{
+#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
sizeof(devtype)),
info->device_name, info->config_methods,
info->dev_capab, info->group_capab);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
}
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+ "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+
wpas_notify_p2p_device_lost(wpa_s, dev_addr);
}
static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
+ return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
}
break;
wpabuf_put_str(resp, usrv->service);
}
+ os_free(str);
if (count == 0) {
wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
os_free(buf);
}
- if (wpa_s->p2p_sd_over_ctrl_iface)
+ if (wpa_s->p2p_sd_over_ctrl_iface) {
+ wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+ update_indic, tlvs, tlvs_len);
return; /* to be processed by an external program */
+ }
resp = wpabuf_alloc(10000);
if (resp == NULL)
}
-void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
- const struct wpabuf *tlvs)
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs)
{
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return (void *) wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
+ return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
- return NULL;
- return p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+ return 0;
+ return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
}
-void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
- u8 version, const char *query)
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+ u8 version, const char *query)
{
struct wpabuf *tlvs;
- void *ret;
+ u64 ret;
tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
if (tlvs == NULL)
- return NULL;
+ return 0;
wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
}
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req)
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_sd_cancel_request(wpa_s, (u64) req);
+ return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- return p2p_sd_cancel_request(wpa_s->global->p2p, req);
+ return p2p_sd_cancel_request(wpa_s->global->p2p,
+ (void *) (uintptr_t) req);
}
void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
const u8 *dev_addr, const u8 *pri_dev_type,
const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab)
+ u8 dev_capab, u8 group_capab, const u8 *group_id,
+ size_t group_id_len)
{
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
- char params[200];
+ char params[300];
u8 empty_dev_type[8];
unsigned int generated_pin = 0;
+ struct wpa_supplicant *group = NULL;
+
+ if (group_id) {
+ for (group = wpa_s->global->ifaces; group; group = group->next)
+ {
+ struct wpa_ssid *s = group->current_ssid;
+ if (s != NULL &&
+ s->mode == WPAS_MODE_P2P_GO &&
+ group_id_len - ETH_ALEN == s->ssid_len &&
+ os_memcmp(group_id + ETH_ALEN, s->ssid,
+ s->ssid_len) == 0)
+ break;
+ }
+ }
if (pri_dev_type == NULL) {
os_memset(empty_dev_type, 0, sizeof(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",
+ "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);
+ dev_name, supp_config_methods, dev_capab, group_capab,
+ group ? " group=" : "",
+ group ? group->ifname : "");
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
else if (config_methods & WPS_CONFIG_PUSHBUTTON)
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
"%s", MAC2STR(peer), params);
+
+ wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
+ P2P_PROV_DISC_SUCCESS,
+ config_methods, generated_pin);
}
{
struct wpa_supplicant *wpa_s = ctx;
unsigned int generated_pin = 0;
-
- if (config_methods & WPS_CONFIG_DISPLAY)
- wpas_prov_disc_local_keypad(wpa_s, peer, "");
- else if (config_methods & WPS_CONFIG_KEYPAD) {
- generated_pin = wps_generate_pin();
- wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
- } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
- MAC2STR(peer));
+ char params[20];
if (wpa_s->pending_pd_before_join &&
(os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation");
wpas_p2p_join_start(wpa_s);
+ return;
+ }
+
+ 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
+ params[0] = '\0';
+
+ if (config_methods & WPS_CONFIG_DISPLAY)
+ wpas_prov_disc_local_keypad(wpa_s, peer, params);
+ else if (config_methods & WPS_CONFIG_KEYPAD) {
+ generated_pin = wps_generate_pin();
+ wpas_prov_disc_local_display(wpa_s, peer, params,
+ generated_pin);
+ } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
+ "%s", MAC2STR(peer), params);
+
+ wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+ P2P_PROV_DISC_SUCCESS,
+ config_methods, generated_pin);
+}
+
+
+static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+ enum p2p_prov_disc_status status)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
+ "failed - fall back to GO Negotiation");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
}
+
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d",
+ MAC2STR(peer), status);
+
+ wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+ status, 0, 0);
}
wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
} else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
- wpa_s->p2p_wps_method);
+ wpa_s->p2p_wps_method, 0);
}
return;
}
}
+static int wpas_p2p_disallowed_freq(struct wpa_global *global,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ if (global->p2p_disallow_freq == NULL)
+ return 0;
+
+ for (i = 0; i < global->num_p2p_disallow_freq; i++) {
+ if (freq >= global->p2p_disallow_freq[i].min &&
+ freq <= global->p2p_disallow_freq[i].max)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
+{
+ reg->channel[reg->channels] = chan;
+ reg->channels++;
+}
+
+
static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan)
{
/* Operating class 81 - 2.4 GHz band channels 1..13 */
chan->reg_class[cla].reg_class = 81;
- chan->reg_class[cla].channels = 11;
- for (i = 0; i < 11; i++)
- chan->reg_class[cla].channel[i] = i + 1;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ for (i = 0; i < 11; i++) {
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
+ }
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
"band");
/* Operating class 115 - 5 GHz, channels 36-48 */
chan->reg_class[cla].reg_class = 115;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 36;
- chan->reg_class[cla].channel[1] = 40;
- chan->reg_class[cla].channel[2] = 44;
- chan->reg_class[cla].channel[3] = 48;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 36);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 40);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 44);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 48);
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
"band");
/* Operating class 124 - 5 GHz, channels 149,153,157,161 */
chan->reg_class[cla].reg_class = 124;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 149;
- chan->reg_class[cla].channel[1] = 153;
- chan->reg_class[cla].channel[2] = 157;
- chan->reg_class[cla].channel[3] = 161;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 149);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 153);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 157);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 161);
+ if (chan->reg_class[cla].channels)
+ cla++;
chan->reg_classes = cla;
return 0;
}
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+static int has_channel(struct wpa_global *global,
+ struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
int i;
+ unsigned int freq;
+
+ freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
+ chan * 5;
+ if (wpas_p2p_disallowed_freq(global, freq))
+ return 0;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].chan == chan) {
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan)
{
- struct hostapd_hw_modes *modes, *mode;
- u16 num_modes, flags;
+ struct hostapd_hw_modes *mode;
int cla, op;
struct p2p_oper_class_map op_class[] = {
{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
{ -1, 0, 0, 0, 0, BW20 }
};
- modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
- if (modes == NULL) {
+ if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
"of all supported channels; assume dualband "
"support");
u8 ch;
struct p2p_reg_class *reg = NULL;
- mode = get_mode(modes, num_modes, o->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
int flag;
- if (!has_channel(mode, ch, &flag))
+ if (!has_channel(wpa_s->global, mode, ch, &flag))
continue;
if (o->bw == BW40MINUS &&
(!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(mode, ch - 4, NULL)))
+ !has_channel(wpa_s->global, mode, ch - 4, NULL)))
continue;
if (o->bw == BW40PLUS &&
(!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(mode, ch + 4, NULL)))
+ !has_channel(wpa_s->global, mode, ch + 4, NULL)))
continue;
if (reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating "
chan->reg_classes = cla;
- ieee80211_sta_free_hw_features(modes, num_modes);
-
return 0;
}
}
+static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ continue;
+ if (ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (wpa_s->wpa_state != WPA_COMPLETED &&
+ wpa_s->wpa_state != WPA_GROUP_HANDSHAKE)
+ continue;
+ if (os_memcmp(wpa_s->go_dev_addr, dev_addr, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
return 0;
-#ifdef CONFIG_CLIENT_MLME
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) {
- wpa_s->mlme.public_action_cb = p2p_rx_action_mlme;
- wpa_s->mlme.public_action_cb_ctx = wpa_s;
- }
-#endif /* CONFIG_CLIENT_MLME */
-
- if (wpa_drv_disable_11b_rates(wpa_s, 1) < 0) {
- wpa_printf(MSG_DEBUG, "P2P: Failed to disable 11b rates");
- /* Continue anyway; this is not really a fatal error */
- }
-
if (global->p2p)
return 0;
p2p.sd_response = wpas_sd_response;
p2p.prov_disc_req = wpas_prov_disc_req;
p2p.prov_disc_resp = wpas_prov_disc_resp;
+ p2p.prov_disc_fail = wpas_prov_disc_fail;
p2p.invitation_process = wpas_invitation_process;
p2p.invitation_received = wpas_invitation_received;
p2p.invitation_result = wpas_invitation_result;
p2p.get_noa = wpas_get_noa;
+ p2p.go_connected = wpas_go_connected;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
- os_memcpy(p2p.dev_addr, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
p2p.dev_name = wpa_s->conf->device_name;
+ p2p.manufacturer = wpa_s->conf->manufacturer;
+ p2p.model_name = wpa_s->conf->model_name;
+ p2p.model_number = wpa_s->conf->model_number;
+ p2p.serial_number = wpa_s->conf->serial_number;
+ if (wpa_s->wps) {
+ os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
+ p2p.config_methods = wpa_s->wps->config_methods;
+ }
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
{
if (wpa_s->driver && wpa_s->drv_priv)
wpa_drv_probe_req_report(wpa_s, 0);
+
+ if (wpa_s->go_params) {
+ /* Clear any stored provisioning info */
+ p2p_clear_provisioning_info(
+ wpa_s->global->p2p,
+ wpa_s->go_params->peer_device_addr);
+ }
+
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
- wpabuf_free(wpa_s->pending_action_tx);
- wpa_s->pending_action_tx = NULL;
- eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
- char *ifname;
if (global->p2p == NULL)
return;
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
wpa_s = wpa_s->next;
while (wpa_s) {
- enum wpa_driver_if_type type;
tmp = global->ifaces;
while (tmp &&
(tmp == wpa_s ||
}
if (tmp == NULL)
break;
- ifname = os_strdup(tmp->ifname);
- type = wpas_p2p_if_type(tmp->p2p_group_interface);
- wpa_supplicant_remove_iface(global, tmp);
- if (ifname)
- wpa_drv_if_remove(wpa_s, type, ifname);
- os_free(ifname);
+ /* Disconnect from the P2P group and deinit the interface */
+ wpas_p2p_disconnect(tmp);
}
/*
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid)
{
+ if (persistent_group && wpa_s->conf->persistent_reconnect)
+ persistent_group = 2;
+
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
go_intent, own_interface_addr,
return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
}
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid)
{
+ if (persistent_group && wpa_s->conf->persistent_reconnect)
+ persistent_group = 2;
+
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return -1;
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
}
" for join operationg - stop join attempt",
MAC2STR(wpa_s->pending_join_iface_addr));
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+ if (wpa_s->p2p_auto_pd) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ return;
+ }
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
}
}
+static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ if (!wpa_s->pending_pd_before_join)
+ return;
+ /*
+ * Provision Discovery Response may have been lost - try to connect
+ * anyway since we do not need any information from this PD.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
+ "try to connect anyway");
+ wpas_p2p_join_start(wpa_s);
+}
+
+
+static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
+{
+ struct wpa_supplicant *iface;
+ int shared_freq;
+ u8 bssid[ETH_ALEN];
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+ return 0;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
+ continue;
+ if (iface->current_ssid == NULL || iface->assoc_freq == 0)
+ continue;
+ if (iface->current_ssid->mode == WPAS_MODE_AP ||
+ iface->current_ssid->mode == WPAS_MODE_P2P_GO)
+ shared_freq = iface->current_ssid->frequency;
+ else if (wpa_drv_get_bssid(iface, bssid) == 0)
+ shared_freq = iface->assoc_freq;
+ else
+ shared_freq = 0;
+
+ if (shared_freq && freq != shared_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
+ "connected on %d MHz - new connection on "
+ "%d MHz", iface->ifname, shared_freq, freq);
+ return 1;
+ }
+ }
+
+ shared_freq = wpa_drv_shared_freq(wpa_s);
+ if (shared_freq > 0 && shared_freq != freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
+ "virtual interface connected on %d MHz - new "
+ "connection on %d MHz", shared_freq, freq);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+ const u8 *peer_dev_addr)
+{
+ struct wpa_bss *bss;
+ int updated;
+
+ bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+ if (bss == NULL)
+ return -1;
+ if (bss->last_update_idx < wpa_s->bss_update_idx) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+ "last scan");
+ return 0;
+ }
+
+ updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+ wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
+ "%ld.%06ld (%supdated in last scan)",
+ bss->last_update.sec, bss->last_update.usec,
+ updated ? "": "not ");
+
+ return updated;
+}
+
+
static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
if (wpa_s->global->p2p_disabled)
return;
- wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
- scan_res ? (int) scan_res->num : -1);
+ wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+ scan_res ? (int) scan_res->num : -1,
+ wpa_s->p2p_auto_join ? "auto_" : "");
if (scan_res)
wpas_p2p_scan_res_handler(wpa_s, scan_res);
+ if (wpa_s->p2p_auto_pd) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join < 0)
+ join = 0;
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
+ 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_pd_config_methods, join,
+ 0) < 0) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ }
+ return;
+ }
+
+ if (wpa_s->p2p_auto_join) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+ "running a GO -> use GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
+ wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+ wpa_s->p2p_persistent_group, 0, 0, 0,
+ wpa_s->p2p_go_intent,
+ wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+ "try to join the group", join ? "" :
+ " in older scan");
+ if (!join)
+ wpa_s->p2p_fallback_to_go_neg = 1;
+ }
+
freq = p2p_get_oper_freq(wpa_s->global->p2p,
wpa_s->pending_join_iface_addr);
if (freq < 0 &&
if (freq > 0) {
u16 method;
+ if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE
+ "reason=FREQ_CONFLICT");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
"prior to joining an existing group (GO " MACSTR
" freq=%u MHz)",
wpa_s->pending_pd_before_join = 1;
switch (wpa_s->pending_join_wps_method) {
- case WPS_PIN_LABEL:
case WPS_PIN_DISPLAY:
method = WPS_CONFIG_KEYPAD;
break;
break;
}
+ if ((p2p_get_provisioning_info(wpa_s->global->p2p,
+ wpa_s->pending_join_dev_addr) ==
+ method)) {
+ /*
+ * We have already performed provision discovery for
+ * joining the group. Proceed directly to join
+ * operation without duplicated provision discovery. */
+ wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
+ "with " MACSTR " already done - proceed to "
+ "join",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ wpa_s->pending_pd_before_join = 0;
+ goto start;
+ }
+
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr, method, 1)
- < 0) {
+ wpa_s->pending_join_dev_addr, method, 1,
+ freq) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
"existing group");
/*
* Actual join operation will be started from the Action frame
- * TX status callback.
+ * TX status callback (if no ACK is received) or when the
+ * Provision Discovery Response is received. Use a short
+ * timeout as a backup mechanism should the Provision Discovery
+ * Response be lost for any reason.
*/
+ eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
+ NULL);
+ eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
+ wpa_s, NULL);
return;
}
int ret;
struct wpa_driver_scan_params params;
struct wpabuf *wps_ie, *ies;
+ size_t ielen;
os_memset(¶ms, 0, sizeof(params));
params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE);
+ wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
+ wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
+ NULL);
if (wps_ie == NULL) {
wpas_p2p_scan_res_join(wpa_s, NULL);
return;
}
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
if (ies == NULL) {
wpabuf_free(wps_ie);
wpas_p2p_scan_res_join(wpa_s, NULL);
wpabuf_put_buf(ies, wps_ie);
wpabuf_free(wps_ie);
- p2p_scan_ie(wpa_s->global->p2p, ies);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+ params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
*/
- wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ret = ieee80211_sta_req_scan(wpa_s, ¶ms);
- else
- ret = wpa_drv_scan(wpa_s, ¶ms);
+ ret = wpa_drv_scan(wpa_s, ¶ms);
+ if (!ret)
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
wpabuf_free(ies);
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method)
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join)
{
wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
- MACSTR " dev " MACSTR ")",
- MAC2STR(iface_addr), MAC2STR(dev_addr));
+ MACSTR " dev " MACSTR ")%s",
+ MAC2STR(iface_addr), MAC2STR(dev_addr),
+ auto_join ? " (auto_join)" : "");
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->p2p_auto_join = !!auto_join;
os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
wpa_s->pending_join_wps_method = wps_method;
{
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
+ struct wpa_bss *bss;
+ eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
if (group == NULL)
return -1;
}
group->p2p_in_provisioning = 1;
+ group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
+ bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ if (bss) {
+ res.freq = bss->freq;
+ res.ssid_len = bss->ssid_len;
+ os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ }
+
+ if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
+ "starting client");
+ wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_s->off_channel_freq = 0;
+ wpa_s->roc_waiting_drv_freq = 0;
+ }
wpas_start_wps_enrollee(group, &res);
/*
* @peer_addr: Address of the peer P2P Device
* @pin: PIN to use during provisioning or %NULL to indicate PBC mode
* @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
* @join: Whether to join an existing group (as a client) instead of starting
* Group Owner negotiation; @peer_addr is BSSID in that case
* @auth: Whether to only authorize the connection instead of doing that and
* initiating Group Owner negotiation
* @go_intent: GO Intent or -1 to use default
* @freq: Frequency for the group or 0 for auto-selection
+ * @persistent_id: Persistent group credentials to use for forcing GO
+ * parameters or -1 to generate new values (SSID/passphrase)
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
*/
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int join, int auth, int go_intent,
- int freq)
+ int persistent_group, int auto_join, int join, int auth,
+ int go_intent, int freq, int persistent_id)
{
int force_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
int ret = 0;
enum wpa_driver_if_type iftype;
+ const u8 *if_addr;
+ struct wpa_ssid *ssid = NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (persistent_id >= 0) {
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO)
+ return -1;
+ }
+
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
wpa_s->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
+ wpa_s->p2p_persistent_group = !!persistent_group;
+ wpa_s->p2p_persistent_id = persistent_id;
+ wpa_s->p2p_go_intent = go_intent;
+ wpa_s->p2p_connect_freq = freq;
+ wpa_s->p2p_fallback_to_go_neg = 0;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
} else
wpa_s->p2p_pin[0] = '\0';
- if (join) {
+ if (join || auto_join) {
u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
dev_addr);
}
- if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
- 0)
+ if (auto_join) {
+ os_get_time(&wpa_s->p2p_auto_started);
+ wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
+ "%ld.%06ld",
+ wpa_s->p2p_auto_started.sec,
+ wpa_s->p2p_auto_started.usec);
+ }
+ if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+ auto_join) < 0)
return -1;
return ret;
}
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
- if (!wpa_s->create_p2p_iface) {
- if (auth) {
- if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
- go_intent, wpa_s->own_addr,
- force_freq, persistent_group)
- < 0)
- return -1;
- return ret;
- }
- if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
- go_intent, wpa_s->own_addr,
- force_freq, persistent_group) < 0)
+ if (wpa_s->create_p2p_iface) {
+ /* Prepare to add a new interface for the group */
+ iftype = WPA_IF_P2P_GROUP;
+ if (go_intent == 15)
+ iftype = WPA_IF_P2P_GO;
+ if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+ "interface for the group");
return -1;
- return ret;
- }
+ }
- /* Prepare to add a new interface for the group */
- iftype = WPA_IF_P2P_GROUP;
- if (join)
- iftype = WPA_IF_P2P_CLIENT;
- else if (go_intent == 15)
- iftype = WPA_IF_P2P_GO;
- if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
- wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
- "interface for the group");
- return -1;
- }
+ if_addr = wpa_s->pending_interface_addr;
+ } else
+ if_addr = wpa_s->own_addr;
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
- go_intent,
- wpa_s->pending_interface_addr,
- force_freq, persistent_group) < 0)
+ go_intent, if_addr,
+ force_freq, persistent_group, ssid) <
+ 0)
return -1;
return ret;
}
- if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent,
- wpa_s->pending_interface_addr,
- force_freq, persistent_group) < 0) {
- wpas_p2p_remove_pending_group_interface(wpa_s);
+
+ if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
+ go_intent, if_addr, force_freq,
+ persistent_group, ssid) < 0) {
+ if (wpa_s->create_p2p_iface)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
}
return ret;
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- wpa_s->roc_waiting_drv_freq = 0;
- wpa_s->off_channel_freq = freq;
- wpas_send_action_cb(wpa_s, NULL);
if (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_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
- wpa_s->off_channel_freq = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
}
-static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
- struct p2p_go_neg_results *params,
- int freq)
+static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params,
+ int freq)
{
u8 bssid[ETH_ALEN];
int res;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
- wpa_s->conf->p2p_oper_reg_class == 118) {
+ wpa_s->conf->p2p_oper_reg_class == 124) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
} else {
- params->freq = 2412;
+ int chan;
+ for (chan = 0; chan < 11; chan++) {
+ params->freq = 2412 + chan * 5;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global,
+ params->freq))
+ break;
+ }
+ if (chan == 11) {
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
+ "allowed");
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
"known)", params->freq);
}
wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
"already using on a shared interface");
params->freq = res;
+ } else if (res > 0 && freq != res &&
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
+ "while connected on another channel (%u MHz)",
+ freq, res);
+ return -1;
}
+
+ return 0;
}
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ /* Make sure we are not running find during connection establishment */
+ wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
+ wpas_p2p_stop_find(wpa_s);
+
if (freq == 2) {
wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
"band");
return -1;
}
- wpas_p2p_init_go_params(wpa_s, ¶ms, freq);
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq))
+ return -1;
+ if (params.freq &&
+ !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
+ "(%u MHz) is not supported for P2P uses",
+ params.freq);
+ return -1;
+ }
p2p_go_params(wpa_s->global->p2p, ¶ms);
params.persistent_group = persistent_group;
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
- wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->proto = WPA_PROTO_RSN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->ssid = os_malloc(params->ssid_len);
if (ssid->ssid == NULL) {
- wpas_notify_network_removed(wpa_s, ssid);
wpa_config_remove_network(wpa_s->conf, ssid->id);
return -1;
}
/* Make sure we are not running find during connection establishment */
wpas_p2p_stop_find(wpa_s);
+ wpa_s->p2p_fallback_to_go_neg = 0;
+
if (ssid->mode == WPAS_MODE_INFRA)
return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- wpas_p2p_init_go_params(wpa_s, ¶ms, freq);
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq))
+ return -1;
params.role_go = 1;
if (ssid->passphrase == NULL ||
struct wpa_supplicant *wpa_s = ctx;
if (wpa_s->ap_iface) {
struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+ if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) {
+ wpabuf_free(beacon_ies);
+ wpabuf_free(proberesp_ies);
+ return;
+ }
if (beacon_ies) {
wpabuf_free(hapd->p2p_beacon_ie);
hapd->p2p_beacon_ie = beacon_ies;
if (cfg == NULL)
return NULL;
- cfg->persistent_group = persistent_group;
+ if (persistent_group && wpa_s->conf->persistent_reconnect)
+ cfg->persistent_group = 2;
+ else if (persistent_group)
+ cfg->persistent_group = 1;
os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
if (wpa_s->max_stations &&
wpa_s->max_stations < wpa_s->conf->max_num_sta)
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int registrar)
{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
if (!wpa_s->p2p_in_provisioning) {
wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P "
"provisioning not in progress");
return;
}
+ if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+ u8 go_dev_addr[ETH_ALEN];
+ os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN);
+ wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+ ssid->ssid_len);
+ /* Clear any stored provisioning info */
+ p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
+ }
+
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
NULL);
+ if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * something goes wrong in this step before the P2P group idle
+ * timeout mechanism is taken into use.
+ */
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s, NULL);
+ }
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
}
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+ if (!wpa_s->p2p_in_provisioning) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P "
+ "provisioning not in progress");
+ return;
+ }
+
+ if (wpa_s->go_params) {
+ p2p_clear_provisioning_info(
+ wpa_s->global->p2p,
+ wpa_s->go_params->peer_device_addr);
+ }
+
+ wpas_notify_p2p_wps_failed(wpa_s, fail);
+}
+
+
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method)
+ const char *config_method,
+ enum wpas_p2p_prov_disc_use use)
{
u16 config_methods;
- if (os_strcmp(config_method, "display") == 0)
+ wpa_s->p2p_fallback_to_go_neg = 0;
+ wpa_s->pending_pd_use = NORMAL_PD;
+ if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
- else if (os_strcmp(config_method, "keypad") == 0)
+ else if (os_strncmp(config_method, "keypad", 6) == 0)
config_methods = WPS_CONFIG_KEYPAD;
- else if (os_strcmp(config_method, "pbc") == 0 ||
- os_strcmp(config_method, "pushbutton") == 0)
+ else if (os_strncmp(config_method, "pbc", 3) == 0 ||
+ os_strncmp(config_method, "pushbutton", 10) == 0)
config_methods = WPS_CONFIG_PUSHBUTTON;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
return -1;
+ }
+
+ if (use == WPAS_P2P_PD_AUTO) {
+ os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+ wpa_s->pending_pd_config_methods = config_methods;
+ wpa_s->p2p_auto_pd = 1;
+ wpa_s->p2p_auto_join = 0;
+ wpa_s->pending_pd_before_join = 0;
+ wpas_p2p_stop_find(wpa_s);
+ wpa_s->p2p_join_scan_count = 0;
+ wpas_p2p_join_scan(wpa_s, NULL);
+ return 0;
+ }
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
- config_methods);
+ config_methods,
+ use == WPAS_P2P_PD_FOR_JOIN);
}
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return -1;
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
- config_methods, 0);
+ config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+ 0);
}
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
- enum p2p_discovery_type type)
+ enum p2p_discovery_type type,
+ unsigned int num_req_dev_types, const u8 *req_dev_types,
+ const u8 *dev_id)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- return p2p_find(wpa_s->global->p2p, timeout, type);
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ return p2p_find(wpa_s->global->p2p, timeout, type,
+ num_req_dev_types, req_dev_types, dev_id);
}
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+ wpa_s->p2p_cb_on_scan_complete = 0;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
wpa_drv_p2p_stop_find(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
if (timeout == 0) {
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
+ /*
+ * Stop previous find/listen operation to avoid trying to request a new
+ * remain-on-channel operation while the driver is still running the
+ * previous one.
+ */
+ if (wpa_s->global->p2p)
+ p2p_stop_find(wpa_s->global->p2p);
+
res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
wpa_s->p2p_long_listen = timeout * 1000;
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
- const u8 *ie, size_t ie_len)
+ const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, int ssi_signal)
{
if (wpa_s->global->p2p_disabled)
return 0;
if (wpa_s->global->p2p == NULL)
return 0;
- return p2p_probe_req_rx(wpa_s->global->p2p, addr, ie, ie_len);
+ switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+ ie, ie_len)) {
+ case P2P_PREQ_NOT_P2P:
+ wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
+ ssi_signal);
+ /* fall through */
+ case P2P_PREQ_MALFORMED:
+ case P2P_PREQ_NOT_LISTEN:
+ case P2P_PREQ_NOT_PROCESSED:
+ default: /* make gcc happy */
+ return 0;
+ case P2P_PREQ_PROCESSED:
+ return 1;
+ }
}
if (wpa_s->global->p2p == NULL)
return;
- p2p_scan_ie(wpa_s->global->p2p, ies);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
}
{
p2p_group_deinit(wpa_s->p2p_group);
wpa_s->p2p_group = NULL;
+
+ wpa_s->ap_configured_cb = NULL;
+ wpa_s->ap_configured_cb_ctx = NULL;
+ wpa_s->ap_configured_cb_data = NULL;
+ wpa_s->connect_without_scan = NULL;
}
enum p2p_invite_role role;
u8 *bssid = NULL;
struct wpa_ssid *ssid;
+ int persistent;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
return -1;
}
+ persistent = ssid->p2p_persistent_group &&
+ wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
+ ssid->ssid, ssid->ssid_len);
+
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_ACTIVE_GO;
bssid = wpa_s->own_addr;
if (go_dev_addr == NULL)
- go_dev_addr = wpa_s->parent->own_addr;
+ go_dev_addr = wpa_s->global->p2p_dev_addr;
} else {
role = P2P_INVITE_ROLE_CLIENT;
if (wpa_s->wpa_state < WPA_ASSOCIATED) {
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len,
- go_dev_addr, 0);
+ go_dev_addr, persistent);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
- go_dev_addr, 0);
+ go_dev_addr, persistent);
}
struct wpa_ssid *ssid = wpa_s->current_ssid;
const char *ssid_txt;
u8 go_dev_addr[ETH_ALEN];
+ int network_id = -1;
int persistent;
+ int freq;
+
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ NULL);
if (!wpa_s->show_group_started || !ssid)
return;
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
+ freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+ (int) wpa_s->assoc_freq;
if (ssid->passphrase == NULL && ssid->psk_set) {
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
"%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
MACSTR "%s",
- wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+ wpa_s->ifname, ssid_txt, freq, psk,
MAC2STR(go_dev_addr),
persistent ? " [PERSISTENT]" : "");
} else {
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
"%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
"go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, ssid->frequency,
+ wpa_s->ifname, ssid_txt, freq,
ssid->passphrase ? ssid->passphrase : "",
MAC2STR(go_dev_addr),
persistent ? " [PERSISTENT]" : "");
}
if (persistent)
- wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
- go_dev_addr);
+ network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+ ssid, go_dev_addr);
+ if (network_id < 0)
+ network_id = ssid->id;
+ wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
}
}
+static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->current_ssid != NULL &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
+
+
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- if (wpa_s->conf->p2p_group_idle == 0) {
+ if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) {
wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
"disabled");
return;
wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
"group");
wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
}
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
{
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
- if (wpa_s->conf->p2p_group_idle == 0)
- return;
+ int timeout;
+
+ if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
return;
+ timeout = wpa_s->conf->p2p_group_idle;
+ if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+ (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE))
+ timeout = P2P_MAX_CLIENT_IDLE;
+
+ if (timeout == 0)
+ return;
+
+ if (timeout < 0) {
+ if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
+ timeout = 0; /* special client mode no-timeout */
+ else
+ return;
+ }
+
+ if (wpa_s->p2p_in_provisioning) {
+ /*
+ * Use the normal group formation timeout during the
+ * provisioning phase to avoid terminating this process too
+ * early due to group idle timeout.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+ "during provisioning");
+ return;
+ }
+
+ if (wpa_s->show_group_started) {
+ /*
+ * Use the normal group formation timeout between the end of
+ * the provisioning phase and completion of 4-way handshake to
+ * avoid terminating this process too early due to group idle
+ * timeout.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+ "while waiting for initial 4-way handshake to "
+ "complete");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
- wpa_s->conf->p2p_group_idle);
- eloop_register_timeout(wpa_s->conf->p2p_group_idle, 0,
- wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ timeout);
+ eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
+ wpa_s, NULL);
}
void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return;
- p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ if (!locally_generated)
+ p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
+
+ if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
+ wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
+ "session is ending");
+ wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
+ wpas_p2p_group_delete(wpa_s, 0);
+ }
}
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return;
- p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ if (!locally_generated)
+ p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
}
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type);
+ if (wpa_s->wps &&
+ (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS))
+ p2p_set_config_methods(p2p, wpa_s->wps->config_methods);
+
+ if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID))
+ p2p_set_uuid(p2p, wpa_s->wps->uuid);
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) {
+ p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer);
+ p2p_set_model_name(p2p, wpa_s->conf->model_name);
+ p2p_set_model_number(p2p, wpa_s->conf->model_number);
+ p2p_set_serial_number(p2p, wpa_s->conf->serial_number);
+ }
+
if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE)
p2p_set_sec_dev_types(p2p,
(void *) wpa_s->conf->sec_device_type,
if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) {
+ u8 reg_class, channel;
+ int ret;
+ unsigned int r;
+ if (wpa_s->conf->p2p_listen_reg_class &&
+ wpa_s->conf->p2p_listen_channel) {
+ reg_class = wpa_s->conf->p2p_listen_reg_class;
+ channel = wpa_s->conf->p2p_listen_channel;
+ } else {
+ reg_class = 81;
+ /*
+ * Pick one of the social channels randomly as the
+ * listen channel.
+ */
+ os_get_random((u8 *) &r, sizeof(r));
+ channel = 1 + (r % 3) * 5;
+ }
+ ret = p2p_set_listen_channel(p2p, reg_class, channel);
+ if (ret)
+ wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
+ "failed: %d", ret);
+ }
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) {
+ u8 op_reg_class, op_channel, cfg_op_channel;
+ int ret = 0;
+ unsigned int r;
+ if (wpa_s->conf->p2p_oper_reg_class &&
+ wpa_s->conf->p2p_oper_channel) {
+ op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+ op_channel = wpa_s->conf->p2p_oper_channel;
+ cfg_op_channel = 1;
+ } else {
+ op_reg_class = 81;
+ /*
+ * Use random operation channel from (1, 6, 11)
+ *if no other preference is indicated.
+ */
+ os_get_random((u8 *) &r, sizeof(r));
+ op_channel = 1 + (r % 3) * 5;
+ cfg_op_channel = 0;
+ }
+ ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
+ cfg_op_channel);
+ if (ret)
+ wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
+ "failed: %d", ret);
+ }
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) {
+ if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan,
+ wpa_s->conf->p2p_pref_chan) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
+ "update failed");
+ }
+ }
}
wpas_p2p_disable_cross_connect(wpa_s);
else
wpas_p2p_enable_cross_connect(wpa_s);
- if (!wpa_s->ap_iface)
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ if (!wpa_s->ap_iface &&
+ eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
}
void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
{
wpas_p2p_disable_cross_connect(wpa_s);
- if (!wpa_s->ap_iface)
+ if (!wpa_s->ap_iface &&
+ !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
+ wpa_s, NULL))
wpas_p2p_set_group_idle_timeout(wpa_s);
}
wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
MACSTR, MAC2STR(peer));
p2p_unauthorize(global->p2p, peer);
+ found = 1;
}
wpas_p2p_stop_find(wpa_s);
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
break;
}
}
wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
"being available anymore");
wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
}
return -1;
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
return 0;
}
+
+
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return 0;
+
+ return p2p_in_progress(wpa_s->global->p2p);
+}
+
+
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL) > 0) {
+ /**
+ * Remove the network by scheduling the group formation
+ * timeout to happen immediately. The teardown code
+ * needs to be scheduled to run asynch later so that we
+ * don't delete data from under ourselves unexpectedly.
+ * Calling wpas_p2p_group_formation_timeout directly
+ * causes a series of crashes in WPS failure scenarios.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
+ "P2P group network getting removed");
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+}
+
+
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_ssid *s;
+ size_t i;
+
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled != 2)
+ continue;
+ if (ssid &&
+ (ssid_len != s->ssid_len ||
+ os_memcmp(ssid, s->ssid, ssid_len) != 0))
+ continue;
+ if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
+ return s; /* peer is GO in the persistent group */
+ 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,
+ addr, ETH_ALEN) == 0)
+ return s; /* peer is P2P client in persistent
+ * group */
+ }
+ }
+
+ return NULL;
+}
+
+
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ if (addr == NULL)
+ return;
+ wpas_p2p_add_persistent_group_client(wpa_s, addr);
+}
+
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added)
+{
+ struct wpa_supplicant *group = wpa_s;
+ if (wpa_s->global->p2p_group_formation)
+ group = wpa_s->global->p2p_group_formation;
+ wpa_s = wpa_s->parent;
+ if (group_added)
+ wpas_p2p_group_delete(group, 1);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
+ wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+ 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->p2p_fallback_to_go_neg ||
+ wpa_s->p2p_in_provisioning <= 5)
+ return 0;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+ "fallback to GO Negotiation");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+ return 1;
+}