return;
}
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params->only_new_results = 1;
+ }
ret = wpa_drv_scan(wpa_s, params);
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
}
conncap = P2PS_SETUP_GROUP_OWNER;
goto grp_owner;
}
+ /* fall through */
default:
return P2PS_SETUP_NONE;
wpa_s->own_addr);
} else if (!s && !go_wpa_s) {
if (wpas_p2p_add_group_interface(wpa_s,
- WPA_IF_P2P_GO) < 0) {
+ WPA_IF_P2P_GROUP) < 0) {
wpa_printf(MSG_ERROR,
"P2P: Failed to allocate a new interface for the group");
return P2PS_SETUP_NONE;
os_free(wpa_s->p2p_group_common_freqs);
wpa_s->p2p_group_common_freqs = NULL;
wpa_s->p2p_group_common_freqs_num = 0;
+ wpa_s->p2p_go_do_acs = 0;
wpa_s->waiting_presence_resp = 0;
"go_dev_addr=" MACSTR,
MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
- return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
}
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
/*
* This callback is likely called for the main interface. Update wpa_s
if (wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
+ } else if (wpa_s->p2p_in_provisioning && !success) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "P2P: Stop provisioning state due to failure");
+ wpa_s->p2p_in_provisioning = 0;
}
wpa_s->p2p_in_invitation = 0;
wpa_s->group_formation_reported = 1;
}
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
}
- if (network_id < 0 && ssid)
- network_id = ssid->id;
+
if (!client) {
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL);
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
}
}
{
struct send_action_work *awork;
- if (wpa_s->p2p_send_action_work) {
+ if (radio_work_pending(wpa_s, "p2p-send-action")) {
wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
return -1;
}
awork->wait_time = wait_time;
os_memcpy(awork->buf, buf, len);
- if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+ if (radio_add_work(wpa_s, freq, "p2p-send-action", 1,
wpas_send_action_cb, awork) < 0) {
os_free(awork);
return -1;
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)
+ size_t len, unsigned int wait_time, int *scheduled)
{
struct wpa_supplicant *wpa_s = ctx;
int listen_freq = -1, send_freq = -1;
+ if (scheduled)
+ *scheduled = 0;
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);
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)",
+ listen_freq, send_freq, freq);
+ res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+ len, wait_time);
+ if (res == 0 && scheduled)
+ *scheduled = 1;
+ return res;
}
wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
if (res->wps_method == WPS_PBC) {
- wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+ wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0);
#ifdef CONFIG_WPS_NFC
} else if (res->wps_method == WPS_NFC) {
wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
{
+ char buf[20 + P2P_MAX_CHANNELS * 6];
+ char *pos, *end;
unsigned int i;
+ int res;
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
- wpa_s->p2p_group_common_freqs_num);
+ pos = buf;
+ end = pos + sizeof(buf);
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ res = os_snprintf(pos, end - pos, " %d",
+ wpa_s->p2p_group_common_freqs[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
- for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
- wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
- i, wpa_s->p2p_group_common_freqs[i]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies:%s", buf);
}
struct wpa_supplicant *wpa_s = ctx;
struct p2p_go_neg_results *params = data;
struct wpa_ssid *ssid;
- int network_id = -1;
wpa_s->ap_configured_cb = NULL;
wpa_s->ap_configured_cb_ctx = NULL;
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
- network_id = wpas_p2p_store_persistent_group(
+ wpas_p2p_store_persistent_group(
wpa_s->p2pdev, ssid,
wpa_s->global->p2p_dev_addr);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid,
+ params->persistent_group, 0,
+ NULL);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
- ssid->p2p_persistent_group = params->persistent_group;
+ ssid->p2p_persistent_group = !!params->persistent_group;
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->vht = params->vht;
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
+ ssid->he = params->he;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
d = dst->conf;
s = src->conf;
-#define C(n) if (s->n) d->n = os_strdup(s->n)
+#define C(n) \
+do { \
+ if (s->n && !d->n) \
+ d->n = os_strdup(s->n); \
+} while (0)
+
C(device_name);
C(manufacturer);
C(model_name);
d->disable_scan_offload = s->disable_scan_offload;
d->passive_scan = s->passive_scan;
- if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
- d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
- d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
- }
- d->p2p_cli_probe = s->p2p_cli_probe;
-}
-
-
-static void wpas_p2p_clone_config_dh(struct wpa_supplicant *dst,
- const struct wpa_supplicant *src)
-{
- struct wpa_config *d;
- const struct wpa_config *s;
-
- d = dst->conf;
- s = src->conf;
-
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
- !d->wps_nfc_dh_privkey && !d->wps_nfc_dh_pubkey) {
+ !d->wps_nfc_pw_from_config) {
+ wpabuf_free(d->wps_nfc_dh_privkey);
+ wpabuf_free(d->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);
}
+ d->p2p_cli_probe = s->p2p_cli_probe;
+ d->go_interworking = s->go_interworking;
+ d->go_access_network_type = s->go_access_network_type;
+ d->go_internet = s->go_internet;
+ d->go_venue_group = s->go_venue_group;
+ d->go_venue_type = s->go_venue_type;
}
return -1;
}
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ random_mac_addr(wpa_s->pending_interface_addr);
+ wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
if (force_ifname[0]) {
wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
force_ifname);
wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ if (wpa_drv_set_mac_addr(group_wpa_s,
+ wpa_s->pending_interface_addr) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
return group_wpa_s;
}
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ if (wpa_s->p2p_go_he)
+ res->he = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
group_wpa_s = wpa_s->parent;
wpa_s->global->p2p_group_formation = group_wpa_s;
if (group_wpa_s != wpa_s)
- wpas_p2p_clone_config_dh(group_wpa_s, wpa_s);
+ wpas_p2p_clone_config(group_wpa_s, wpa_s);
}
group_wpa_s->p2p_in_provisioning = 1;
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
}
-enum chan_allowed {
- NOT_ALLOWED, NO_IR, ALLOWED
-};
-
static int has_channel(struct wpa_global *global,
struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
u8 channel)
{
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
- unsigned int i;
+ size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
/* Remove stale persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ s->id);
+ wpas_notify_persistent_group_removed(wpa_s, s);
wpa_config_remove_network(wpa_s->conf, s->id);
save_config = 1;
continue;
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
}
/* Remove stale persistent group */
if (stale->mode != WPAS_MODE_P2P_GO ||
stale->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ stale->id);
+ wpas_notify_persistent_group_removed(wpa_s, stale);
wpa_config_remove_network(wpa_s->conf, stale->id);
} else {
size_t i;
if (persistent_go && s != persistent_go &&
!persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
/* Save config */
return;
}
+ wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
+
if (conncap == P2PS_SETUP_GROUP_OWNER) {
/*
* We need to copy the interface name. Simply saving a
go_ifname[0] = '\0';
if (!go_wpa_s) {
- wpa_s->global->pending_p2ps_group = 1;
- wpa_s->global->pending_p2ps_group_freq = freq;
+ if (!response_done) {
+ wpa_s->global->pending_p2ps_group = 1;
+ wpa_s->global->pending_p2ps_group_freq = freq;
+ }
if (!wpas_p2p_create_iface(wpa_s))
os_memcpy(go_ifname, wpa_s->ifname,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq,
+ 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s, persistent_go);
wpa_config_remove_network(wpa_s->conf, persistent_go->id);
}
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
}
return 1;
}
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
+{
+ u8 addr[ETH_ALEN] = {0};
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 0)
+ return 0;
+
+ if (!wpa_s->conf->ssid) {
+ if (random_mac_addr(addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to generate random MAC address");
+ return -EINVAL;
+ }
+
+ /* Store generated MAC address. */
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr, addr,
+ ETH_ALEN);
+ } else {
+ /* If there are existing saved groups, restore last MAC address.
+ * if there is no last used MAC address, the last one is
+ * factory MAC. */
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr))
+ return 0;
+ os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr,
+ ETH_ALEN);
+ wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address.");
+ }
+
+ if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ return -EINVAL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -EINVAL;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+ MAC2STR(addr));
+
+ return 0;
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
if (global->p2p)
return 0;
+ if (wpas_p2p_mac_setup(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to initialize P2P random MAC address.");
+ return -1;
+ }
+
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
* channel.
*/
if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
- &p2p.channel) != 0) {
+ &p2p.channel,
+ &global->p2p_go_avoid_freq,
+ &global->p2p_disallow_freq) !=
+ 0) {
wpa_printf(MSG_INFO,
"P2P: No social channels supported by the driver - do not enable P2P");
return 0;
* other preference is indicated.
*/
if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
- &p2p.op_channel) != 0) {
- wpa_printf(MSG_ERROR,
+ &p2p.op_channel, NULL,
+ NULL) != 0) {
+ wpa_printf(MSG_INFO,
"P2P: Failed to select random social channel as operation channel");
- return -1;
+ p2p.op_reg_class = 0;
+ p2p.op_channel = 0;
+ /* This will be overridden during group setup in
+ * p2p_prepare_channel(), so allow setup to continue. */
}
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
NULL, 0);
return;
}
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params.only_new_results = 1;
+ }
+
/*
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
}
wpabuf_free(ies);
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
- } else {
- /*
- * Need to mark the current interface for p2p_group_formation
- * when a separate group interface is not used. This is needed
- * to allow p2p_cancel stop a pending p2p_connect-join.
- * wpas_p2p_init_group_interface() addresses this for the case
- * where a separate group interface is used.
- */
- wpa_s->global->p2p_group_formation = wpa_s;
}
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ if (group == wpa_s->parent)
+ wpa_s->global->p2p_group_formation = group;
+
group->p2p_in_provisioning = 1;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
if (!ret) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded
* to the driver, allow P2P GO to use it.
if (!res && max_pref_freq > 0) {
*num_pref_freq = max_pref_freq;
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < *num_pref_freq) {
+ while (i < *num_pref_freq &&
+ (!p2p_supported_freq(wpa_s->global->p2p,
+ pref_freq_list[i]) ||
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i]))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
* @vht_chwidth: Channel width supported by GO operating with VHT support
- * (VHT_CHANWIDTH_*).
+ * (CHANWIDTH_*).
* @group_ssid: Specific Group SSID for join or %NULL if not set
* @group_ssid_len: Length of @group_ssid in octets
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, const u8 *group_ssid,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
wpa_s->p2p_go_vht = !!vht;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
+ wpa_s->p2p_go_he = !!he;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
+ } else if (wps_method == WPS_P2PS) {
+ /* Force the P2Ps default PIN to be used */
+ os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin));
} else
wpa_s->p2p_pin[0] = '\0';
&size, pref_freq_list);
if (!res && size > 0) {
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < size) {
+ while (i < size &&
+ (!p2p_supported_freq(wpa_s->global->p2p,
+ pref_freq_list[i]) ||
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i]))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded to the
* driver, allow P2P GO to use it.
{
unsigned int i, r;
- /* first try some random selection of the social channels */
- if (os_get_random((u8 *) &r, sizeof(r)) < 0)
- return;
-
- for (i = 0; i < 3; i++) {
- params->freq = 2412 + ((r + i) % 3) * 25;
- if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
- goto out;
- }
-
- /* try all other channels in operating class 81 */
- for (i = 0; i < 11; i++) {
- params->freq = 2412 + i * 5;
-
- /* skip social channels; covered in the previous loop */
- if (params->freq == 2412 ||
- params->freq == 2437 ||
- params->freq == 2462)
- continue;
-
- if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
- goto out;
- }
-
/* try all channels in operating class 115 */
for (i = 0; i < 4; i++) {
params->freq = 5180 + i * 20;
goto out;
}
+ /* try some random selection of the social channels */
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ params->freq = 2412 + ((r + i) % 3) * 25;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
+ goto out;
+ }
+
+ /* try all other channels in operating class 81 */
+ for (i = 0; i < 11; i++) {
+ params->freq = 2412 + i * 5;
+
+ /* skip social channels; covered in the previous loop */
+ if (params->freq == 2412 ||
+ params->freq == 2437 ||
+ params->freq == 2462)
+ continue;
+
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
+ goto out;
+ }
+
params->freq = 0;
wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed");
return;
}
+static int wpas_same_band(int freq1, int freq2)
+{
+ enum hostapd_hw_mode mode1, mode2;
+ u8 chan1, chan2;
+
+ mode1 = ieee80211_freq_to_chan(freq1, &chan1);
+ mode2 = ieee80211_freq_to_chan(freq2, &chan2);
+ if (mode1 == NUM_HOSTAPD_MODES)
+ return 0;
+ return mode1 == mode2;
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
params->role_go = 1;
params->ht40 = ht40;
params->vht = vht;
+ params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
/* try using the forced freq */
if (freq) {
- if (!wpas_p2p_supported_freq_go(wpa_s, channels, freq)) {
+ if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
+ !freq_included(wpa_s, channels, freq)) {
wpa_printf(MSG_DEBUG,
- "P2P: Forced GO freq %d MHz not accepted",
+ "P2P: Forced GO freq %d MHz disallowed",
freq);
goto fail;
}
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded
+ * to the driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s: The forced channel for GO (%u MHz) requires DFS and DFS is offloaded",
+ __func__, freq);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel for GO (%u MHz) is not supported for P2P uses",
+ freq);
+ goto fail;
+ }
+ }
for (i = 0; i < num; i++) {
if (freqs[i].freq == freq) {
goto success;
}
+ /* Try using a channel that allows VHT to be used with 80 MHz */
+ if (wpa_s->hw.modes && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!hwmode ||
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW80) != ALLOWED)
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and allowing VHT80",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using a channel that allows HT to be used with 40 MHz on the same
+ * band so that CSA can be used */
+ if (wpa_s->current_ssid && wpa_s->hw.modes &&
+ wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand) ||
+ !hwmode ||
+ (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40MINUS) != ALLOWED &&
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40PLUS) != ALLOWED))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer, allowing HT40, and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using one of the group common freqs on the same band so that CSA
+ * can be used */
+ if (wpa_s->current_ssid && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ cand = wpa_s->p2p_group_common_freqs[i];
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
/* Try using one of the group common freqs */
if (wpa_s->p2p_group_common_freqs) {
for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
"P2P: Use primary interface for group operations");
wpa_s->p2p_first_connection_timeout = 0;
if (wpa_s != wpa_s->p2pdev)
- wpas_p2p_clone_config_dh(wpa_s, wpa_s->p2pdev);
+ wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev);
return wpa_s;
}
return NULL;
}
+ if (go && wpa_s->p2p_go_do_acs) {
+ group_wpa_s->p2p_go_do_acs = wpa_s->p2p_go_do_acs;
+ group_wpa_s->p2p_go_acs_band = wpa_s->p2p_go_acs_band;
+ wpa_s->p2p_go_do_acs = 0;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
group_wpa_s->p2p_first_connection_timeout = 0;
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth)
+ int max_oper_chwidth, int he)
{
struct p2p_go_neg_results params;
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s);
- freq = wpas_p2p_select_go_freq(wpa_s, freq);
- if (freq < 0)
- return -1;
+ if (!wpa_s->p2p_go_do_acs) {
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
+ return -1;
+ }
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, NULL))
+ ht40, vht, max_oper_chwidth, he, NULL))
return -1;
- if (params.freq &&
- !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(params.freq)) {
- /*
- * If freq is a DFS channel and DFS is offloaded to the
- * driver, allow P2P GO to use it.
- */
- wpa_printf(MSG_DEBUG,
- "P2P: %s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to driver",
- __func__, params.freq);
- } else {
- wpa_printf(MSG_DEBUG,
- "P2P: The selected channel for GO (%u MHz) is not supported for P2P uses",
- params.freq);
- return -1;
- }
- }
+
p2p_go_params(wpa_s->global->p2p, ¶ms);
params.persistent_group = persistent_group;
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, channels))
+ ht40, vht, max_oper_chwidth, he, channels))
return -1;
params.role_go = 1;
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ !ssid->p2p_group)
return NULL;
cfg = os_zalloc(sizeof(*cfg));
wpa_s->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
- wpa_s->p2p_in_provisioning)
+ wpa_s->p2p_in_provisioning) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Reject p2p_find operation%s%s",
+ (wpa_s->global->p2p_disabled || !wpa_s->global->p2p) ?
+ " (P2P disabled)" : "",
+ wpa_s->p2p_in_provisioning ?
+ " (p2p_in_provisioning)" : "");
return -1;
+ }
wpa_supplicant_cancel_sched_scan(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->p2p_lo_started) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Cannot start P2P listen, it is offloaded");
+ return -1;
+ }
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len, rx_freq)) {
+ ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq)
+ int pref_freq, int he)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
int persistent;
int freq;
- u8 ip[3 * 4];
+ u8 ip[3 * 4], *ip_ptr = NULL;
char ip_addr[100];
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
ip[8], ip[9], ip[10], ip[11]);
if (os_snprintf_error(sizeof(ip_addr), res))
ip_addr[0] = '\0';
+ ip_ptr = ip;
}
wpas_p2p_group_started(wpa_s, 0, ssid, freq,
ip_addr);
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr);
}
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
- wpa_s->p2p_go_max_oper_chwidth, NULL, 0);
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
return ret;
}
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len);
}
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
}
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
if (res)
return res;
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
csa_settings.freq_params.center_freq2 = freq2;
switch (conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_80MHZ:
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80MHZ:
+ case CHANWIDTH_80P80MHZ:
csa_settings.freq_params.bandwidth = 80;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
csa_settings.freq_params.bandwidth = 160;
break;
}
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
unsigned int i, invalid_freq = 0, policy_move = 0, flags = 0;
unsigned int timeout;
int freq;
+ int dfs_offload;
wpas_p2p_go_update_common_freqs(wpa_s);
freq = wpa_s->current_ssid->frequency;
+ dfs_offload = (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
for (i = 0, invalid_freq = 0; i < num; i++) {
if (freqs[i].freq == freq) {
flags = freqs[i].flags;
/* The channel is invalid, must change it */
- if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq) &&
+ !dfs_offload) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P: Freq=%d MHz no longer valid for GO",
freq);
/* Freq is not used by any other station interface */
continue;
} else if (!p2p_supported_freq(wpa_s->global->p2p,
- freqs[i].freq)) {
+ freqs[i].freq) && !dfs_offload) {
/* Freq is not valid for P2P use cases */
continue;
} else if (wpa_s->conf->p2p_go_freq_change_policy ==
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
wpas_p2p_group_deinit(wpa_s);
}
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ u8 *device_types;
+ size_t dev_types_len;
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->p2p_lo_started) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P Listen offload is already started");
+ return 0;
+ }
+
+ if (wpa_s->global->p2p == NULL ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+ return -1;
+ }
+
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+ freq);
+ return -1;
+ }
+
+ /* Get device type */
+ dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+ WPS_DEV_TYPE_LEN;
+ device_types = os_malloc(dev_types_len);
+ if (!device_types)
+ return -1;
+ os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+ os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+ wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+ /* Get Probe Response IE(s) */
+ buf = p2p_build_probe_resp_template(p2p, freq);
+ if (!buf) {
+ os_free(device_types);
+ return -1;
+ }
+
+ ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+ device_types, dev_types_len,
+ wpabuf_mhead_u8(buf), wpabuf_len(buf));
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to start P2P listen offload");
+
+ os_free(device_types);
+ wpabuf_free(buf);
+
+ if (ret == 0) {
+ wpa_s->p2p_lo_started = 1;
+
+ /* Stop current P2P listen if any */
+ wpas_stop_listen(wpa_s);
+ }
+
+ return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->p2p_lo_started)
+ return 0;
+
+ ret = wpa_drv_p2p_lo_stop(wpa_s);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to stop P2P listen offload");
+
+ wpa_s->p2p_lo_started = 0;
+ return ret;
+}