/*
* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
#include "ap/ap_config.h"
#include "ap/sta_info.h"
#include "ap/ap_drv_ops.h"
+#include "ap/wps_hostapd.h"
#include "ap/p2p_hostapd.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
#include "offchannel.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
/*
#ifndef P2P_MAX_INITIAL_CONN_WAIT
/*
* How many seconds to wait for initial 4-way handshake to get completed after
- * WPS provisioning step.
+ * WPS provisioning step or after the re-invocation of a persistent group on a
+ * P2P Client.
*/
#define P2P_MAX_INITIAL_CONN_WAIT 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT */
#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
-#ifndef P2P_CONCURRENT_SEARCH_DELAY
-#define P2P_CONCURRENT_SEARCH_DELAY 500
-#endif /* P2P_CONCURRENT_SEARCH_DELAY */
-
#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
enum p2p_group_removal_reason {
P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
P2P_GROUP_REMOVAL_UNAVAILABLE,
P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
- P2P_GROUP_REMOVAL_PSK_FAILURE
+ P2P_GROUP_REMOVAL_PSK_FAILURE,
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
};
static struct wpa_supplicant *
wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
int go);
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len);
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,
- int auto_join);
+ int auto_join, int freq,
+ const u8 *ssid, size_t ssid_len);
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_group_formation_timeout(void *eloop_ctx,
void *timeout_ctx);
+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);
/*
* Get the frequencies that are currently in use by one or more of the virtual
* interfaces, and that are also valid for P2P operation.
*/
-static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
- int *p2p_freqs, unsigned int len)
+static unsigned int
+wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *p2p_freqs,
+ unsigned int len)
{
- int *freqs;
+ struct wpa_used_freq_data *freqs;
unsigned int num, i, j;
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
- return -1;
+ return 0;
- num = get_shared_radio_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = get_shared_radio_freqs_data(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
- os_memset(p2p_freqs, 0, sizeof(int) * len);
+ os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len);
for (i = 0, j = 0; i < num && j < len; i++) {
- if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
p2p_freqs[j++] = freqs[i];
}
os_free(freqs);
- dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j);
+ dump_freq_data(wpa_s, "valid for P2P", p2p_freqs, j);
return j;
}
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
- wpas_p2p_num_unused_channels(wpa_s) > 0 &&
- wpa_s->parent->conf->p2p_ignore_shared_freq)
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
+ freq);
freq = 0;
+ }
p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
}
{
size_t i;
+ 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;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
- struct os_time time_tmp_age, entry_ts;
+ struct os_reltime time_tmp_age, entry_ts;
const u8 *ies;
size_t ies_len;
time_tmp_age.sec = bss->age / 1000;
time_tmp_age.usec = (bss->age % 1000) * 1000;
- os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
+ os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
ies = (const u8 *) (bss + 1);
ies_len = bss->ie_len;
}
+static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_driver_scan_params *params = work->ctx;
+ int ret;
+
+ if (deinit) {
+ if (!work->started) {
+ wpa_scan_free_params(params);
+ return;
+ }
+
+ wpa_s->p2p_scan_work = NULL;
+ return;
+ }
+
+ ret = wpa_drv_scan(wpa_s, params);
+ wpa_scan_free_params(params);
+ work->ctx = NULL;
+ if (ret) {
+ radio_work_done(work);
+ return;
+ }
+
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ wpa_s->own_scan_requested = 1;
+ wpa_s->p2p_scan_work = work;
+}
+
+
+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)
{
struct wpa_supplicant *wpa_s = ctx;
- struct wpa_supplicant *ifs;
- struct wpa_driver_scan_params params;
- int ret;
+ struct wpa_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
- int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+ unsigned int num_channels = 0;
+ int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
+ u8 *n, i;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs->sta_scan_pending &&
- (wpas_scan_scheduled(ifs) || ifs->scanning) &&
- wpas_p2p_in_progress(wpa_s) == 2) {
- wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
- "pending station mode scan to be "
- "completed on interface %s", ifs->ifname);
- wpa_s->global->p2p_cb_on_scan_complete = 1;
- wpa_supplicant_req_scan(ifs, 0, 0);
- return 1;
- }
+ if (wpa_s->p2p_scan_work) {
+ wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending");
+ return -1;
}
- os_memset(¶ms, 0, sizeof(params));
+ params = os_zalloc(sizeof(*params));
+ if (params == NULL)
+ return -1;
/* P2P Wildcard SSID */
- params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ params->num_ssids = 1;
+ n = os_malloc(P2P_WILDCARD_SSID_LEN);
+ if (n == NULL)
+ goto fail;
+ os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+ params->ssids[0].ssid = n;
+ params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
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;
+ goto fail;
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;
+ goto fail;
}
wpabuf_put_buf(ies, wps_ie);
wpabuf_free(wps_ie);
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);
+ params->p2p_probe = 1;
+ n = os_malloc(wpabuf_len(ies));
+ if (n == NULL) {
+ wpabuf_free(ies);
+ goto fail;
+ }
+ os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
+ params->extra_ies = n;
+ params->extra_ies_len = wpabuf_len(ies);
+ wpabuf_free(ies);
switch (type) {
case P2P_SCAN_SOCIAL:
- params.freqs = social_channels;
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
+ sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
+ params->freqs[num_channels++] =
+ social_channels_freq[i];
+ }
+ params->freqs[num_channels++] = 0;
break;
case P2P_SCAN_FULL:
break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
- social_channels[3] = freq;
- params.freqs = social_channels;
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
+ sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ for (i = 0; i < ARRAY_SIZE(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 (p2p_supported_freq(wpa_s->global->p2p, freq))
+ params->freqs[num_channels++] = freq;
+ params->freqs[num_channels++] = 0;
break;
}
- ret = wpa_drv_scan(wpa_s, ¶ms);
-
- wpabuf_free(ies);
-
- if (ret) {
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs->scanning ||
- ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
- wpa_s->global->p2p_cb_on_scan_complete = 1;
- ret = 1;
- break;
- }
- }
- } else {
- os_get_time(&wpa_s->scan_trigger_time);
- wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
- }
+ radio_remove_works(wpa_s, "p2p-scan", 0);
+ if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
+ params) < 0)
+ goto fail;
+ return 0;
- return ret;
+fail:
+ wpa_scan_free_params(params);
+ return -1;
}
}
+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->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);
+}
+
+
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason)
{
(ssid && ssid->mode == WPAS_MODE_INFRA)) {
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
gtype = "client";
} else
gtype = "GO";
+
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
+ wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
+ if (os_strcmp(gtype, "client") == 0) {
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ if (eloop_is_timeout_registered(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: PSK failure removal was scheduled, so use PSK failure as reason for group removal");
+ removal_reason = P2P_GROUP_REMOVAL_PSK_FAILURE;
+ eloop_cancel_timeout(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL);
+ }
+ }
+
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
wpa_msg_global(wpa_s->parent, MSG_INFO,
case P2P_GROUP_REMOVAL_PSK_FAILURE:
reason = " reason=PSK_FAILURE";
break;
+ case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
+ reason = " reason=FREQ_CONFLICT";
+ break;
default:
reason = "";
break;
wpa_s->ifname, gtype, reason);
}
+ if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict 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 (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->p2p_in_provisioning = 0;
}
+ wpa_s->p2p_in_invitation = 0;
+
/*
* Make sure wait for the first client does not remain active after the
* group has been removed.
*/
wpa_s->global->p2p_go_wait_client.sec = 0;
- if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
- wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
-
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
struct wpa_global *global;
char *ifname;
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;
+ wpa_s->waiting_presence_resp = 0;
+
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
if (ssid && (ssid->p2p_group ||
ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_s->sta_scan_pending = 0;
} else {
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
bssid = wpa_s->bssid;
bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+ if (bss == NULL && wpa_s->go_params &&
+ !is_zero_ether_addr(wpa_s->go_params->peer_device_addr))
+ bss = wpa_bss_get_p2p_dev_addr(
+ wpa_s, wpa_s->go_params->peer_device_addr);
if (bss == NULL) {
u8 iface_addr[ETH_ALEN];
if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
changed = 1;
}
-#ifndef CONFIG_NO_CONFIG_WRITE
if (changed && wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
}
-#endif /* CONFIG_NO_CONFIG_WRITE */
return s->id;
}
os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
s->p2p_client_list = n;
s->num_p2p_clients++;
- } else if (!found) {
+ } else if (!found && s->p2p_client_list) {
/* Not enough room for an additional entry - drop the oldest
* entry */
os_memmove(s->p2p_client_list,
addr, ETH_ALEN);
}
-#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 */
+}
+
+
+static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
+ int go, struct wpa_ssid *ssid, int freq,
+ const u8 *psk, const char *passphrase,
+ const u8 *go_dev_addr, int persistent,
+ const char *extra)
+{
+ const char *ssid_txt;
+ char psk_txt[65];
+
+ if (psk)
+ wpa_snprintf_hex(psk_txt, sizeof(psk_txt), psk, 32);
+ else
+ psk_txt[0] = '\0';
+
+ if (ssid)
+ ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+ else
+ ssid_txt = "";
+
+ if (passphrase && passphrase[0] == '\0')
+ passphrase = NULL;
+
+ /*
+ * Include PSK/passphrase only in the control interface message and
+ * leave it out from the debug log entry.
+ */
+ wpa_msg_global_ctrl(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_STARTED
+ "%s %s ssid=\"%s\" freq=%d%s%s%s%s%s go_dev_addr="
+ MACSTR "%s%s",
+ wpa_s->ifname, go ? "GO" : "client", ssid_txt, freq,
+ psk ? " psk=" : "", psk_txt,
+ passphrase ? " passphrase=\"" : "",
+ passphrase ? passphrase : "",
+ passphrase ? "\"" : "",
+ MAC2STR(go_dev_addr),
+ persistent ? " [PERSISTENT]" : "", extra);
+ wpa_printf(MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s %s ssid=\"%s\" freq=%d go_dev_addr=" MACSTR "%s%s",
+ wpa_s->ifname, go ? "GO" : "client", ssid_txt, freq,
+ MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : "",
+ extra);
}
int success)
{
struct wpa_ssid *ssid;
- const char *ssid_txt;
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
}
+ wpa_s->p2p_in_invitation = 0;
+ wpa_s->group_formation_reported = 1;
if (!success) {
wpa_msg_global(wpa_s->parent, MSG_INFO,
persistent = 0;
if (ssid) {
- ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
client = ssid->mode == WPAS_MODE_INFRA;
if (ssid->mode == WPAS_MODE_P2P_GO) {
persistent = ssid->p2p_persistent_group;
ssid->ssid,
ssid->ssid_len);
} else {
- ssid_txt = "";
client = wpa_s->p2p_group_interface ==
P2P_GROUP_INTERFACE_CLIENT;
os_memset(go_dev_addr, 0, ETH_ALEN);
* packets.
*/
wpa_s->show_group_started = 1;
- } else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
- char psk[65];
- wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
- wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr="
- MACSTR "%s",
- wpa_s->ifname, ssid_txt, ssid->frequency, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
- wpas_p2p_cross_connect_setup(wpa_s);
- wpas_p2p_set_group_idle_timeout(wpa_s);
} else {
- wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt,
- ssid ? ssid->frequency : 0,
- ssid && ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+ wpas_p2p_group_started(wpa_s, 1, ssid,
+ ssid ? ssid->frequency : 0,
+ ssid && ssid->passphrase == NULL &&
+ ssid->psk_set ? ssid->psk : NULL,
+ ssid ? ssid->passphrase : NULL,
+ go_dev_addr, persistent, "");
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
}
network_id = ssid->id;
if (!client) {
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
- os_get_time(&wpa_s->global->p2p_go_wait_client);
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
+ }
+}
+
+
+struct send_action_work {
+ unsigned int freq;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ size_t len;
+ unsigned int wait_time;
+ u8 buf[0];
+};
+
+
+static void wpas_p2p_send_action_work_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (!wpa_s->p2p_send_action_work)
+ return;
+
+ wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out");
+ os_free(wpa_s->p2p_send_action_work->ctx);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+}
+
+
+static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_send_action_work) {
+ struct send_action_work *awork;
+ awork = wpa_s->p2p_send_action_work->ctx;
+ if (awork->wait_time == 0) {
+ os_free(awork);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+ } else {
+ /*
+ * In theory, this should not be needed, but number of
+ * places in the P2P code is still using non-zero wait
+ * time for the last Action frame in the sequence and
+ * some of these do not call send_action_done().
+ */
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 0, awork->wait_time * 1000,
+ wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ }
}
}
{
enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
+ wpas_p2p_action_tx_clear(wpa_s);
+
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
switch (result) {
case OFFCHANNEL_SEND_ACTION_SUCCESS:
}
+static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct send_action_work *awork = work->ctx;
+
+ if (deinit) {
+ if (work->started) {
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ wpa_s->p2p_send_action_work = NULL;
+ offchannel_send_action_done(wpa_s);
+ }
+ os_free(awork);
+ return;
+ }
+
+ if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src,
+ awork->bssid, awork->buf, awork->len,
+ awork->wait_time,
+ wpas_p2p_send_action_tx_status, 1) < 0) {
+ os_free(awork);
+ radio_work_done(work);
+ return;
+ }
+ wpa_s->p2p_send_action_work = work;
+}
+
+
+static int wpas_send_action_work(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid, const u8 *buf,
+ size_t len, unsigned int wait_time)
+{
+ struct send_action_work *awork;
+
+ if (wpa_s->p2p_send_action_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
+ return -1;
+ }
+
+ awork = os_zalloc(sizeof(*awork) + len);
+ if (awork == NULL)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->dst, dst, ETH_ALEN);
+ os_memcpy(awork->src, src, ETH_ALEN);
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ awork->len = len;
+ awork->wait_time = wait_time;
+ os_memcpy(awork->buf, buf, len);
+
+ if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+ wpas_send_action_cb, awork) < 0) {
+ os_free(awork);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time)
{
struct wpa_supplicant *wpa_s = ctx;
+ int listen_freq = -1, send_freq = -1;
+
+ if (wpa_s->p2p_listen_work)
+ listen_freq = wpa_s->p2p_listen_work->freq;
+ if (wpa_s->p2p_send_action_work)
+ send_freq = wpa_s->p2p_send_action_work->freq;
+ if (listen_freq != (int) freq && send_freq != (int) freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)",
+ listen_freq, send_freq);
+ return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+ len, wait_time);
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
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;
+
+ if (wpa_s->p2p_send_action_work) {
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout,
+ wpa_s, NULL);
+ os_free(wpa_s->p2p_send_action_work->ctx);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+ }
+
offchannel_send_action_done(wpa_s);
}
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
- wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
- MAC2STR(res->peer_interface_addr));
+ wpa_s->group_formation_reported = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
+ " dev_addr " MACSTR " wps_method %d",
+ MAC2STR(res->peer_interface_addr),
+ MAC2STR(res->peer_device_addr), res->wps_method);
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
res->ssid, res->ssid_len);
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
- if (res->wps_method == WPS_PBC)
+ if (res->wps_method == WPS_PBC) {
wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
- else {
+#ifdef CONFIG_WPS_NFC
+ } else if (res->wps_method == WPS_NFC) {
+ wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
+ res->peer_interface_addr,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_oob_dev_pw_id, 1,
+ wpa_s->parent->p2p_oob_dev_pw_id ==
+ DEV_PW_NFC_CONNECTION_HANDOVER ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ NULL,
+ NULL, 0, 0);
+#endif /* CONFIG_WPS_NFC */
+ } else {
u16 dev_pw_id = DEV_PW_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
- if (os_strlen(params->passphrase) > 0) {
- wpa_msg_global(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d "
- "passphrase=\"%s\" go_dev_addr=" MACSTR
- "%s", wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency, params->passphrase,
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ?
- " [PERSISTENT]" : "");
- } else {
- char psk[65];
- wpa_snprintf_hex(psk, sizeof(psk), params->psk,
- sizeof(params->psk));
- wpa_msg_global(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d psk=%s "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency, psk,
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ?
- " [PERSISTENT]" : "");
- }
-
- os_get_time(&wpa_s->global->p2p_go_wait_client);
+ wpas_p2p_group_started(wpa_s, 1, ssid, ssid->frequency,
+ params->passphrase[0] == '\0' ?
+ params->psk : NULL,
+ params->passphrase,
+ wpa_s->global->p2p_dev_addr,
+ params->persistent_group, "");
+ wpa_s->group_formation_reported = 1;
+
+ os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
network_id = wpas_p2p_store_persistent_group(
wpa_s->parent, ssid,
"filtering");
return;
}
- if (params->wps_method == WPS_PBC)
+ if (params->wps_method == WPS_PBC) {
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
params->peer_device_addr);
- else if (wpa_s->p2p_pin[0])
+#ifdef CONFIG_WPS_NFC
+ } else if (params->wps_method == WPS_NFC) {
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->p2p_oob_dev_pw) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+ return;
+ }
+ wpas_ap_wps_add_nfc_pw(
+ wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+#endif /* CONFIG_WPS_NFC */
+ } else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
}
wpa_s->show_group_started = 0;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->group_formation_reported = 0;
wpa_config_set_network_defaults(ssid);
ssid->temporary = 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->scan_req = NORMAL_SCAN_REQ;
wpa_s->connect_without_scan = ssid;
wpa_s->reassociate = 1;
wpa_s->disconnected = 0;
d->pbc_in_m1 = s->pbc_in_m1;
d->ignore_old_scan_res = s->ignore_old_scan_res;
d->beacon_int = s->beacon_int;
+ d->dtim_period = s->dtim_period;
d->disassoc_low_ack = s->disassoc_low_ack;
d->disable_scan_offload = s->disable_scan_offload;
+
+ if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+ d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
+ d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
+ }
}
wpa_s->parent, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- wpa_drv_p2p_group_formation_failed(wpa_s);
wpas_group_formation_completed(wpa_s, 0);
}
+static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure");
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+}
+
+
void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->global->p2p_group_formation != wpa_s)
}
-void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
+ wpa_s, NULL);
+ wpas_p2p_group_formation_failed(wpa_s);
return;
}
if (group_wpa_s != wpa_s) {
}
-void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
{
struct wpa_supplicant *wpa_s = ctx;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
}
-void wpas_dev_found(void *ctx, const u8 *addr,
- const struct p2p_peer_info *info,
- int new_device)
+static void wpas_dev_found(void *ctx, const u8 *addr,
+ 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];
+ char *wfd_dev_info_hex = NULL;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+ WFD_SUBELEM_DEVICE_INFO);
+#endif /* CONFIG_WIFI_DISPLAY */
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",
+ "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
- info->device_name, info->config_methods,
- info->dev_capab, info->group_capab);
+ info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab,
+ wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+ wfd_dev_info_hex ? wfd_dev_info_hex : "",
+ info->vendor_elems ? " vendor_elems=1" : "",
+ new_device);
+
+ os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
}
-static int wpas_start_listen(void *ctx, unsigned int freq,
- unsigned int duration,
- const struct wpabuf *probe_resp_ie)
+struct wpas_p2p_listen_work {
+ unsigned int freq;
+ unsigned int duration;
+ struct wpabuf *probe_resp_ie;
+};
+
+
+static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork)
{
- struct wpa_supplicant *wpa_s = ctx;
+ if (lwork == NULL)
+ return;
+ wpabuf_free(lwork->probe_resp_ie);
+ os_free(lwork);
+}
+
+
+static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpas_p2p_listen_work *lwork;
- wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
+ if (!wpa_s->p2p_listen_work)
+ return;
+
+ lwork = wpa_s->p2p_listen_work->ctx;
+ wpas_p2p_listen_work_free(lwork);
+ radio_work_done(wpa_s->p2p_listen_work);
+ wpa_s->p2p_listen_work = NULL;
+}
+
+
+static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
+{
+ 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->p2p_listen_work = NULL;
+ wpas_stop_listen(wpa_s);
+ }
+ wpas_p2p_listen_work_free(lwork);
+ return;
+ }
+
+ wpa_s->p2p_listen_work = work;
+
+ wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL);
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
"report received Probe Request frames");
- return -1;
+ wpas_p2p_listen_work_done(wpa_s);
+ return;
}
- wpa_s->pending_listen_freq = freq;
- wpa_s->pending_listen_duration = duration;
+ wpa_s->pending_listen_freq = lwork->freq;
+ wpa_s->pending_listen_duration = lwork->duration;
+
+ 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, freq, duration) < 0) {
+ 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", freq);
+ "state", lwork->freq);
+ wpas_p2p_listen_work_done(wpa_s);
wpa_s->pending_listen_freq = 0;
- return -1;
+ return;
}
wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = freq;
+ wpa_s->roc_waiting_drv_freq = lwork->freq;
+}
+
+
+static int wpas_start_listen(void *ctx, unsigned int freq,
+ unsigned int duration,
+ const struct wpabuf *probe_resp_ie)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpas_p2p_listen_work *lwork;
+
+ if (wpa_s->p2p_listen_work) {
+ wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists");
+ return -1;
+ }
+
+ lwork = os_zalloc(sizeof(*lwork));
+ if (lwork == NULL)
+ return -1;
+ lwork->freq = freq;
+ lwork->duration = duration;
+ if (probe_resp_ie) {
+ lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie);
+ if (lwork->probe_resp_ie == NULL) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
+ }
+
+ if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb,
+ lwork) < 0) {
+ wpas_p2p_listen_work_free(lwork);
+ return -1;
+ }
return 0;
}
}
wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
wpa_drv_probe_req_report(wpa_s, 0);
+ wpas_p2p_listen_work_done(wpa_s);
}
#endif /* CONFIG_WIFI_DISPLAY */
-void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
- u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+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)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = tlvs;
}
-void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
+static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
{
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos = 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 wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
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, req);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
return p2p_sd_cancel_request(wpa_s->global->p2p,
const u8 *dst, u8 dialog_token,
const struct wpabuf *resp_tlvs)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
- resp_tlvs);
- return;
- }
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_service_update(wpa_s);
- return;
- }
if (wpa_s->global->p2p)
p2p_sd_service_update(wpa_s->global->p2p);
}
}
-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, const u8 *group_id,
- size_t group_id_len)
+static 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, const u8 *group_id,
+ size_t group_id_len)
{
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
}
-void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
{
struct wpa_supplicant *wpa_s = ctx;
unsigned int generated_pin = 0;
wpa_s->pending_pd_before_join = 0;
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation");
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
return;
}
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation (no ACK for PD "
"Req attempts)");
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
return;
}
}
-static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
- const u8 *go_dev_addr, const u8 *ssid,
- size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group,
- const struct p2p_channels *channels)
+/**
+ * Pick the best frequency to use from all the currently used frequencies.
+ */
+static int wpas_p2p_pick_best_used_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs,
+ unsigned int num)
+{
+ unsigned int i, c;
+
+ /* find a candidate freq that is supported by P2P */
+ for (c = 0; c < num; c++)
+ if (p2p_supported_freq(wpa_s->global->p2p, freqs[c].freq))
+ break;
+
+ if (c == num)
+ return 0;
+
+ /* once we have a candidate, try to find a 'better' one */
+ for (i = c + 1; i < num; i++) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i].freq))
+ continue;
+
+ /*
+ * 1. Infrastructure station interfaces have higher preference.
+ * 2. P2P Clients have higher preference.
+ * 3. All others.
+ */
+ if (freqs[i].flags & WPA_FREQ_USED_BY_INFRA_STATION) {
+ c = i;
+ break;
+ }
+
+ if ((freqs[i].flags & WPA_FREQ_USED_BY_P2P_CLIENT))
+ c = i;
+ }
+ return freqs[c].freq;
+}
+
+
+static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
+ const u8 *go_dev_addr, const u8 *ssid,
+ size_t ssid_len, int *go, u8 *group_bssid,
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels,
+ int dev_pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
- int res;
+ struct wpa_used_freq_data *freqs;
struct wpa_supplicant *grp;
+ int best_freq;
if (!persistent_group) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
- " to join an active group", MAC2STR(sa));
+ " to join an active group (SSID: %s)",
+ MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len));
if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
(os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
== 0 ||
"authorized invitation");
goto accept_inv;
}
+
+#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) {
+ 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,
+ go_dev_addr, ETH_ALEN);
+ os_memcpy(wpa_s->parent->pending_join_iface_addr,
+ bssid, ETH_ALEN);
+ goto accept_inv;
+ }
+#endif /* CONFIG_WPS_NFC */
+
/*
* Do not accept the invitation automatically; notify user and
* request approval.
os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
"invitation to re-invoke a persistent group");
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
} else if (!wpa_s->conf->persistent_reconnect)
return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
accept_inv:
wpas_p2p_set_own_freq_preference(wpa_s, 0);
+ best_freq = 0;
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
+ if (freqs) {
+ int num_channels = wpa_s->num_multichan_concurrent;
+ int num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, num_channels);
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+ os_free(freqs);
+ }
+
/* Get one of the frequencies currently in use */
- if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
- *force_freq = res;
- wpas_p2p_set_own_freq_preference(wpa_s, res);
+ if (best_freq > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces");
+ wpas_p2p_set_own_freq_preference(wpa_s, best_freq);
+
+ if (wpa_s->num_multichan_concurrent < 2 ||
+ wpas_p2p_num_unused_channels(wpa_s) < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces");
+ *force_freq = best_freq;
+ }
}
if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
if (status == P2P_SC_SUCCESS) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
- " was accepted; op_freq=%d MHz",
- MAC2STR(sa), op_freq);
+ " was accepted; op_freq=%d MHz, SSID=%s",
+ MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
- wpa_s->p2p_wps_method, 0);
+ wpa_s->p2p_wps_method, 0, op_freq,
+ ssid, ssid_len);
}
return;
}
ETH_ALEN) == 0)
break;
}
- if (i >= ssid->num_p2p_clients) {
+ if (i >= ssid->num_p2p_clients || !ssid->p2p_client_list) {
if (ssid->mode != WPAS_MODE_P2P_GO &&
os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
ssid->p2p_client_list + (i + 1) * ETH_ALEN,
(ssid->num_p2p_clients - i - 1) * ETH_ALEN);
ssid->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 */
}
static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels,
- const u8 *peer, int neg_freq)
+ const u8 *peer, int neg_freq,
+ int peer_oper_freq)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
"starting persistent group");
os_sleep(0, 50000);
- freq = wpa_s->p2p_persistent_go_freq;
if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
- freq_included(channels, neg_freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use frequence %d MHz from invitation for GO mode",
- neg_freq);
+ freq_included(channels, neg_freq))
freq = neg_freq;
- }
+ else if (peer_oper_freq > 0 && ssid->mode != WPAS_MODE_P2P_GO &&
+ freq_included(channels, peer_oper_freq))
+ freq = peer_oper_freq;
+ else
+ freq = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Persistent group invitation success - op_freq=%d MHz SSID=%s",
+ freq, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
+ wpa_s->p2p_persistent_go_freq,
freq,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
channels,
static int wpas_p2p_disallowed_freq(struct wpa_global *global,
unsigned int freq)
{
+ if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq))
+ return 1;
return freq_range_list_includes(&global->p2p_disallow_freq, freq);
}
{
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 "
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
};
static struct p2p_oper_class_map op_class[] = {
* removing invalid channels.
*/
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
+ { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 },
{ -1, 0, 0, 0, 0, BW20 }
};
struct hostapd_hw_modes *mode,
u8 channel, u8 bw)
{
- int flag;
+ int flag = 0;
enum chan_allowed res, res2;
res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
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);
}
-static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+struct wpa_supplicant * wpas_get_p2p_go_iface(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len)
{
- struct wpa_supplicant *wpa_s = ctx;
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ struct wpa_ssid *s = wpa_s->current_ssid;
+ if (s == NULL)
+ continue;
+ if (s->mode != WPAS_MODE_P2P_GO &&
+ s->mode != WPAS_MODE_AP &&
+ s->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+ continue;
+ if (s->ssid_len != ssid_len ||
+ os_memcmp(ssid, s->ssid, ssid_len) != 0)
+ continue;
+ return wpa_s;
+ }
+
+ return NULL;
+}
+
+
+struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s,
+ const u8 *peer_dev_addr)
+{
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)
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;
+ if (os_memcmp(wpa_s->go_dev_addr, peer_dev_addr, ETH_ALEN) == 0)
+ return wpa_s;
}
+ return NULL;
+}
+
+
+static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpas_get_p2p_client_iface(wpa_s, dev_addr) != NULL;
+}
+
+
+static int wpas_is_concurrent_session_active(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *ifs;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s)
+ continue;
+ if (ifs->wpa_state > WPA_ASSOCIATED)
+ return 1;
+ }
return 0;
}
}
-int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
+ const char *conf_p2p_dev)
{
struct wpa_interface iface;
struct wpa_supplicant *p2pdev_wpa_s;
iface.ifname = wpa_s->pending_interface_name;
iface.driver = wpa_s->driver->name;
iface.driver_param = wpa_s->conf->driver_param;
- iface.confname = wpa_s->confname;
+
+ /*
+ * If a P2P Device configuration file was given, use it as the interface
+ * configuration file (instead of using parent's configuration file.
+ */
+ if (conf_p2p_dev) {
+ iface.confname = conf_p2p_dev;
+ iface.ctrl_interface = NULL;
+ } else {
+ iface.confname = wpa_s->confname;
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+ }
+ iface.conf_p2p_dev = NULL;
+
p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
if (!p2pdev_wpa_s) {
wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
}
+static void wpas_presence_resp(void *ctx, const u8 *src, u8 status,
+ const u8 *noa, size_t noa_len)
+{
+ struct wpa_supplicant *wpa_s, *intf = ctx;
+ char hex[100];
+
+ for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_s->waiting_presence_resp)
+ break;
+ }
+ if (!wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response");
+ return;
+ }
+ wpa_s->waiting_presence_resp = 0;
+
+ wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len);
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR
+ " status=%u noa=%s", MAC2STR(src), status, hex);
+}
+
+
+static int _wpas_p2p_in_progress(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpas_p2p_in_progress(wpa_s);
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p;
- unsigned int r;
int i;
if (wpa_s->conf->p2p_disabled)
if (global->p2p)
return 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- struct p2p_params params;
-
- wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
- os_memset(¶ms, 0, sizeof(params));
- params.dev_name = wpa_s->conf->device_name;
- os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
- WPS_DEV_TYPE_LEN);
- params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
- os_memcpy(params.sec_dev_type,
- wpa_s->conf->sec_device_type,
- params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
-
- if (wpa_drv_p2p_set_params(wpa_s, ¶ms) < 0)
- return -1;
-
- return 0;
- }
-
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
p2p.invitation_result = wpas_invitation_result;
p2p.get_noa = wpas_get_noa;
p2p.go_connected = wpas_go_connected;
+ 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;
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);
p2p.config_methods = wpa_s->wps->config_methods;
}
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to configure supported channel list");
+ return -1;
+ }
+
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
p2p.channel = wpa_s->conf->p2p_listen_channel;
+ p2p.channel_forced = 1;
} else {
- p2p.reg_class = 81;
/*
* Pick one of the social channels randomly as the listen
* channel.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
+ &p2p.channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as listen channel");
+ return -1;
+ }
+ p2p.channel_forced = 0;
}
- wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
+ wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d:%d",
+ p2p.reg_class, p2p.channel);
if (wpa_s->conf->p2p_oper_reg_class &&
wpa_s->conf->p2p_oper_channel) {
"%d:%d", p2p.op_reg_class, p2p.op_channel);
} else {
- p2p.op_reg_class = 81;
/*
- * Use random operation channel from (1, 6, 11) if no other
- * preference is indicated.
+ * Use random operation channel from 2.4 GHz band social
+ * channels (1, 6, 11) or band 60 GHz social channel (2) if no
+ * other preference is indicated.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.op_channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
+ &p2p.op_channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as operation channel");
+ return -1;
+ }
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
"%d:%d", p2p.op_reg_class, p2p.op_channel);
} else
os_memcpy(p2p.country, "XX\x04", 3);
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
- wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
- "channel list");
- return -1;
- }
-
os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
WPS_DEV_TYPE_LEN);
p2p.max_listen = wpa_s->max_remain_on_chan;
+ if (wpa_s->conf->p2p_passphrase_len >= 8 &&
+ wpa_s->conf->p2p_passphrase_len <= 63)
+ p2p.passphrase_len = wpa_s->conf->p2p_passphrase_len;
+ else
+ p2p.passphrase_len = 8;
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
+ eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, 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);
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ wpas_p2p_listen_work_done(wpa_s);
+ if (wpa_s->p2p_send_action_work) {
+ os_free(wpa_s->p2p_send_action_work->ctx);
+ radio_work_done(wpa_s->p2p_send_action_work);
+ wpa_s->p2p_send_action_work = NULL;
+ }
+ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
*
* This function deinitializes the global (per device) P2P module.
*/
-void wpas_p2p_deinit_global(struct wpa_global *global)
+static void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
- if (global->p2p == NULL)
- return;
+ wpas_p2p_service_flush(global->p2p_init_wpa_s);
/* Remove remaining P2P group interfaces */
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
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,
- force_freq, persistent_group);
- }
-
/*
* Increase GO config timeout if HT40 is used since it takes some time
* to scan channels for coex purposes before the BSS can be started.
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0,
- wpa_s->p2p_pd_before_go_neg, pref_freq);
+ wpa_s->p2p_pd_before_go_neg, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
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, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0, pref_freq);
+ ssid ? ssid->ssid_len : 0, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
- int *freqs, res, num, i;
+ int res;
+ unsigned int num, i;
+ struct wpa_used_freq_data *freqs;
if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
/* Multiple channels are supported and not all are in use */
return 0;
}
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
return 1;
num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
wpa_s->num_multichan_concurrent);
- if (num < 0) {
- res = 1;
- goto exit_free;
- }
for (i = 0; i < num; i++) {
- if (freqs[i] == freq) {
+ if (freqs[i].freq == freq) {
wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
freq);
res = 0;
}
}
+ wpa_printf(MSG_DEBUG, "P2P: No valid operating frequencies");
res = 1;
exit_free:
return 0;
}
- updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+ updated = os_reltime_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,
static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss = NULL;
int freq;
u8 iface_addr[ETH_ALEN];
MAC2STR(wpa_s->
pending_join_dev_addr),
freq);
- wpas_p2p_join_scan_req(wpa_s, freq);
+ wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0);
return;
}
}
p2p_get_interface_addr(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr,
iface_addr) == 0 &&
- os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
- {
+ os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0
+ && !wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr)) {
wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
"address for join from " MACSTR " to " MACSTR
" based on newly discovered P2P peer entry",
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
- bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
+ if (wpa_s->p2p_join_ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+ MACSTR " and SSID %s",
+ MAC2STR(wpa_s->pending_join_iface_addr),
+ wpa_ssid_txt(wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len));
+ bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
+ wpa_s->p2p_join_ssid,
+ wpa_s->p2p_join_ssid_len);
+ }
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID "
+ MACSTR, MAC2STR(wpa_s->pending_join_iface_addr));
+ bss = wpa_bss_get_bssid_latest(wpa_s,
+ wpa_s->pending_join_iface_addr);
+ }
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
start:
/* Start join operation immediately */
- wpas_p2p_join_start(wpa_s);
+ wpas_p2p_join_start(wpa_s, 0, NULL, 0);
}
-static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
int ret;
struct wpa_driver_scan_params params;
/* P2P Wildcard SSID */
params.num_ssids = 1;
- params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
- params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ if (ssid && ssid_len) {
+ params.ssids[0].ssid = ssid;
+ params.ssids[0].ssid_len = ssid_len;
+ os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len);
+ wpa_s->p2p_join_ssid_len = ssid_len;
+ } else {
+ params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+ params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ wpa_s->p2p_join_ssid_len = 0;
+ }
wpa_s->wps->dev.p2p = 1;
wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
+
+ if (!freq) {
+ int oper_freq;
+ /*
+ * If freq is not provided, check the operating freq of the GO
+ * and use a single channel scan on if possible.
+ */
+ oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
+ wpa_s->pending_join_iface_addr);
+ if (oper_freq > 0)
+ freq = oper_freq;
+ }
if (freq > 0) {
freqs[0] = freq;
params.freqs = freqs;
*/
ret = wpa_drv_scan(wpa_s, ¶ms);
if (!ret) {
- os_get_time(&wpa_s->scan_trigger_time);
+ os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+ wpa_s->own_scan_requested = 1;
}
wpabuf_free(ies);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpas_p2p_join_scan_req(wpa_s, 0);
+ wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0);
}
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method,
- int auto_join)
+ int auto_join, int op_freq,
+ const u8 *ssid, size_t ssid_len)
{
wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
- MACSTR " dev " MACSTR ")%s",
- MAC2STR(iface_addr), MAC2STR(dev_addr),
+ MACSTR " dev " MACSTR " op_freq=%d)%s",
+ MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq,
auto_join ? " (auto_join)" : "");
+ if (ssid && ssid_len) {
+ wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s",
+ wpa_ssid_txt(ssid, ssid_len));
+ }
wpa_s->p2p_auto_pd = 0;
wpa_s->p2p_auto_join = !!auto_join;
wpas_p2p_stop_find(wpa_s);
wpa_s->p2p_join_scan_count = 0;
- wpas_p2p_join_scan(wpa_s, NULL);
+ wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len);
return 0;
}
-static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *ssid, size_t ssid_len)
{
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
+ os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
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_latest(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);
- wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency "
- "from BSS table: %d MHz (SSID %s)", bss->freq,
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ if (freq && ssid && ssid_len) {
+ res.freq = freq;
+ res.ssid_len = ssid_len;
+ os_memcpy(res.ssid, ssid, ssid_len);
+ } else {
+ bss = wpa_bss_get_bssid_latest(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);
+ wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
+ bss->freq,
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ }
}
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
int *force_freq, int *pref_freq, int go)
{
- int *freqs, res;
+ struct wpa_used_freq_data *freqs;
+ int res, best_freq, num_unused;
unsigned int freq_in_use = 0, num, i;
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- num = get_shared_radio_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ wpa_s->num_multichan_concurrent);
+
+ /*
+ * It is possible that the total number of used frequencies is bigger
+ * than the number of frequencies used for P2P, so get the system wide
+ * number of unused frequencies.
+ */
+ num_unused = wpas_p2p_num_unused_channels(wpa_s);
+
wpa_printf(MSG_DEBUG,
- "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
- freq, wpa_s->num_multichan_concurrent, num);
+ "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u num_unused=%d",
+ freq, wpa_s->num_multichan_concurrent, num, num_unused);
if (freq > 0) {
int ret;
}
for (i = 0; i < num; i++) {
- if (freqs[i] == freq)
+ if (freqs[i].freq == freq)
freq_in_use = 1;
}
- if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+ if (num_unused <= 0 && !freq_in_use) {
wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
freq);
res = -2;
goto exit_ok;
}
- for (i = 0; i < num; i++) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
- continue;
+ best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
- if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+ /* We have a candidate frequency to use */
+ if (best_freq > 0) {
+ if (*pref_freq == 0 && num_unused > 0) {
wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using",
- freqs[i]);
- *pref_freq = freqs[i];
+ best_freq);
+ *pref_freq = best_freq;
} else {
wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
- freqs[i]);
- *force_freq = freqs[i];
- }
- break;
- }
-
- if (i == num) {
- if (num < wpa_s->num_multichan_concurrent) {
- wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
- *force_freq = 0;
- } else {
- wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
- res = -2;
- goto exit_free;
+ best_freq);
+ *force_freq = best_freq;
}
+ } else if (num_unused > 0) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Current operating channels are not available for P2P. Try to use another channel");
+ *force_freq = 0;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
+ res = -2;
+ goto exit_free;
}
exit_ok:
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
+ wpa_s->global->p2p_fail_on_wps_complete = 0;
+
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
dev_addr);
}
if (auto_join) {
- os_get_time(&wpa_s->p2p_auto_started);
+ os_get_reltime(&wpa_s->p2p_auto_started);
wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
"%ld.%06ld",
wpa_s->p2p_auto_started.sec,
}
wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
- auto_join) < 0)
+ auto_join, freq, NULL, 0) < 0)
return -1;
return ret;
}
go_intent == 15);
if (res)
return res;
- wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
+ wpas_p2p_set_own_freq_preference(wpa_s,
+ force_freq ? force_freq : pref_freq);
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
wpa_s->pending_listen_duration);
wpa_s->pending_listen_freq = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d freq=%u duration=%u)",
+ wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+ freq, duration);
}
}
if (timeout > wpa_s->max_remain_on_chan)
timeout = wpa_s->max_remain_on_chan;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_listen(wpa_s, timeout);
-
return p2p_listen(wpa_s->global->p2p, timeout);
}
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
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_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
"channel: %d MHz", freq);
} else {
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
freq = 2412 + (r % 3) * 25;
wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
"channel: %d MHz", freq);
wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
"channel: %d MHz", freq);
} else {
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
freq = 5180 + (r % 4) * 20;
if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
wpa_printf(MSG_DEBUG, "P2P: Could not select "
}
+static int wpas_p2p_select_freq_no_pref(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params,
+ const struct p2p_channels *channels)
+{
+ unsigned int i, r;
+
+ /* first try some random selection of the social channels */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
+
+ for (i = 0; i < 3; i++) {
+ params->freq = 2412 + ((r + i) % 3) * 25;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try all channels in reg. class 81 */
+ for (i = 0; i < 11; i++) {
+ params->freq = 2412 + i * 5;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try social channel class 180 channel 2 */
+ params->freq = 58320 + 1 * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+
+ /* try all channels in reg. class 180 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 58320 + i * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4 and 60 GHz channel allowed");
+ return -1;
+out:
+ wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
+ params->freq);
+ return 0;
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int ht40, int vht,
const struct p2p_channels *channels)
{
- int res, *freqs;
- unsigned int pref_freq;
+ struct wpa_used_freq_data *freqs;
+ unsigned int pref_freq, cand_freq;
unsigned int num, i;
os_memset(params, 0, sizeof(*params));
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
"channels", params->freq);
} else {
- int chan;
- for (chan = 0; chan < 11; chan++) {
- params->freq = 2412 + chan * 5;
- if (!wpas_p2p_disallowed_freq(wpa_s->global,
- params->freq) &&
- freq_included(channels, params->freq))
- break;
- }
- if (chan == 11) {
- wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
- "allowed");
+ /* no preference, select some channel */
+ if (wpas_p2p_select_freq_no_pref(wpa_s, params, channels) < 0)
return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
- "known)", params->freq);
}
- freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ freqs = os_calloc(wpa_s->num_multichan_concurrent,
+ sizeof(struct wpa_used_freq_data));
if (!freqs)
return -1;
- res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+ num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
wpa_s->num_multichan_concurrent);
- if (res < 0) {
- os_free(freqs);
- return -1;
- }
- num = res;
- if (!freq) {
+ cand_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num);
+
+ /* First try the best used frequency if possible */
+ if (!freq && cand_freq > 0 && freq_included(channels, cand_freq)) {
+ params->freq = cand_freq;
+ } else if (!freq) {
+ /* Try any of the used frequencies */
for (i = 0; i < num; i++) {
- if (freq_included(channels, freqs[i])) {
+ if (freq_included(channels, freqs[i].freq)) {
wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
- freqs[i]);
- params->freq = freqs[i];
+ freqs[i].freq);
+ params->freq = freqs[i].freq;
break;
}
}
}
} else {
for (i = 0; i < num; i++) {
- if (freqs[i] == freq)
+ if (freqs[i].freq == freq)
break;
}
if (i == num) {
if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+ if (freq)
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
os_free(freqs);
return -1;
} else {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+ wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
}
}
}
+
os_free(freqs);
return 0;
}
static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *params, int addr_allocated)
+ struct wpa_ssid *params, int addr_allocated,
+ int freq)
{
struct wpa_ssid *ssid;
if (params->passphrase)
ssid->passphrase = os_strdup(params->passphrase);
- wpa_supplicant_select_network(wpa_s, ssid);
-
wpa_s->show_group_started = 1;
+ wpa_s->p2p_in_invitation = 1;
+ wpa_s->p2p_invite_go_freq = freq;
+
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+ NULL);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ wpa_supplicant_select_network(wpa_s, ssid);
return 0;
}
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40, int vht,
- const struct p2p_channels *channels,
+ int force_freq, int neg_freq, int ht40,
+ int vht, const struct p2p_channels *channels,
int connection_timeout)
{
struct p2p_go_neg_results params;
- int go = 0;
+ int go = 0, freq;
if (ssid->disabled != 2 || ssid->ssid == NULL)
return -1;
wpa_s->p2p_fallback_to_go_neg = 0;
+ 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 = neg_freq;
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
+
if (ssid->mode == WPAS_MODE_INFRA)
- return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
+ return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq);
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- freq = wpas_p2p_select_go_freq(wpa_s, freq);
- if (freq < 0)
- return -1;
-
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, channels))
return -1;
if (!wpa_s->ap_iface)
return;
wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
- if (idle)
+ if (idle) {
+ if (wpa_s->global->p2p_fail_on_wps_complete &&
+ wpa_s->p2p_in_provisioning) {
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+ return;
+ }
wpas_p2p_set_group_idle_timeout(wpa_s);
- else
+ } else
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
}
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return NULL;
cfg->max_clients = wpa_s->conf->max_num_sta;
os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
cfg->ssid_len = ssid->ssid_len;
+ cfg->freq = ssid->frequency;
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
}
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)
- wpa_drv_wps_success_cb(wpa_s, peer_addr);
wpas_group_formation_completed(wpa_s, 1);
}
}
wpas_notify_p2p_wps_failed(wpa_s, fail);
+
+ if (wpa_s == wpa_s->global->p2p_group_formation) {
+ /*
+ * Allow some time for the failed WPS negotiation exchange to
+ * complete, but remove the group since group formation cannot
+ * succeed after provisioning failure.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout");
+ wpa_s->global->p2p_fail_on_wps_complete = 1;
+ eloop_deplete_timeout(0, 50000,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+}
+
+
+int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->global->p2p_fail_on_wps_complete ||
+ !wpa_s->p2p_in_provisioning)
+ return 0;
+
+ wpas_p2p_grpform_fail_after_wps(wpa_s);
+
+ return 1;
}
wpa_s->auto_pd_scan_retry = 0;
wpas_p2p_stop_find(wpa_s);
wpa_s->p2p_join_scan_count = 0;
- os_get_time(&wpa_s->p2p_auto_started);
+ os_get_reltime(&wpa_s->p2p_auto_started);
wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
wpa_s->p2p_auto_started.sec,
wpa_s->p2p_auto_started.usec);
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,
- use == WPAS_P2P_PD_FOR_JOIN);
- }
-
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return -1;
if (!offchannel_pending_action_tx(wpa_s))
return;
+ wpas_p2p_action_tx_clear(wpa_s);
+
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
offchannel_clear_pending_action_tx(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_find(wpa_s, timeout, type);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning)
return -1;
}
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+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;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->global->p2p_cb_on_scan_complete = 0;
-
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
- wpa_drv_p2p_stop_find(wpa_s);
- return 1;
- }
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
-
- return 0;
}
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);
}
if (wpa_s->global->p2p_disabled)
return -1;
+ if (wpa_s->conf->p2p_disabled)
+ return -1;
if (wpa_s->global->p2p == NULL)
return -1;
if (bss == NULL)
}
-void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
{
p2p_group_deinit(wpa_s->p2p_group);
wpa_s->p2p_group = NULL;
{
wpa_s->p2p_long_listen = 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return wpa_drv_p2p_reject(wpa_s, addr);
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
u8 *bssid = NULL;
int force_freq = 0;
int res;
+ int no_pref_freq_given = pref_freq == 0;
wpa_s->global->p2p_invite_group = NULL;
if (peer_addr)
if (res)
return res;
- 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, 1);
-
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, force_freq, go_dev_addr,
- 1, pref_freq);
+ if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+ no_pref_freq_given && pref_freq > 0 &&
+ wpa_s->num_multichan_concurrent > 1 &&
+ wpas_p2p_num_unused_channels(wpa_s) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration",
+ pref_freq);
+ pref_freq = 0;
+ }
+
+ 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);
}
}
wpa_s->parent->pending_invite_ssid_id = -1;
- 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, 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, force_freq,
- go_dev_addr, persistent, pref_freq);
+ go_dev_addr, persistent, pref_freq, -1);
}
void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
{
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;
+ u8 ip[3 * 4];
+ char ip_addr[100];
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
}
if (!wpa_s->show_group_started || !ssid)
- goto done;
+ return;
wpa_s->show_group_started = 0;
- ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
os_memset(go_dev_addr, 0, ETH_ALEN);
if (ssid->bssid_set)
os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN);
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_global(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, freq, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
- } else {
- wpa_msg_global(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, freq,
- ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "");
+
+ 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]);
}
+ wpas_p2p_group_started(wpa_s, 0, ssid, freq,
+ ssid->passphrase == NULL && ssid->psk_set ?
+ ssid->psk : NULL,
+ ssid->passphrase, go_dev_addr, persistent,
+ ip_addr);
+
if (persistent)
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);
-
-done:
- wpas_p2p_continue_after_scan(wpa_s);
}
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
u32 interval1, u32 duration2, u32 interval2)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
return -1;
- return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->assoc_freq,
- duration1, interval1, duration2, interval2);
+ ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->assoc_freq,
+ duration1, interval1, duration2, interval2);
+ if (ret == 0)
+ wpa_s->waiting_presence_resp = 1;
+
+ return ret;
}
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval)
{
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return 0;
if (!locally_generated)
p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
if (!locally_generated)
p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
u8 reg_class, channel;
int ret;
unsigned int r;
+ u8 channel_forced;
+
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;
+ channel_forced = 1;
} 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;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ channel = 1;
+ else
+ channel = 1 + (r % 3) * 5;
+ channel_forced = 0;
}
- ret = p2p_set_listen_channel(p2p, reg_class, channel);
+ ret = p2p_set_listen_channel(p2p, reg_class, channel,
+ channel_forced);
if (ret)
wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
"failed: %d", ret);
* 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;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ op_channel = 1;
+ else
+ op_channel = 1 + (r % 3) * 5;
cfg_op_channel = 0;
}
ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
"update failed");
}
}
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PASSPHRASE_LEN)
+ p2p_set_passphrase_len(p2p, wpa_s->conf->p2p_passphrase_len);
}
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return -1;
wpa_s->global->cross_connection = enabled;
p2p_set_cross_connect(wpa_s->global->p2p, enabled);
}
+void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_notif_pbc_overlap(wpa_s);
+}
+
+
void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
{
struct p2p_channels chan, cli_chan;
+ struct wpa_supplicant *ifs;
if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
return;
}
p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ int freq;
+ if (!ifs->current_ssid ||
+ !ifs->current_ssid->p2p_group ||
+ (ifs->current_ssid->mode != WPAS_MODE_P2P_GO &&
+ ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION))
+ continue;
+ freq = ifs->current_ssid->frequency;
+ if (freq_included(&chan, freq)) {
+ wpa_dbg(ifs, MSG_DEBUG,
+ "P2P GO operating frequency %d MHz in valid range",
+ freq);
+ continue;
+ }
+
+ wpa_dbg(ifs, MSG_DEBUG,
+ "P2P GO operating in invalid frequency %d MHz", freq);
+ /* TODO: Consider using CSA or removing the group within
+ * wpa_supplicant */
+ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
+ }
}
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_REQUESTED);
break;
+ } else if (wpa_s->p2p_in_invitation) {
+ wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
+ wpa_s->ifname);
+ found = 1;
+ wpas_p2p_group_formation_failed(wpa_s);
}
}
int freq_24, int freq_5, int freq_overall)
{
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return;
p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
}
u8 peer[ETH_ALEN];
struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+ if (p2p == NULL)
return -1;
if (hwaddr_aton(addr, peer))
}
if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
- struct os_time now;
- os_get_time(&now);
- if (now.sec > wpa_s->global->p2p_go_wait_client.sec +
- P2P_MAX_INITIAL_CONN_WAIT_GO) {
+ struct os_reltime now;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client,
+ P2P_MAX_INITIAL_CONN_WAIT_GO)) {
/* Wait for the first client has expired */
wpa_s->global->p2p_go_wait_client.sec = 0;
} else {
* provisioning step.
*/
wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+
+ if (!wpa_s->p2p_go_group_formation_completed &&
+ !wpa_s->group_formation_reported) {
+ /*
+ * GO has not yet notified group formation success since
+ * the WPS step was not completed cleanly. Do that
+ * notification now since the P2P Client was able to
+ * connect and as such, must have received the
+ * credential from the WPS step.
+ */
+ if (wpa_s->global->p2p)
+ p2p_wps_success_cb(wpa_s->global->p2p, addr);
+ wpas_group_formation_completed(wpa_s, 1);
+ }
}
if (!wpa_s->p2p_go_group_formation_completed) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
wpa_s->p2p_go_group_formation_completed = 1;
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
+ wpa_s->p2p_in_invitation = 0;
}
wpa_s->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
{
- const char *rn, *rn2;
struct wpa_supplicant *ifs;
if (wpa_s->wpa_state > WPA_SCANNING) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
"concurrent operation",
- P2P_CONCURRENT_SEARCH_DELAY);
- return P2P_CONCURRENT_SEARCH_DELAY;
+ wpa_s->conf->p2p_search_delay);
+ return wpa_s->conf->p2p_search_delay;
}
- if (!wpa_s->driver->get_radio_name)
- return 0;
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
- return 0;
-
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
- continue;
-
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (!rn2 || os_strcmp(rn, rn2) != 0)
- continue;
- if (ifs->wpa_state > WPA_SCANNING) {
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs != wpa_s && ifs->wpa_state > WPA_SCANNING) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
"delay due to concurrent operation on "
"interface %s",
- P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
- return P2P_CONCURRENT_SEARCH_DELAY;
+ wpa_s->conf->p2p_search_delay,
+ ifs->ifname);
+ return wpa_s->conf->p2p_search_delay;
}
}
}
-void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
-{
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
- "pending anymore (sta_scan_pending=%d "
- "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
- wpa_s->global->p2p_cb_on_scan_complete);
- wpa_s->sta_scan_pending = 0;
-
- if (!wpa_s->global->p2p_cb_on_scan_complete)
- return;
- wpa_s->global->p2p_cb_on_scan_complete = 0;
-
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
- return;
-
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after successful connection");
- p2p_increase_search_delay(wpa_s->global->p2p,
- wpas_p2p_search_delay(wpa_s));
- }
-}
-
-
static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s,
struct wpa_ssid *s, const u8 *addr,
int iface_addr)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
struct wpa_ssid *persistent;
- struct psk_list_entry *p;
+ struct psk_list_entry *p, *last;
if (psk_len != sizeof(p->psk))
return;
}
os_memcpy(p->psk, psk, psk_len);
- if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS) {
- struct psk_list_entry *last;
- last = dl_list_last(&persistent->psk_list,
- struct psk_list_entry, list);
+ if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS &&
+ (last = dl_list_last(&persistent->psk_list,
+ struct psk_list_entry, list))) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for "
MACSTR " (p2p=%u) to make room for a new one",
MAC2STR(last->addr), last->p2p);
}
dl_list_add(&persistent->psk_list, &p->list);
-#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 res;
res = wpas_p2p_remove_psk_entry(wpa_s, s, addr, iface_addr);
- if (res > 0) {
-#ifndef CONFIG_NO_CONFIG_WRITE
- if (wpa_s->conf->update_config &&
- wpa_config_write(wpa_s->confname, wpa_s->conf))
- wpa_dbg(wpa_s, MSG_DEBUG,
- "P2P: Failed to update configuration");
-#endif /* CONFIG_NO_CONFIG_WRITE */
- }
+ if (res > 0 && wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to update configuration");
}
}
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_supplicant *iface;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!iface->current_ssid ||
+ iface->current_ssid->frequency == freq ||
+ (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ !iface->current_ssid->p2p_group))
+ continue;
+
+ /* Remove the connection with least priority */
+ if (!wpas_is_p2p_prioritized(iface)) {
+ /* STA connection has priority over existing
+ * P2P connection, so remove the interface. */
+ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+ eloop_register_timeout(0, 0,
+ wpas_p2p_group_freq_conflict,
+ iface, NULL);
+ /* If connection in progress is P2P connection, do not
+ * proceed for the connection. */
+ if (wpa_s == iface)
+ return -1;
+ else
+ return 0;
+ } else {
+ /* P2P connection has priority, disable the STA network
+ */
+ wpa_supplicant_disable_network(wpa_s->global->ifaces,
+ ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+ WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+ ETH_ALEN);
+ /* If P2P connection is in progress, continue
+ * connecting...*/
+ if (wpa_s == iface)
+ return 0;
+ else
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_s->p2p_last_4way_hs_fail = ssid;
return 0;
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc,
+ struct wpabuf *p2p)
+{
+ struct wpabuf *ret;
+ size_t wsc_len;
+
+ if (p2p == NULL) {
+ wpabuf_free(wsc);
+ wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover");
+ return NULL;
+ }
+
+ wsc_len = wsc ? wpabuf_len(wsc) : 0;
+ ret = wpabuf_alloc(2 + wsc_len + 2 + wpabuf_len(p2p));
+ if (ret == NULL) {
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ return NULL;
+ }
+
+ wpabuf_put_be16(ret, wsc_len);
+ if (wsc)
+ wpabuf_put_buf(ret, wsc);
+ wpabuf_put_be16(ret, wpabuf_len(p2p));
+ wpabuf_put_buf(ret, p2p);
+
+ wpabuf_free(wsc);
+ wpabuf_free(p2p);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "P2P: Generated NFC connection handover message", ret);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_p2p(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request");
+ return NULL;
+ }
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+static int wpas_p2p_cli_freq(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **ssid, u8 *go_dev_addr)
+{
+ struct wpa_supplicant *iface;
+
+ if (go_dev_addr)
+ os_memset(go_dev_addr, 0, ETH_ALEN);
+ if (ssid)
+ *ssid = NULL;
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (iface->wpa_state < WPA_ASSOCIATING ||
+ iface->current_ssid == NULL || iface->assoc_freq == 0 ||
+ !iface->current_ssid->p2p_group ||
+ iface->current_ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (ssid)
+ *ssid = iface->current_ssid;
+ if (go_dev_addr)
+ os_memcpy(go_dev_addr, iface->go_dev_addr, ETH_ALEN);
+ return iface->assoc_freq;
+ }
+ return 0;
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request");
+ return NULL;
+ }
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request");
+ return NULL;
+ }
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_req_p2p(
+ wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int tag)
+{
+ struct wpabuf *wsc, *p2p;
+ struct wpa_ssid *ssid;
+ u8 go_dev_addr[ETH_ALEN];
+ int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr);
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return NULL;
+
+ if (!tag && wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+
+ if (cli_freq == 0) {
+ wsc = wps_build_nfc_handover_sel_p2p(
+ wpa_s->parent->wps,
+ tag ? wpa_s->conf->wps_nfc_dev_pw_id :
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ tag ? wpa_s->conf->wps_nfc_dev_pw : NULL);
+ } else
+ wsc = NULL;
+ p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p, cli_freq,
+ go_dev_addr, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+
+ return wpas_p2p_nfc_handover(ndef, wsc, p2p);
+}
+
+
+static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
+ "connection handover (freq=%d)",
+ params->go_freq);
+
+ if (params->go_freq && params->go_ssid_len) {
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr,
+ ETH_ALEN);
+ return wpas_p2p_join_start(wpa_s, params->go_freq,
+ params->go_ssid,
+ params->go_ssid_len);
+ }
+
+ return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
+ params->go_freq, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params, int tag)
+{
+ int res, persistent;
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC "
+ "connection handover");
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ continue;
+ if (ssid->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (wpa_s->ap_iface == NULL)
+ continue;
+ break;
+ }
+ if (wpa_s == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface");
+ return -1;
+ }
+
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->p2p_oob_dev_pw) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+ return -1;
+ }
+ res = wpas_ap_wps_add_nfc_pw(
+ wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ if (res)
+ return res;
+
+ if (!tag) {
+ wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation");
+ return 0;
+ }
+
+ if (!params->peer ||
+ !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR
+ " to join", MAC2STR(params->peer->p2p_device_addr));
+
+ wpa_s->global->p2p_invite_group = wpa_s;
+ persistent = ssid->p2p_persistent_group &&
+ wpas_p2p_get_persistent(wpa_s->parent,
+ params->peer->p2p_device_addr,
+ ssid->ssid, ssid->ssid_len);
+ wpa_s->parent->pending_invite_ssid_id = -1;
+
+ return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
+ P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
+ ssid->ssid, ssid->ssid_len, ssid->frequency,
+ wpa_s->global->p2p_dev_addr, persistent, 0,
+ wpa_s->parent->p2p_oob_dev_pw_id);
+}
+
+
+static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC "
+ "connection handover");
+ return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
+ forced_freq, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params,
+ int forced_freq)
+{
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC "
+ "connection handover");
+ res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
+ forced_freq, -1, 0, 1, 1);
+ if (res)
+ return res;
+
+ res = wpas_p2p_listen(wpa_s, 60);
+ if (res) {
+ p2p_unauthorize(wpa_s->global->p2p,
+ params->peer->p2p_device_addr);
+ }
+
+ return res;
+}
+
+
+static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data,
+ int sel, int tag, int forced_freq)
+{
+ const u8 *pos, *end;
+ u16 len, id;
+ struct p2p_nfc_params params;
+ int res;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.sel = sel;
+
+ wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data);
+
+ pos = wpabuf_head(data);
+ end = pos + wpabuf_len(data);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
+ "attributes");
+ return -1;
+ }
+ params.wsc_attr = pos;
+ params.wsc_len = len;
+ pos += len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
+ "attributes");
+ return -1;
+ }
+ params.p2p_attr = pos;
+ params.p2p_len = len;
+ pos += len;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes",
+ params.wsc_attr, params.wsc_len);
+ wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes",
+ params.p2p_attr, params.p2p_len);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "P2P: Ignored extra data after P2P attributes",
+ pos, end - pos);
+ }
+
+ res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, ¶ms);
+ if (res)
+ return res;
+
+ if (params.next_step == NO_ACTION)
+ return 0;
+
+ if (params.next_step == BOTH_GO) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_BOTH_GO "peer=" MACSTR,
+ MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ if (params.next_step == PEER_CLIENT) {
+ if (!is_zero_ether_addr(params.go_dev_addr)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d go_dev_addr=" MACSTR
+ " ssid=\"%s\"",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq,
+ MAC2STR(params.go_dev_addr),
+ wpa_ssid_txt(params.go_ssid,
+ params.go_ssid_len));
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT
+ "peer=" MACSTR " freq=%d",
+ MAC2STR(params.peer->p2p_device_addr),
+ params.go_freq);
+ }
+ return 0;
+ }
+
+ if (wpas_p2p_cli_freq(wpa_s, NULL, NULL)) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_WHILE_CLIENT "peer="
+ MACSTR, MAC2STR(params.peer->p2p_device_addr));
+ return 0;
+ }
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
+ if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw "
+ "received");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id);
+ wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash",
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash,
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_s->p2p_peer_oob_pk_hash_known = 1;
+
+ if (tag) {
+ if (id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
+ "peer OOB Device Password Id %u", id);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB "
+ "Device Password Id %u", id);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password",
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ wpa_s->p2p_oob_dev_pw_id = id;
+ wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy(
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake "
+ "without Device Password");
+ wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ }
+
+ switch (params.next_step) {
+ case NO_ACTION:
+ case BOTH_GO:
+ case PEER_CLIENT:
+ /* already covered above */
+ return 0;
+ case JOIN_GROUP:
+ return wpas_p2p_nfc_join_group(wpa_s, ¶ms);
+ case AUTH_JOIN:
+ return wpas_p2p_nfc_auth_join(wpa_s, ¶ms, tag);
+ case INIT_GO_NEG:
+ return wpas_p2p_nfc_init_go_neg(wpa_s, ¶ms, forced_freq);
+ case RESP_GO_NEG:
+ /* TODO: use own OOB Dev Pw */
+ return wpas_p2p_nfc_resp_go_neg(wpa_s, ¶ms, forced_freq);
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data, int forced_freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ return wpas_p2p_nfc_connection_handover(wpa_s, data, 1, 1, forced_freq);
+}
+
+
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel, int forced_freq)
+{
+ struct wpabuf *tmp;
+ int ret;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported");
+
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req",
+ wpabuf_head(req), wpabuf_len(req));
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel",
+ wpabuf_head(sel), wpabuf_len(sel));
+ if (forced_freq)
+ wpa_printf(MSG_DEBUG, "NFC: Forced freq %d", forced_freq);
+ tmp = ndef_parse_p2p(init ? sel : req);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF");
+ return -1;
+ }
+
+ ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0,
+ forced_freq);
+ wpabuf_free(tmp);
+
+ return ret;
+}
+
+
+int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
+{
+ const u8 *if_addr;
+ int go_intent = wpa_s->conf->p2p_go_intent;
+ struct wpa_supplicant *iface;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG, "P2P: Disable use of own NFC Tag");
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+ {
+ if (!iface->ap_iface)
+ continue;
+ hostapd_wps_nfc_token_disable(iface->ap_iface->bss[0]);
+ }
+ p2p_set_authorized_oob_dev_pw_id(wpa_s->global->p2p, 0,
+ 0, NULL);
+ if (wpa_s->p2p_nfc_tag_enabled)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
+ wpa_s->p2p_nfc_tag_enabled = 0;
+ return 0;
+ }
+
+ if (wpa_s->global->p2p_disabled)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw_id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: NFC password token not configured "
+ "to allow static handover cases");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Enable use of own NFC Tag");
+
+ wpa_s->p2p_oob_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+ wpa_s->p2p_peer_oob_pk_hash_known = 0;
+
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO ||
+ wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) {
+ /*
+ * P2P Group Interface present and the command came on group
+ * interface, so enable the token for the current interface.
+ */
+ wpa_s->create_p2p_iface = 0;
+ } else {
+ wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+ }
+
+ if (wpa_s->create_p2p_iface) {
+ enum wpa_driver_if_type iftype;
+ /* 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;
+ }
+
+ if_addr = wpa_s->pending_interface_addr;
+ } else
+ if_addr = wpa_s->own_addr;
+
+ wpa_s->p2p_nfc_tag_enabled = enabled;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ struct hostapd_data *hapd;
+ if (iface->ap_iface == NULL)
+ continue;
+ hapd = iface->ap_iface->bss[0];
+ wpabuf_free(hapd->conf->wps_nfc_dh_pubkey);
+ hapd->conf->wps_nfc_dh_pubkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ wpabuf_free(hapd->conf->wps_nfc_dh_privkey);
+ hapd->conf->wps_nfc_dh_privkey =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ wpabuf_free(hapd->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw =
+ wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw);
+ hapd->conf->wps_nfc_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id;
+
+ if (hostapd_wps_nfc_token_enable(iface->ap_iface->bss[0]) < 0) {
+ wpa_dbg(iface, MSG_DEBUG,
+ "P2P: Failed to enable NFC Tag for GO");
+ }
+ }
+ p2p_set_authorized_oob_dev_pw_id(
+ wpa_s->global->p2p, wpa_s->conf->wps_nfc_dev_pw_id, go_intent,
+ if_addr);
+
+ return 0;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs,
+ unsigned int num)
+{
+ u8 curr_chan, cand, chan;
+ unsigned int i;
+
+ curr_chan = p2p_get_listen_channel(wpa_s->global->p2p);
+ for (i = 0, cand = 0; i < num; i++) {
+ ieee80211_freq_to_chan(freqs[i].freq, &chan);
+ if (curr_chan == chan) {
+ cand = 0;
+ break;
+ }
+
+ if (chan == 1 || chan == 6 || chan == 11)
+ cand = chan;
+ }
+
+ if (cand) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Update Listen channel to %u baased on operating channel",
+ cand);
+ p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
+ }
+}
+
+
+void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_used_freq_data *freqs;
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ /*
+ * If possible, optimize the Listen channel to be a channel that is
+ * already used by one of the other interfaces.
+ */
+ if (!wpa_s->conf->p2p_optimize_listen_chan)
+ return;
+
+ if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
+ return;
+
+ freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
+ if (!freqs)
+ return;
+
+ num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+
+ wpas_p2p_optimize_listen_channel(wpa_s, freqs, num);
+ os_free(freqs);
+}
+
+
+void wpas_p2p_deinit_iface(struct wpa_supplicant *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");
+ wpas_p2p_deinit_global(wpa_s->global);
+ }
+}
+
+
+void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->ap_iface->bss)
+ wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+ wpas_p2p_group_deinit(wpa_s);
+}