#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 {
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;
}
}
+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_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
+ unsigned int num_channels = 0;
+ int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
- u8 *n;
+ u8 *n, i;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
switch (type) {
case P2P_SCAN_SOCIAL:
- params->freqs = os_malloc(4 * sizeof(int));
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
+ sizeof(int));
if (params->freqs == NULL)
goto fail;
- params->freqs[0] = 2412;
- params->freqs[1] = 2437;
- params->freqs[2] = 2462;
- params->freqs[3] = 0;
+ 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:
- params->freqs = os_malloc(5 * sizeof(int));
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
+ sizeof(int));
if (params->freqs == NULL)
goto fail;
- params->freqs[0] = 2412;
- params->freqs[1] = 2437;
- params->freqs[2] = 2462;
- params->freqs[3] = freq;
- params->freqs[4] = 0;
+ 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;
}
}
+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,
*/
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_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,
}
+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);
+}
+
+
static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
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);
}
}
-static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
- unsigned int freq,
- const u8 *dst, const u8 *src,
- const u8 *bssid,
- const u8 *data, size_t data_len,
- enum offchannel_send_action_result
- result)
+static void wpas_p2p_action_tx_clear(struct wpa_supplicant *wpa_s)
{
- enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
-
if (wpa_s->p2p_send_action_work) {
struct send_action_work *awork;
awork = wpa_s->p2p_send_action_work->ctx;
wpa_s, NULL);
}
}
+}
+
+
+static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result
+ result)
+{
+ 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;
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
+ 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),
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]" : "");
- }
+ 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) {
}
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;
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%s%s",
+ "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,
wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
- wfd_dev_info_hex ? wfd_dev_info_hex : "");
+ 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 */
{
struct wpa_supplicant *wpa_s = work->wpa_s;
struct wpas_p2p_listen_work *lwork = work->ctx;
+ unsigned int duration;
if (deinit) {
if (work->started) {
wpa_s->pending_listen_freq = lwork->freq;
wpa_s->pending_listen_duration = lwork->duration;
- if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
- {
+ duration = lwork->duration;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ duration, duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
"state", lwork->freq);
}
+/**
+ * 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,
{
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
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) {
+ 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, res);
+ 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 = res;
+ *force_freq = best_freq;
}
}
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 "
{
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 }
};
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 0;
+ 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;
}
}
-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;
* If a P2P Device configuration file was given, use it as the interface
* configuration file (instead of using parent's configuration file.
*/
- if (wpa_s->conf_p2p_dev) {
- iface.confname = wpa_s->conf_p2p_dev;
+ if (conf_p2p_dev) {
+ iface.confname = conf_p2p_dev;
iface.ctrl_interface = NULL;
} else {
iface.confname = wpa_s->confname;
}
+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)
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;
*
* 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)
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:
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",
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 && num > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
- *force_freq = 0;
- } else if (num < wpa_s->num_multichan_concurrent) {
- wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new 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:
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;
- for (i = 0; i < num; i++) {
- if (freq && freqs[i] == freq)
- break;
- if (!freq && freq_included(channels, freqs[i])) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
- freqs[i]);
- params->freq = freqs[i];
- break;
+ 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].freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+ freqs[i].freq);
+ params->freq = freqs[i].freq;
+ break;
+ }
}
- }
- if (i == num) {
- if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
- if (freq)
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
- else
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
- os_free(freqs);
- return -1;
- } else if (num == 0) {
- wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels");
- } else {
- wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+ 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");
+ }
+ }
+ } else {
+ for (i = 0; i < num; i++) {
+ if (freqs[i].freq == freq)
+ break;
+ }
+
+ if (i == num) {
+ if (wpas_p2p_num_unused_channels(wpa_s) <= 0) {
+ 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: Use one of the free channels");
+ }
}
}
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;
wpa_s->p2p_fallback_to_go_neg = 0;
- if (force_freq > 0) {
- freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
- if (freq < 0)
- return -1;
+ if (ssid->mode == WPAS_MODE_P2P_GO) {
+ if (force_freq > 0) {
+ freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+ if (freq < 0)
+ return -1;
+ } else {
+ freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
} else {
- freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
- if (freq < 0 || (freq > 0 && !freq_included(channels, freq)))
+ freq = neg_freq;
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
freq = 0;
}
if (!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);
}
-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;
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;
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;
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);
ip[8], ip[9], ip[10], ip[11]);
}
- 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%s",
- wpa_s->ifname, ssid_txt, freq, psk,
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "", ip_addr);
- } 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%s",
- wpa_s->ifname, ssid_txt, freq,
- ssid->passphrase ? ssid->passphrase : "",
- MAC2STR(go_dev_addr),
- persistent ? " [PERSISTENT]" : "", ip_addr);
- }
+ 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,
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);
}
}
+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);
}
}
* 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)
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;
}
dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
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;
}
}
{
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);
}
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
"attributes");
return -1;
}
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
"attributes");
return -1;
}
#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);
+}