#include "wps/wps_i.h"
#include "p2p/p2p.h"
#include "ap/hostapd.h"
+#include "ap/p2p_hostapd.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "ap.h"
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method);
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_scan_res_handler(struct wpa_supplicant *wpa_s,
gtype = "client";
} else
gtype = "GO";
+ if (wpa_s->cross_connect_in_use) {
+ wpa_s->cross_connect_in_use = 0;
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
+ }
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s",
wpa_s->ifname, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" psk=%s go_dev_addr=" MACSTR "%s",
- wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+ "%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);
} else {
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
- MACSTR "%s",
- wpa_s->ifname, ssid_txt,
+ "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+ "go_dev_addr=" MACSTR "%s",
+ wpa_s->ifname, ssid_txt, ssid->frequency,
ssid && ssid->passphrase ? ssid->passphrase : "",
MAC2STR(go_dev_addr),
persistent ? " [PERSISTENT]" : "");
+ wpas_p2p_cross_connect_setup(wpa_s);
}
if (persistent)
without_roc = wpa_s->pending_action_without_roc;
wpa_s->pending_action_without_roc = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
+ "pending_action_tx=%p)",
+ without_roc, wpa_s->pending_action_tx);
if (wpa_s->pending_action_tx == NULL)
return;
struct wpa_supplicant *wpa_s = ctx;
wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
- " src=" MACSTR " bssid=" MACSTR,
- freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
+ " src=" MACSTR " bssid=" MACSTR " len=%d",
+ freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+ (int) len);
if (wpa_s->pending_action_tx) {
wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
wpabuf_free(wpa_s->pending_action_tx);
}
wpa_s->pending_action_tx = wpabuf_alloc(len);
- if (wpa_s->pending_action_tx == NULL)
+ if (wpa_s->pending_action_tx == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
+ "TX buffer (len=%llu)", (unsigned long long) len);
return -1;
+ }
wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
wpa_s->pending_action_freq = freq;
if (wpa_s->off_channel_freq == freq || freq == 0) {
- /* Already on requested channel; send immediately */
+ wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
+ "send Action frame immediately");
/* TODO: Would there ever be need to extend the current
* duration on the channel? */
wpa_s->pending_action_without_roc = 1;
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
+ 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 (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
- MACSTR "%s",
+ "%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 ? params->passphrase : "",
MAC2STR(wpa_s->parent->own_addr),
params->persistent_group ? " [PERSISTENT]" : "");
wpas_p2p_store_persistent_group(
wpa_s->parent, ssid,
wpa_s->parent->own_addr);
+ wpas_p2p_cross_connect_setup(wpa_s);
return;
}
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
- /* TODO: add peer Config Timeout */
- eloop_register_timeout(15, 0, wpas_p2p_group_formation_timeout, wpa_s,
- NULL);
+ eloop_register_timeout(15 + res->peer_config_timeout / 100,
+ (res->peer_config_timeout % 100) * 10000,
+ wpas_p2p_group_formation_timeout, wpa_s, NULL);
}
-void wpas_go_neg_req_rx(void *ctx, const u8 *src)
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR,
- MAC2STR(src));
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+ " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
}
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie);
+ wpa_drv_set_ap_wps_ie(wpa_s, NULL, 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 "
else if (config_methods & WPS_CONFIG_PUSHBUTTON)
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
MAC2STR(peer));
+
+ if (wpa_s->pending_pd_before_join &&
+ (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+ os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 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);
+ }
}
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
" to join an active group", MAC2STR(sa));
if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
- os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN) ==
- 0) {
+ (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
+ == 0 ||
+ os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) {
wpa_printf(MSG_DEBUG, "P2P: Accept previously "
"authorized invitation");
goto accept_inv;
if (s) {
wpas_p2p_group_add_persistent(
wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
- } else {
+ } else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method);
}
/* Operating class 81 - 2.4 GHz band channels 1..13 */
p2p->channels.reg_class[cla].reg_class = 81;
+#if 0
p2p->channels.reg_class[cla].channels = 13;
for (i = 0; i < 13; i++)
p2p->channels.reg_class[cla].channel[i] = i + 1;
+#else
+ p2p->channels.reg_class[cla].channels = 11;
+ for (i = 0; i < 11; i++)
+ p2p->channels.reg_class[cla].channel[i] = i + 1;
+#endif
cla++;
+#if 0
/* Operating class 82 - 2.4 GHz band channel 14 */
p2p->channels.reg_class[cla].reg_class = 82;
p2p->channels.reg_class[cla].channels = 1;
p2p->channels.reg_class[cla].channel[0] = 14;
cla++;
+#endif
#if 0
/* Operating class 83 - 2.4 GHz band channels 1..9; 40 MHz */
p2p.concurrent_operations = !!(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_P2P_CONCURRENT);
- p2p.max_peers = 100;
+ p2p.max_peers = wpa_s->max_stations ? wpa_s->max_stations : 100;
if (wpa_s->conf->p2p_ssid_postfix) {
p2p.ssid_postfix_len =
p2p.ssid_postfix_len);
}
+ p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
os_free(ifname);
}
+ /*
+ * Deinit GO data on any possibly remaining interface (if main
+ * interface is used as GO).
+ */
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_s->ap_iface)
+ wpas_p2p_group_deinit(wpa_s);
+ }
+
p2p_deinit(global->p2p);
global->p2p = NULL;
}
struct wpa_scan_results *scan_res)
{
struct wpa_bss *bss;
+ int freq;
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
if (scan_res)
wpas_p2p_scan_res_handler(wpa_s, scan_res);
+ freq = p2p_get_oper_freq(wpa_s->global->p2p,
+ wpa_s->pending_join_iface_addr);
+ if (freq >= 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+ "from P2P peer table: %d MHz", freq);
+ }
bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
+ freq = bss->freq;
+ wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+ "from BSS table: %d MHz", freq);
+ }
+ if (freq > 0) {
u16 method;
wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
"prior to joining an existing group (GO " MACSTR
" freq=%u MHz)",
- MAC2STR(wpa_s->pending_join_dev_addr), bss->freq);
+ MAC2STR(wpa_s->pending_join_dev_addr), freq);
wpa_s->pending_pd_before_join = 1;
switch (wpa_s->pending_join_wps_method) {
res.wps_method = wpa_s->pending_join_wps_method;
wpas_start_wps_enrollee(group, &res);
+ /*
+ * Allow a longer timeout for join-a-running-group than normal 15
+ * second group formation timeout since the GO may not have authorized
+ * our connection yet.
+ */
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+ eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
+ wpa_s, NULL);
+
return 0;
}
wpa_s->p2p_pin[0] = '\0';
if (join) {
- u8 iface_addr[ETH_ALEN];
+ u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
"connect a running group from " MACSTR,
os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
return ret;
}
+ os_memcpy(dev_addr, peer_addr, ETH_ALEN);
if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
- iface_addr) < 0)
+ iface_addr) < 0) {
os_memcpy(iface_addr, peer_addr, ETH_ALEN);
- if (wpas_p2p_join(wpa_s, iface_addr, peer_addr, wps_method) <
+ p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
+ dev_addr);
+ }
+ if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
0)
return -1;
return ret;
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
+ wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
+ "(p2p_long_listen=%d pending_action_tx=%p)",
+ wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
wpa_s->off_channel_freq = 0;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
}
+static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->pending_action_tx)
+ return;
+
+ wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
+ "operation request");
+ wpabuf_free(wpa_s->pending_action_tx);
+ wpa_s->pending_action_tx = NULL;
+}
+
+
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type)
{
+ wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
return p2p_find(wpa_s->global->p2p, timeout, type);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
{
+ wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
{
int res;
+ wpas_p2p_clear_pending_action_tx(wpa_s);
+
if (timeout == 0) {
/*
* This is a request for unlimited Listen state. However, at
}
-int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, const u8 *bssid,
+int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
u8 *buf, size_t len, int p2p_group)
{
+ struct wpabuf *p2p_ie;
+ int ret;
+
if (wpa_s->global->p2p_disabled)
return -1;
if (wpa_s->global->p2p == NULL)
return -1;
+ if (bss == NULL)
+ return -1;
+
+ p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
+ p2p_group, p2p_ie);
+ wpabuf_free(p2p_ie);
- return p2p_assoc_req_ie(wpa_s->global->p2p, bssid, buf, len,
- p2p_group);
+ return ret;
}
wpa_s->pending_invite_ssid_id = -1;
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 0);
+ ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
+ go_dev_addr, 0);
}
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" psk=%s go_dev_addr=" MACSTR
- "%s",
- wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+ "%s client 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]" : "");
} else {
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s client ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
- MACSTR "%s",
- wpa_s->ifname, ssid_txt,
+ "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
+ "go_dev_addr=" MACSTR "%s",
+ wpa_s->ifname, ssid_txt, ssid->frequency,
ssid->passphrase ? ssid->passphrase : "",
MAC2STR(go_dev_addr),
persistent ? " [PERSISTENT]" : "");
if (p2p == NULL)
return;
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+ return;
+
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
p2p_set_dev_name(p2p, wpa_s->conf->device_name);
os_strlen(wpa_s->conf->p2p_ssid_postfix) :
0);
}
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
+ p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+}
+
+
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+ int duration)
+{
+ if (!wpa_s->ap_iface)
+ return -1;
+ return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
+ duration);
+}
+
+
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
+{
+ if (wpa_s->global->p2p_disabled)
+ 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);
+
+ if (!enabled) {
+ struct wpa_supplicant *iface;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+ {
+ if (iface->cross_connect_enabled == 0)
+ continue;
+
+ iface->cross_connect_enabled = 0;
+ iface->cross_connect_in_use = 0;
+ wpa_msg(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
+ }
+ }
+
+ return 0;
+}
+
+
+static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
+{
+ struct wpa_supplicant *iface;
+
+ if (!uplink->global->cross_connection)
+ return;
+
+ for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+ if (!iface->cross_connect_enabled)
+ continue;
+ if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+ 0)
+ continue;
+ if (iface->ap_iface == NULL)
+ continue;
+ if (iface->cross_connect_in_use)
+ continue;
+
+ iface->cross_connect_in_use = 1;
+ wpa_msg(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
+ }
+}
+
+
+static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
+{
+ struct wpa_supplicant *iface;
+
+ for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+ if (!iface->cross_connect_enabled)
+ continue;
+ if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+ 0)
+ continue;
+ if (!iface->cross_connect_in_use)
+ continue;
+
+ wpa_msg(iface->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+ iface->ifname, iface->cross_connect_uplink);
+ iface->cross_connect_in_use = 0;
+ }
+}
+
+
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->ap_iface || wpa_s->current_ssid == NULL ||
+ wpa_s->current_ssid->mode != WPAS_MODE_INFRA ||
+ wpa_s->cross_connect_disallowed)
+ wpas_p2p_disable_cross_connect(wpa_s);
+ else
+ wpas_p2p_enable_cross_connect(wpa_s);
+}
+
+
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+ wpas_p2p_disable_cross_connect(wpa_s);
+}
+
+
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *iface;
+
+ if (!wpa_s->global->cross_connection)
+ return;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (iface == wpa_s)
+ continue;
+ if (iface->drv_flags &
+ WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
+ continue;
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+ continue;
+
+ wpa_s->cross_connect_enabled = 1;
+ os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname,
+ sizeof(wpa_s->cross_connect_uplink));
+ wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from "
+ "%s to %s whenever uplink is available",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
+
+ if (iface->ap_iface || iface->current_ssid == NULL ||
+ iface->current_ssid->mode != WPAS_MODE_INFRA ||
+ iface->cross_connect_disallowed ||
+ iface->wpa_state != WPA_COMPLETED)
+ break;
+
+ wpa_s->cross_connect_in_use = 1;
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+ wpa_s->ifname, wpa_s->cross_connect_uplink);
+ break;
+ }
+}
+
+
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
+ !wpa_s->p2p_in_provisioning)
+ return 0; /* not P2P client operation */
+
+ wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
+ "session overlap");
+ wpas_group_formation_completed(wpa_s, 0);
+ return 1;
}