#endif /* P2P_MAX_INITIAL_CONN_WAIT */
#ifndef P2P_CONCURRENT_SEARCH_DELAY
-#ifdef ANDROID_P2P
-#define P2P_CONCURRENT_SEARCH_DELAY 0
-#else
#define P2P_CONCURRENT_SEARCH_DELAY 500
-#endif
#endif /* P2P_CONCURRENT_SEARCH_DELAY */
enum p2p_group_removal_reason {
#endif
};
-#ifdef ANDROID_P2P
-static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
-#endif
+
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
static struct wpa_supplicant *
wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method,
int auto_join);
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
- void *timeout_ctx);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
-#ifdef ANDROID_P2P
-static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s)
-{
- struct wpa_supplicant *iface = NULL;
-
- for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
- if(iface->scanning || iface->wpa_state == WPA_SCANNING) {
- wpa_printf(MSG_DEBUG, "P2P: Scan in progress on %s,"
- "defer P2P SEARCH", iface->ifname);
- return 1;
- }
- }
-
- return 0;
-}
-#endif
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->level,
+ bss->freq, bss->age, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
break;
wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
"pending station mode scan to be "
"completed on interface %s", ifs->ifname);
- wpa_s->p2p_cb_on_scan_complete = 1;
+ wpa_s->global->p2p_cb_on_scan_complete = 1;
wpa_supplicant_req_scan(ifs, 0, 0);
return 1;
}
wpabuf_free(ies);
if (ret) {
- if (wpa_s->scanning ||
- wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
- wpa_s->p2p_cb_on_scan_complete = 1;
- ret = 1;
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs->scanning ||
+ ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
+ wpa_s->global->p2p_cb_on_scan_complete = 1;
+ ret = 1;
+ break;
+ }
}
} else
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
const char *reason;
ssid = wpa_s->current_ssid;
-#ifdef ANDROID_P2P
- if ((ssid == NULL) && (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
-#else
if (ssid == NULL) {
-#endif
/*
* The current SSID was not known, but there may still be a
- * pending P2P group interface waiting for provisioning.
+ * pending P2P group interface waiting for provisioning or a
+ * P2P group that is trying to reconnect.
*/
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (ssid->p2p_group &&
- (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
- (ssid->key_mgmt & WPA_KEY_MGMT_WPS)))
+ if (ssid->p2p_group && ssid->disabled != 2)
break;
ssid = ssid->next;
}
- if (ssid == NULL) {
+ if (ssid == NULL &&
+ wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
+ {
wpa_printf(MSG_ERROR, "P2P: P2P group interface "
"not found");
return -1;
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->sta_scan_pending = 0;
} else {
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
#ifdef ANDROID_P2P
/* For client Second phase of Group formation (4-way handshake) can be still pending
* So we need to restore wpa_s->global->p2p_group_formation */
+ wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
wpa_s->global->p2p_group_formation = wpa_s;
#endif
if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
wpa_s->pending_pd_before_join &&
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
- os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+ os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+ wpa_s->p2p_fallback_to_go_neg) {
wpa_s->pending_pd_before_join = 0;
- if (wpa_s->p2p_fallback_to_go_neg) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
- "during p2p_connect-auto");
- wpas_p2p_fallback_to_go_neg(wpa_s, 0);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "P2P: Starting pending "
- "join-existing-group operation (no ACK for PD "
- "Req)");
- wpas_p2p_join_start(wpa_s);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+ "during p2p_connect-auto");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
}
}
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
- wpa_msg(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 ? params->passphrase : "",
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ? " [PERSISTENT]" : "");
+ if (os_strlen(params->passphrase) > 0) {
+ wpa_msg(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(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]" :
+ "");
+ }
if (params->persistent_group)
network_id = wpas_p2p_store_persistent_group(
params->peer_device_addr);
else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
- wpa_s->p2p_pin, NULL, 0);
+ wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
}
{
struct wpa_ssid *ssid;
- if (wpas_copy_go_neg_results(wpa_s, params) < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO");
+ if (wpas_copy_go_neg_results(wpa_s, params) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation "
+ "results");
return;
+ }
ssid = wpa_config_add_network(wpa_s->conf);
- if (ssid == NULL)
+ if (ssid == NULL) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
return;
+ }
wpa_s->show_group_started = 0;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->passphrase = os_strdup(params->passphrase);
+ if (os_strlen(params->passphrase) > 0) {
+ ssid->passphrase = os_strdup(params->passphrase);
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
+ "passphrase for GO");
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ } else
+ ssid->passphrase = NULL;
+ ssid->psk_set = params->psk_set;
+ if (ssid->psk_set)
+ os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
+ else if (ssid->passphrase)
+ wpa_config_update_psk(ssid);
ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->connect_without_scan = ssid;
wpa_s->reassociate = 1;
wpa_s->disconnected = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to "
+ "start GO)");
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
-
+#define WFD_DEV_INFO_SIZE 9
+ char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
+ os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
+#ifdef CONFIG_WIFI_DISPLAY
+ if (info->wfd_subelems) {
+ wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
+ wpabuf_head(info->wfd_subelems),
+ WFD_DEV_INFO_SIZE);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x",
+ "dev_capab=0x%x group_capab=0x%x%s%s",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
info->device_name, info->config_methods,
- info->dev_capab, info->group_capab);
+ info->dev_capab, info->group_capab,
+ wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
}
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+ u8 **spos, const u8 *end)
+{
+ while (*spos < end) {
+ u8 val = ((*spos)[0] & 0xc0) >> 6;
+ int len;
+
+ if (val == 1 || val == 2) {
+ /* These are reserved values in RFC 1035 */
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence starting with 0x%x", val);
+ return -1;
+ }
+
+ if (val == 3) {
+ u16 offset;
+ u8 *spos_tmp;
+
+ /* Offset */
+ if (*spos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "P2P: No room for full "
+ "DNS offset field");
+ return -1;
+ }
+
+ offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+ if (offset >= *spos - start) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+ "pointer offset %u", offset);
+ return -1;
+ }
+
+ (*spos) += 2;
+ spos_tmp = start + offset;
+ return p2p_sd_dns_uncompress_label(upos, uend, start,
+ &spos_tmp,
+ *spos - 2);
+ }
+
+ /* Label */
+ len = (*spos)[0] & 0x3f;
+ if (len == 0)
+ return 0;
+
+ (*spos)++;
+ if (*spos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence - no room for label with length "
+ "%u", len);
+ return -1;
+ }
+
+ if (*upos + len + 2 > uend)
+ return -2;
+
+ os_memcpy(*upos, *spos, len);
+ *spos += len;
+ *upos += len;
+ (*upos)[0] = '.';
+ (*upos)++;
+ (*upos)[0] = '\0';
+ }
+
+ return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+ size_t msg_len, size_t offset)
+{
+ /* 27-octet in-memory packet from P2P specification */
+ const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+ "\x04_udp\xC0\x11\x00\x0C\x00\x01";
+ u8 *tmp, *end, *spos;
+ char *upos, *uend;
+ int ret = 0;
+
+ if (buf_len < 2)
+ return -1;
+ if (offset > msg_len)
+ return -1;
+
+ tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+ if (tmp == NULL)
+ return -1;
+ spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+ end = spos + msg_len;
+ spos += offset;
+
+ os_memset(tmp, 0, DNS_HEADER_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+ upos = buf;
+ uend = buf + buf_len;
+
+ ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+ if (ret) {
+ os_free(tmp);
+ return ret;
+ }
+
+ if (upos == buf) {
+ upos[0] = '.';
+ upos[1] = '\0';
+ } else if (upos[-1] == '.')
+ upos[-1] = '\0';
+
+ os_free(tmp);
+ return 0;
+}
+
+
static struct p2p_srv_bonjour *
wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
const struct wpabuf *query)
}
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+ size_t query_len)
+{
+ char str_rx[256], str_srv[256];
+
+ if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+ return 0; /* Too short to include DNS Type and Version */
+ if (os_memcmp(query + query_len - 3,
+ wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+ 3) != 0)
+ return 0; /* Mismatch in DNS Type or Version */
+ if (query_len == wpabuf_len(bsrv->query) &&
+ os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+ return 1; /* Binary match */
+
+ if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+ 0))
+ return 0; /* Failed to uncompress query */
+ if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+ wpabuf_head(bsrv->query),
+ wpabuf_len(bsrv->query) - 3, 0))
+ return 0; /* Failed to uncompress service */
+
+ return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id,
const u8 *query, size_t query_len)
{
struct p2p_srv_bonjour *bsrv;
- struct wpabuf buf;
u8 *len_pos;
+ int matches = 0;
wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
query, query_len);
return;
}
- if (wpabuf_tailroom(resp) < 5)
- return;
- /* Length (to be filled) */
- len_pos = wpabuf_put(resp, 2);
- wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
- wpabuf_put_u8(resp, srv_trans_id);
+ dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+ struct p2p_srv_bonjour, list) {
+ if (!match_bonjour_query(bsrv, query, query_len))
+ continue;
+
+ if (wpabuf_tailroom(resp) <
+ 5 + query_len + wpabuf_len(bsrv->resp))
+ return;
+
+ matches++;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
+
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+ wpabuf_head(bsrv->resp),
+ wpabuf_len(bsrv->resp));
- wpabuf_set(&buf, query, query_len);
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
- if (bsrv == NULL) {
+ /* Response Data */
+ wpabuf_put_data(resp, query, query_len); /* Key */
+ wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
+
+ if (matches == 0) {
wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
"available");
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
2);
- return;
}
-
- /* Status Code */
- wpabuf_put_u8(resp, P2P_SD_SUCCESS);
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
- wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
- if (wpabuf_tailroom(resp) >=
- wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
- /* Response Data */
- wpabuf_put_buf(resp, bsrv->query); /* Key */
- wpabuf_put_buf(resp, bsrv->resp); /* Value */
- }
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
{
struct p2p_srv_bonjour *bsrv;
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
- if (bsrv) {
- wpabuf_free(query);
- wpabuf_free(bsrv->resp);
- bsrv->resp = resp;
- return 0;
- }
-
bsrv = os_zalloc(sizeof(*bsrv));
if (bsrv == NULL)
return -1;
return;
}
+ if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
+ wpa_s->pending_pd_before_join = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+ "join-existing-group operation (no ACK for PD "
+ "Req attempts)");
+ wpas_p2p_join_start(wpa_s);
+ return;
+ }
+
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
" p2p_dev_addr=" MACSTR " status=%d",
MAC2STR(peer), status);
" was accepted; op_freq=%d MHz",
MAC2STR(sa), op_freq);
if (s) {
+ int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
+ wpa_s, s, go, go ? op_freq : 0, 0);
} else if (bssid) {
+ wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0);
}
return;
}
+ /*
+ * The peer could have missed our ctrl::ack frame for Invitation
+ * Response and continue retransmitting the frame. To reduce the
+ * likelihood of the peer not getting successful TX status for the
+ * Invitation Response frame, wait a short time here before starting
+ * the persistent group so that we will remain on the current channel to
+ * acknowledge any possible retransmission from the peer.
+ */
+#ifndef ANDROID_P2P
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
+ "starting persistent group");
+ os_sleep(0, 50000);
+#else
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 100 ms wait on current channel before "
+ "starting persistent group");
+ os_sleep(0, 100000);
+#endif
+
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
static struct p2p_oper_class_map op_class[] = {
{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
- { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
#if 0 /* Do not enable HT40 on 2 GHz for now */
{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+ p2p.max_listen = wpa_s->max_remain_on_chan;
+
#ifdef ANDROID_P2P
- if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+ if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
- else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT)
+ wpa_printf(MSG_DEBUG, "P2P: Multi channel concurrency support");
+ } else {
+ // Add support for WPA_DRIVER_FLAGS_P2P_CONCURRENT
p2p.p2p_concurrency = P2P_SINGLE_CHANNEL_CONCURRENT;
+ wpa_printf(MSG_DEBUG, "P2P: Single channel concurrency support");
+ }
#endif
global->p2p = p2p_init(&p2p);
wpa_s->go_params = NULL;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->conf->p2p_no_group_iface)
+ return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg, pref_freq);
}
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0);
+ ssid ? ssid->ssid_len : 0, pref_freq);
}
}
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- if (!wpa_s->pending_pd_before_join)
- return;
- /*
- * Provision Discovery Response may have been lost - try to connect
- * anyway since we do not need any information from this PD.
- */
- wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
- "try to connect anyway");
- wpas_p2p_join_start(wpa_s);
-}
-
-
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
struct wpa_supplicant *iface;
if (p2p_prov_disc_req(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr,
wpa_s->pending_pd_config_methods, join,
- 0) < 0) {
+ 0, wpa_s->user_initiated_pd) < 0) {
wpa_s->p2p_auto_pd = 0;
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
" p2p_dev_addr=" MACSTR " status=N/A",
if (p2p_prov_disc_req(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr, method, 1,
- freq) < 0) {
+ freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
"existing group");
wpa_s->pending_pd_before_join = 0;
goto start;
}
-
- /*
- * Actual join operation will be started from the Action frame
- * TX status callback (if no ACK is received) or when the
- * Provision Discovery Response is received. Use a short
- * timeout as a backup mechanism should the Provision Discovery
- * Response be lost for any reason.
- */
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
- NULL);
- eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
- wpa_s, NULL);
return;
}
struct p2p_go_neg_results res;
struct wpa_bss *bss;
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
if (group == NULL)
return -1;
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;
}
group->p2p_in_provisioning = 1;
int go_intent, int freq, int persistent_id, int pd,
int ht40)
{
- int force_freq = 0, oper_freq = 0;
+ int force_freq = 0, pref_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
int ret = 0;
enum wpa_driver_if_type iftype;
wpa_s->p2p_auto_started.sec,
wpa_s->p2p_auto_started.usec);
}
+ wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
auto_join) < 0)
return -1;
"(%u MHz) not available for P2P - try to use "
"another channel", oper_freq);
force_freq = 0;
+ } else if (oper_freq > 0 &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+ "are already using (%u MHz) on another interface",
+ oper_freq);
+ pref_freq = oper_freq;
} else if (oper_freq > 0) {
wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
"channel we are already using (%u MHz) on another "
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr,
- force_freq, persistent_group, ssid) <
- 0)
+ force_freq, persistent_group, ssid,
+ pref_freq) < 0)
return -1;
return ret;
}
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,
- persistent_group, ssid) < 0) {
+ persistent_group, ssid, pref_freq) < 0) {
if (wpa_s->create_p2p_iface)
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+ wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
- if (wpa_s->pending_action_tx)
+ if (offchannel_pending_action_tx(wpa_s))
return;
if (wpa_s->p2p_long_listen > 0)
wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
{
struct wpa_supplicant *group_wpa_s;
- if (!wpas_p2p_create_iface(wpa_s))
+ if (!wpas_p2p_create_iface(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
+ "operations");
return wpa_s;
+ }
if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
- WPA_IF_P2P_CLIENT) < 0)
+ WPA_IF_P2P_CLIENT) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to add group interface");
return NULL;
+ }
group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
if (group_wpa_s == NULL) {
+ wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to initialize group "
+ "interface");
wpas_p2p_remove_pending_group_interface(wpa_s);
return NULL;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
+ group_wpa_s->ifname);
return group_wpa_s;
}
/* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
- wpas_p2p_stop_find(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
if (freq == 2) {
wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
}
/* Make sure we are not running find during connection establishment */
- wpas_p2p_stop_find(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
wpa_s->p2p_fallback_to_go_neg = 0;
return -1;
params.role_go = 1;
- if (ssid->passphrase == NULL ||
- os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
- wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
- "group");
- return -1;
+ params.psk_set = ssid->psk_set;
+ if (params.psk_set)
+ os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
+ if (ssid->passphrase) {
+ if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
+ wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
+ "persistent group");
+ return -1;
+ }
+ os_strlcpy(params.passphrase, ssid->passphrase,
+ sizeof(params.passphrase));
}
- os_strlcpy(params.passphrase, ssid->passphrase,
- sizeof(params.passphrase));
os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
params.ssid_len = ssid->ssid_len;
params.persistent_group = 1;
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
- 0);
+ 0, 1);
}
static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
- if (!wpa_s->pending_action_tx)
+ if (!offchannel_pending_action_tx(wpa_s))
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;
+ offchannel_clear_pending_action_tx(wpa_s);
}
}
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_cb_on_scan_complete = 0;
+ wpa_s->global->p2p_cb_on_scan_complete = 0;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
wpa_drv_p2p_stop_find(wpa_s);
- return;
+ return 1;
}
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
+ return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+ if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+ return;
wpas_p2p_remove_pending_group_interface(wpa_s);
}
{
enum p2p_invite_role role;
u8 *bssid = NULL;
+#ifdef ANDROID_P2P
+ int force_freq = 0, oper_freq = 0;
+#endif
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
}
wpa_s->pending_invite_ssid_id = ssid->id;
+#ifdef ANDROID_P2P
+ if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+ wpa_s->assoc_freq)
+ oper_freq = wpa_s->assoc_freq;
+ else {
+ oper_freq = wpa_drv_shared_freq(wpa_s);
+ if (oper_freq < 0)
+ oper_freq = 0;
+ }
+
+ if (freq > 0) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ return -3;
+ }
+
+ if (oper_freq > 0 && freq != oper_freq &&
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+ "on %u MHz while connected on another "
+ "channel (%u MHz)", freq, oper_freq);
+ return -2;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "requested channel (%u MHz)", freq);
+ force_freq = freq;
+ } else if (oper_freq > 0 &&
+ !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
+ if (!(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+ "while connected on non-P2P supported "
+ "channel (%u MHz)", oper_freq);
+ return -2;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+ "(%u MHz) not available for P2P - try to use "
+ "another channel", oper_freq);
+ force_freq = 0;
+ } else if (oper_freq > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "channel we are already using (%u MHz) on another "
+ "interface", oper_freq);
+ force_freq = oper_freq;
+ }
+#endif
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len,
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+#ifdef ANDROID_P2P
+ return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+ ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1);
+#else
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+#endif
}
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
done:
- if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
wpa_s->global->p2p != NULL) {
- wpa_s->p2p_cb_on_scan_complete = 0;
+ wpa_s->global->p2p_cb_on_scan_complete = 0;
if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
"continued after successful connection");
static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
{
- return wpa_s->current_ssid != NULL &&
- wpa_s->current_ssid->p2p_group &&
+ if (wpa_s->current_ssid == NULL) {
+ /*
+ * current_ssid can be cleared when P2P client interface gets
+ * disconnected, so assume this interface was used as P2P
+ * client.
+ */
+ return 1;
+ }
+ return wpa_s->current_ssid->p2p_group &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
}
}
+static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+}
+
+
int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
{
struct wpa_global *global = wpa_s->global;
found = 1;
}
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
+ found = 1;
+ }
+
+ if (wpa_s->pending_pd_before_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
+ wpa_s->pending_pd_before_join = 0;
+ found = 1;
+ }
+
wpas_p2p_stop_find(wpa_s);
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
+ if (wpa_s->p2p_in_provisioning) {
+ wpas_group_formation_completed(wpa_s, 0);
+ break;
+ }
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_REQUESTED);
break;
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
{
-#ifdef ANDROID_P2P
- struct wpa_supplicant *group = wpa_s;
-#endif
-
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
-#ifdef ANDROID_P2P
- while (group && (group->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)) {
- if(group->wpa_state == WPA_ASSOCIATED) {
- /* WPA_ASSOCIATED hasn't moved to WPA_COMPLETED. So it could be in WPS
- * or 4Way Hanshake phase. Avoid allowing scan during this time critical
- * phase
- */
- wpa_printf(MSG_ERROR, "P2P: WPS/4way handshake in Progress."
- " Defer SCAN ");
- return 1;
- }
- group = group->next;
- }
-#endif
-
return p2p_in_progress(wpa_s->global->p2p);
}
int group_added)
{
struct wpa_supplicant *group = wpa_s;
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
if (wpa_s->global->p2p_group_formation)
group = wpa_s->global->p2p_group_formation;
wpa_s = wpa_s->parent;
}
#ifdef ANDROID_P2P
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
{
struct wpa_supplicant *iface = NULL;
struct p2p_data *p2p = wpa_s->global->p2p;
for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
- if((iface->p2p_group_interface) && (iface->current_ssid) &&
- (iface->current_ssid->frequency != freq)) {
-
- if (iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) {
- /* Try to see whether we can move the GO. If it
- * is not possible, remove the GO interface
- */
- if(wpa_drv_switch_channel(iface, freq) == 0) {
- wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
- iface->current_ssid->frequency = freq;
- continue;
- }
+ if ((iface->current_ssid) &&
+ (iface->current_ssid->frequency != freq) &&
+ ((iface->p2p_group_interface) ||
+ (iface->current_ssid->p2p_group))) {
+
+ if ((iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) ||
+ (iface->current_ssid->mode == WPAS_MODE_P2P_GO)) {
+ /* Try to see whether we can move the GO. If it
+ * is not possible, remove the GO interface
+ */
+ if (wpa_drv_switch_channel(iface, freq) == 0) {
+ wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
+ iface->current_ssid->frequency = freq;
+ continue;
+ }
}
/* If GO cannot be moved or if the conflicting interface is a
* P2P Client, remove the interface depending up on the connection
* priority */
- if(!wpas_is_p2p_prioritized(wpa_s)) {
- /* STA connection has priority over existing
+ if(!wpas_is_p2p_prioritized(iface)) {
+ /* STA connection has priority over existing
* P2P connection. So remove the interface */
wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
"concurrent mode frequency conflict");
wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+ /* If connection in progress is p2p connection, do not proceed for the connection */
+ if (wpa_s == iface)
+ return -1;
+ else
+ /* If connection in progress is STA connection, proceed for the connection */
+ return 0;
} else {
- /* Existing connection has the priority. Disable the newly
- * selected network and let the application know about it.
- */
- return -1;
+ /* P2p connection has priority, disable the STA network*/
+ wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+ " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
+ if (wpa_s == iface) {
+ /* p2p connection is in progress, continue connecting...*/
+ return 0;
+ }
+ else {
+ /* STA connection is in progress, do not allow to continue */
+ return -1;
+ }
}
}
}