diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2012-07-19 12:16:46 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2012-07-19 16:03:19 -0700 |
commit | 04949598a23f501be6eec21697465fd46a28840a (patch) | |
tree | 6eb315b8d139b0690cb644dc914c53bacb42df42 /wpa_supplicant/p2p_supplicant.c | |
parent | ce1e0634ed741293de60d5ba3476b26ccbd58ce2 (diff) | |
download | external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.zip external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.tar.gz external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.tar.bz2 |
wpa_supplicant: Update to 07-Jul-2012 TOT
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date: Sat Jul 7 13:01:45 2012 +0300
WPS SSDP: Fix socket leaks on error paths
Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'wpa_supplicant/p2p_supplicant.c')
-rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 741 |
1 files changed, 601 insertions, 140 deletions
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 5f1329e..e0c3580 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -39,6 +39,8 @@ */ #define P2P_MAX_JOIN_SCAN_ATTEMPTS 10 +#define P2P_AUTO_PD_SCAN_ATTEMPTS 5 + #ifndef P2P_MAX_CLIENT_IDLE /* * How many seconds to try to reconnect to the GO when connection in P2P client @@ -51,6 +53,14 @@ #endif /* ANDROID_P2P */ #endif /* P2P_MAX_CLIENT_IDLE */ +#ifndef P2P_MAX_INITIAL_CONN_WAIT +/* + * How many seconds to wait for initial 4-way handshake to get completed after + * WPS provisioning step. + */ +#define P2P_MAX_INITIAL_CONN_WAIT 10 +#endif /* P2P_MAX_INITIAL_CONN_WAIT */ + #ifdef ANDROID_P2P static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s); #endif @@ -59,15 +69,19 @@ static struct wpa_supplicant * wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int go); static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s); +static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, - const u8 *dev_addr, enum p2p_wps_method wps_method); + 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); #ifdef ANDROID_P2P static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s) @@ -112,7 +126,7 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, 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) + const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_scan_params params; @@ -120,7 +134,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, struct wpabuf *wps_ie, *ies; int social_channels[] = { 2412, 2437, 2462, 0, 0 }; size_t ielen; - int was_in_p2p_scan; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -133,8 +146,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid, - WPS_REQ_ENROLLEE, + wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, + wpa_s->wps->uuid, WPS_REQ_ENROLLEE, num_req_dev_types, req_dev_types); if (wps_ie == NULL) return -1; @@ -160,34 +173,24 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, break; case P2P_SCAN_FULL: break; - case P2P_SCAN_SPECIFIC: - social_channels[0] = freq; - social_channels[1] = 0; - params.freqs = social_channels; - break; case P2P_SCAN_SOCIAL_PLUS_ONE: social_channels[3] = freq; params.freqs = social_channels; break; } - was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler; - wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; ret = wpa_drv_scan(wpa_s, ¶ms); wpabuf_free(ies); if (ret) { - wpa_s->scan_res_handler = NULL; -#ifdef ANDROID_P2P - if (wpa_s->scanning || was_in_p2p_scan || wpas_global_scan_in_progress(wpa_s)) { -#else - if (wpa_s->scanning || was_in_p2p_scan) { -#endif + if (wpa_s->scanning || + wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) { wpa_s->p2p_cb_on_scan_complete = 1; ret = 1; } - } + } else + wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; return ret; } @@ -233,14 +236,12 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s, } -static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s) +static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent) { struct wpa_ssid *ssid; char *gtype; const char *reason; - eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); - ssid = wpa_s->current_ssid; if (ssid == NULL) { /* @@ -283,6 +284,9 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s) case P2P_GROUP_REMOVAL_UNAVAILABLE: reason = " reason=UNAVAILABLE"; break; + case P2P_GROUP_REMOVAL_GO_ENDING_SESSION: + reason = " reason=GO_ENDING_SESSION"; + break; #ifdef ANDROID_P2P case P2P_GROUP_REMOVAL_FREQ_CONFLICT: reason = " reason=FREQ_CONFLICT"; @@ -292,10 +296,16 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s) reason = ""; break; } - wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s", - wpa_s->ifname, gtype, reason); + if (!silent) { + wpa_msg(wpa_s->parent, MSG_INFO, + P2P_EVENT_GROUP_REMOVED "%s %s%s", + wpa_s->ifname, gtype, reason); + } - if (ssid) + if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) + wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); + + if (!silent && ssid) wpas_notify_p2p_group_removed(wpa_s, ssid, gtype); if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { @@ -341,7 +351,10 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Temporary group network not " "found"); } - wpa_supplicant_ap_deinit(wpa_s); + if (wpa_s->ap_iface) + wpa_supplicant_ap_deinit(wpa_s); + else + wpa_drv_deinit_p2p_cli(wpa_s); } @@ -562,7 +575,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, if (!success) { wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); - wpas_p2p_group_delete(wpa_s); + wpas_p2p_group_delete(wpa_s, 0); return; } @@ -670,6 +683,13 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) { 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)"); @@ -851,6 +871,8 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->p2p_group_idle = s->p2p_group_idle; d->p2p_intra_bss = s->p2p_intra_bss; d->persistent_reconnect = s->persistent_reconnect; + d->max_num_sta = s->max_num_sta; + d->pbc_in_m1 = s->pbc_in_m1; } @@ -1002,6 +1024,20 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS); wpas_notify_p2p_go_neg_completed(wpa_s, res); + if (res->role_go && wpa_s->p2p_persistent_id >= 0) { + struct wpa_ssid *ssid; + ssid = wpa_config_get_network(wpa_s->conf, + wpa_s->p2p_persistent_id); + if (ssid && ssid->disabled == 2 && + ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) { + size_t len = os_strlen(ssid->passphrase); + wpa_printf(MSG_DEBUG, "P2P: Override passphrase based " + "on requested persistent group"); + os_memcpy(res->passphrase, ssid->passphrase, len); + res->passphrase[len] = '\0'; + } + } + if (wpa_s->create_p2p_iface) { struct wpa_supplicant *group_wpa_s = wpas_p2p_init_group_interface(wpa_s, res->role_go); @@ -1836,6 +1872,7 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; + char params[20]; if (wpa_s->pending_pd_before_join && (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || @@ -1847,14 +1884,22 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) return; } + if (wpa_s->pending_pd_use == AUTO_PD_JOIN || + wpa_s->pending_pd_use == AUTO_PD_GO_NEG) + os_snprintf(params, sizeof(params), " peer_go=%d", + wpa_s->pending_pd_use == AUTO_PD_JOIN); + else + params[0] = '\0'; + if (config_methods & WPS_CONFIG_DISPLAY) - wpas_prov_disc_local_keypad(wpa_s, peer, ""); + wpas_prov_disc_local_keypad(wpa_s, peer, params); else if (config_methods & WPS_CONFIG_KEYPAD) { generated_pin = wps_generate_pin(); - wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin); + wpas_prov_disc_local_display(wpa_s, peer, params, + generated_pin); } else if (config_methods & WPS_CONFIG_PUSHBUTTON) - wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR, - MAC2STR(peer)); + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR + "%s", MAC2STR(peer), params); wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */, P2P_PROV_DISC_SUCCESS, @@ -1867,6 +1912,17 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer, { struct wpa_supplicant *wpa_s = ctx; + if (wpa_s->p2p_fallback_to_go_neg) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto " + "failed - fall back to GO Negotiation"); + wpas_p2p_fallback_to_go_neg(wpa_s, 0); + return; + } + + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE + " p2p_dev_addr=" MACSTR " status=%d", + MAC2STR(peer), status); + wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */, status, 0, 0); } @@ -1993,7 +2049,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0); } else if (bssid) { wpas_p2p_join(wpa_s, bssid, go_dev_addr, - wpa_s->p2p_wps_method); + wpa_s->p2p_wps_method, 0); } return; } @@ -2061,6 +2117,31 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid) } +static int wpas_p2p_disallowed_freq(struct wpa_global *global, + unsigned int freq) +{ + unsigned int i; + + if (global->p2p_disallow_freq == NULL) + return 0; + + for (i = 0; i < global->num_p2p_disallow_freq; i++) { + if (freq >= global->p2p_disallow_freq[i].min && + freq <= global->p2p_disallow_freq[i].max) + return 1; + } + + return 0; +} + + +static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan) +{ + reg->channel[reg->channels] = chan; + reg->channels++; +} + + static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, struct p2p_channels *chan) { @@ -2071,34 +2152,47 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, /* Operating class 81 - 2.4 GHz band channels 1..13 */ chan->reg_class[cla].reg_class = 81; - chan->reg_class[cla].channels = 11; - for (i = 0; i < 11; i++) - chan->reg_class[cla].channel[i] = i + 1; - cla++; + chan->reg_class[cla].channels = 0; + for (i = 0; i < 11; i++) { + if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], i + 1); + } + if (chan->reg_class[cla].channels) + cla++; wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz " "band"); /* Operating class 115 - 5 GHz, channels 36-48 */ chan->reg_class[cla].reg_class = 115; - chan->reg_class[cla].channels = 4; - chan->reg_class[cla].channel[0] = 36; - chan->reg_class[cla].channel[1] = 40; - chan->reg_class[cla].channel[2] = 44; - chan->reg_class[cla].channel[3] = 48; - cla++; + chan->reg_class[cla].channels = 0; + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 36); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 40); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 44); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 48); + if (chan->reg_class[cla].channels) + cla++; wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz " "band"); /* Operating class 124 - 5 GHz, channels 149,153,157,161 */ chan->reg_class[cla].reg_class = 124; - chan->reg_class[cla].channels = 4; - chan->reg_class[cla].channel[0] = 149; - chan->reg_class[cla].channel[1] = 153; - chan->reg_class[cla].channel[2] = 157; - chan->reg_class[cla].channel[3] = 161; - cla++; + chan->reg_class[cla].channels = 0; + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 149); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 153); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 157); + if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5)) + wpas_p2p_add_chan(&chan->reg_class[cla], 161); + if (chan->reg_class[cla].channels) + cla++; chan->reg_classes = cla; return 0; @@ -2120,9 +2214,16 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, } -static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags) +static int has_channel(struct wpa_global *global, + struct hostapd_hw_modes *mode, u8 chan, int *flags) { int i; + unsigned int freq; + + freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) + + chan * 5; + if (wpas_p2p_disallowed_freq(global, freq)) + return 0; for (i = 0; i < mode->num_channels; i++) { if (mode->channels[i].chan == chan) { @@ -2189,15 +2290,15 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, continue; for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { int flag; - if (!has_channel(mode, ch, &flag)) + if (!has_channel(wpa_s->global, mode, ch, &flag)) continue; if (o->bw == BW40MINUS && (!(flag & HOSTAPD_CHAN_HT40MINUS) || - !has_channel(mode, ch - 4, NULL))) + !has_channel(wpa_s->global, mode, ch - 4, NULL))) continue; if (o->bw == BW40PLUS && (!(flag & HOSTAPD_CHAN_HT40PLUS) || - !has_channel(mode, ch + 4, NULL))) + !has_channel(wpa_s->global, mode, ch + 4, NULL))) continue; if (reg == NULL) { wpa_printf(MSG_DEBUG, "P2P: Add operating " @@ -2404,6 +2505,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) global->p2p = p2p_init(&p2p); if (global->p2p == NULL) return -1; + global->p2p_init_wpa_s = wpa_s; for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) { if (wpa_s->conf->wps_vendor_ext[i] == NULL) @@ -2431,7 +2533,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) /* Clear any stored provisioning info */ p2p_clear_provisioning_info( wpa_s->global->p2p, - wpa_s->go_params->peer_interface_addr); + wpa_s->go_params->peer_device_addr); } os_free(wpa_s->go_params); @@ -2458,7 +2560,6 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) void wpas_p2p_deinit_global(struct wpa_global *global) { struct wpa_supplicant *wpa_s, *tmp; - char *ifname; if (global->p2p == NULL) return; @@ -2470,7 +2571,6 @@ void wpas_p2p_deinit_global(struct wpa_global *global) while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) wpa_s = wpa_s->next; while (wpa_s) { - enum wpa_driver_if_type type; tmp = global->ifaces; while (tmp && (tmp == wpa_s || @@ -2479,12 +2579,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global) } if (tmp == NULL) break; - ifname = os_strdup(tmp->ifname); - type = wpas_p2p_if_type(tmp->p2p_group_interface); - wpa_supplicant_remove_iface(global, tmp, 0); - if (ifname) - wpa_drv_if_remove(wpa_s, type, ifname); - os_free(ifname); + /* Disconnect from the P2P group and deinit the interface */ + wpas_p2p_disconnect(tmp); } /* @@ -2498,6 +2594,7 @@ void wpas_p2p_deinit_global(struct wpa_global *global) p2p_deinit(global->p2p); global->p2p = NULL; + global->p2p_init_wpa_s = NULL; } @@ -2522,7 +2619,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + struct wpa_ssid *ssid) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -2535,7 +2633,9 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, - persistent_group); + persistent_group, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0, + wpa_s->p2p_pd_before_go_neg); } @@ -2543,7 +2643,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + struct wpa_ssid *ssid) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -2553,7 +2654,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, - persistent_group); + persistent_group, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0); } @@ -2567,6 +2669,13 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) " for join operationg - stop join attempt", MAC2STR(wpa_s->pending_join_iface_addr)); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); + if (wpa_s->p2p_auto_pd) { + wpa_s->p2p_auto_pd = 0; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE + " p2p_dev_addr=" MACSTR " status=N/A", + MAC2STR(wpa_s->pending_join_dev_addr)); + return; + } wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); } @@ -2588,26 +2697,155 @@ static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx) } +static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq) +{ + struct wpa_supplicant *iface; + int shared_freq; + u8 bssid[ETH_ALEN]; + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) + return 0; + + for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { + if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s) + continue; + if (iface->current_ssid == NULL || iface->assoc_freq == 0) + continue; + if (iface->current_ssid->mode == WPAS_MODE_AP || + iface->current_ssid->mode == WPAS_MODE_P2P_GO) + shared_freq = iface->current_ssid->frequency; + else if (wpa_drv_get_bssid(iface, bssid) == 0) + shared_freq = iface->assoc_freq; + else + shared_freq = 0; + + if (shared_freq && freq != shared_freq) { + wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s " + "connected on %d MHz - new connection on " + "%d MHz", iface->ifname, shared_freq, freq); + return 1; + } + } + + shared_freq = wpa_drv_shared_freq(wpa_s); + if (shared_freq > 0 && shared_freq != freq) { + wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared " + "virtual interface connected on %d MHz - new " + "connection on %d MHz", shared_freq, freq); + return 1; + } + + return 0; +} + + +static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, + const u8 *peer_dev_addr) +{ + struct wpa_bss *bss; + int updated; + + bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr); + if (bss == NULL) + return -1; + if (bss->last_update_idx < wpa_s->bss_update_idx) { + wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the " + "last scan"); + return 0; + } + + updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update); + wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " + "%ld.%06ld (%supdated in last scan)", + bss->last_update.sec, bss->last_update.usec, + updated ? "": "not "); + + return updated; +} + + static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { struct wpa_bss *bss; int freq; u8 iface_addr[ETH_ALEN]; -#ifdef ANDROID_P2P - int shared_freq = 0; -#endif + eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); if (wpa_s->global->p2p_disabled) return; - wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join", - scan_res ? (int) scan_res->num : -1); + wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin", + scan_res ? (int) scan_res->num : -1, + wpa_s->p2p_auto_join ? "auto_" : ""); if (scan_res) wpas_p2p_scan_res_handler(wpa_s, scan_res); + if (wpa_s->p2p_auto_pd) { + int join = wpas_p2p_peer_go(wpa_s, + wpa_s->pending_join_dev_addr); + if (join == 0 && + wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) { + wpa_s->auto_pd_scan_retry++; + bss = wpa_bss_get_bssid(wpa_s, + wpa_s->pending_join_dev_addr); + if (bss) { + freq = bss->freq; + wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for " + "the peer " MACSTR " at %d MHz", + wpa_s->auto_pd_scan_retry, + MAC2STR(wpa_s-> + pending_join_dev_addr), + freq); + wpas_p2p_join_scan_req(wpa_s, freq); + return; + } + } + + if (join < 0) + join = 0; + + wpa_s->p2p_auto_pd = 0; + wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG; + wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d", + MAC2STR(wpa_s->pending_join_dev_addr), join); + if (p2p_prov_disc_req(wpa_s->global->p2p, + wpa_s->pending_join_dev_addr, + wpa_s->pending_pd_config_methods, join, + 0) < 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", + MAC2STR(wpa_s->pending_join_dev_addr)); + } + return; + } + + if (wpa_s->p2p_auto_join) { + int join = wpas_p2p_peer_go(wpa_s, + wpa_s->pending_join_dev_addr); + if (join < 0) { + wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " + "running a GO -> use GO Negotiation"); + wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, + wpa_s->p2p_pin, wpa_s->p2p_wps_method, + wpa_s->p2p_persistent_group, 0, 0, 0, + wpa_s->p2p_go_intent, + wpa_s->p2p_connect_freq, + wpa_s->p2p_persistent_id, + wpa_s->p2p_pd_before_go_neg); + return; + } + + wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> " + "try to join the group", join ? "" : + " in older scan"); + if (!join) + wpa_s->p2p_fallback_to_go_neg = 1; + } + freq = p2p_get_oper_freq(wpa_s->global->p2p, wpa_s->pending_join_iface_addr); if (freq < 0 && @@ -2631,16 +2869,6 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency " "from P2P peer table: %d MHz", freq); } - -#ifdef ANDROID_P2P - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && - ((shared_freq = wpa_drv_shared_freq(wpa_s)) > 0) && (shared_freq != freq)) { - wpa_msg(wpa_s->parent, MSG_INFO, - P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT"); - return; - } -#endif - bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr); if (bss) { freq = bss->freq; @@ -2650,6 +2878,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (freq > 0) { u16 method; + if (wpas_check_freq_conflict(wpa_s, freq) > 0) { + wpa_msg(wpa_s->parent, MSG_INFO, + P2P_EVENT_GROUP_FORMATION_FAILURE + "reason=FREQ_CONFLICT"); + return; + } + wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request " "prior to joining an existing group (GO " MACSTR " freq=%u MHz)", @@ -2722,13 +2957,13 @@ start: } -static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) +static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq) { - struct wpa_supplicant *wpa_s = eloop_ctx; int ret; struct wpa_driver_scan_params params; struct wpabuf *wps_ie, *ies; size_t ielen; + int freqs[2] = { 0, 0 }; os_memset(¶ms, 0, sizeof(params)); @@ -2738,8 +2973,9 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid, - WPS_REQ_ENROLLEE, 0, NULL); + wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev, + wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0, + NULL); if (wps_ie == NULL) { wpas_p2p_scan_res_join(wpa_s, NULL); return; @@ -2760,13 +2996,18 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) params.p2p_probe = 1; params.extra_ies = wpabuf_head(ies); params.extra_ies_len = wpabuf_len(ies); + if (freq > 0) { + freqs[0] = freq; + params.freqs = freqs; + } /* * Run a scan to update BSS table and start Provision Discovery once * the new scan results become available. */ - wpa_s->scan_res_handler = wpas_p2p_scan_res_join; ret = wpa_drv_scan(wpa_s, ¶ms); + if (!ret) + wpa_s->scan_res_handler = wpas_p2p_scan_res_join; wpabuf_free(ies); @@ -2780,13 +3021,24 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) } +static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + wpas_p2p_join_scan_req(wpa_s, 0); +} + + static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, - const u8 *dev_addr, enum p2p_wps_method wps_method) + const u8 *dev_addr, enum p2p_wps_method wps_method, + int auto_join) { wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface " - MACSTR " dev " MACSTR ")", - MAC2STR(iface_addr), MAC2STR(dev_addr)); + MACSTR " dev " MACSTR ")%s", + MAC2STR(iface_addr), MAC2STR(dev_addr), + auto_join ? " (auto_join)" : ""); + wpa_s->p2p_auto_pd = 0; + wpa_s->p2p_auto_join = !!auto_join; os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN); os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN); wpa_s->pending_join_wps_method = wps_method; @@ -2804,6 +3056,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) { struct wpa_supplicant *group; 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); @@ -2816,11 +3069,19 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) } group->p2p_in_provisioning = 1; + group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg; os_memset(&res, 0, sizeof(res)); os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr, ETH_ALEN); res.wps_method = wpa_s->pending_join_wps_method; + bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr); + if (bss) { + res.freq = bss->freq; + res.ssid_len = bss->ssid_len; + os_memcpy(res.ssid, bss->ssid, bss->ssid_len); + } + if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to " "starting client"); @@ -2849,30 +3110,43 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) * @peer_addr: Address of the peer P2P Device * @pin: PIN to use during provisioning or %NULL to indicate PBC mode * @persistent_group: Whether to create a persistent group + * @auto_join: Whether to select join vs. GO Negotiation automatically * @join: Whether to join an existing group (as a client) instead of starting * Group Owner negotiation; @peer_addr is BSSID in that case * @auth: Whether to only authorize the connection instead of doing that and * initiating Group Owner negotiation * @go_intent: GO Intent or -1 to use default * @freq: Frequency for the group or 0 for auto-selection + * @persistent_id: Persistent group credentials to use for forcing GO + * parameters or -1 to generate new values (SSID/passphrase) + * @pd: Whether to send Provision Discovery prior to GO Negotiation as an + * interoperability workaround when initiating group formation * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported */ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, - int persistent_group, int join, int auth, int go_intent, - int freq) + int persistent_group, int auto_join, int join, int auth, + int go_intent, int freq, int persistent_id, int pd) { int force_freq = 0, oper_freq = 0; u8 bssid[ETH_ALEN]; int ret = 0; enum wpa_driver_if_type iftype; const u8 *if_addr; + struct wpa_ssid *ssid = NULL; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + if (persistent_id >= 0) { + ssid = wpa_config_get_network(wpa_s->conf, persistent_id); + if (ssid == NULL || ssid->disabled != 2 || + ssid->mode != WPAS_MODE_P2P_GO) + return -1; + } + if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; @@ -2880,6 +3154,12 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_long_listen = 0; wpa_s->p2p_wps_method = wps_method; + wpa_s->p2p_persistent_group = !!persistent_group; + wpa_s->p2p_persistent_id = persistent_id; + wpa_s->p2p_go_intent = go_intent; + wpa_s->p2p_connect_freq = freq; + wpa_s->p2p_fallback_to_go_neg = 0; + wpa_s->p2p_pd_before_go_neg = !!pd; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -2892,7 +3172,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } else wpa_s->p2p_pin[0] = '\0'; - if (join) { + if (join || auto_join) { u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN]; if (auth) { wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to " @@ -2908,8 +3188,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, 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) + if (auto_join) { + os_get_time(&wpa_s->p2p_auto_started); + wpa_printf(MSG_DEBUG, "P2P: Auto join started at " + "%ld.%06ld", + wpa_s->p2p_auto_started.sec, + wpa_s->p2p_auto_started.usec); + } + if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method, + auto_join) < 0) return -1; return ret; } @@ -2982,14 +3269,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (auth) { if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, - force_freq, persistent_group) < 0) + force_freq, persistent_group, ssid) < + 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) < 0) { + persistent_group, ssid) < 0) { if (wpa_s->create_p2p_iface) wpas_p2p_remove_pending_group_interface(wpa_s); return -1; @@ -3147,7 +3435,18 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz " "channel %d MHz", params->freq); } else { - params->freq = 2412; + int chan; + for (chan = 0; chan < 11; chan++) { + params->freq = 2412 + chan * 5; + if (!wpas_p2p_disallowed_freq(wpa_s->global, + params->freq)) + break; + } + if (chan == 11) { + wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel " + "allowed"); + return -1; + } wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference " "known)", params->freq); } @@ -3270,6 +3569,13 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq)) return -1; + if (params.freq && + !p2p_supported_freq(wpa_s->global->p2p, params.freq)) { + 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; @@ -3346,6 +3652,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, /* Make sure we are not running find during connection establishment */ wpas_p2p_stop_find(wpa_s); + wpa_s->p2p_fallback_to_go_neg = 0; + if (ssid->mode == WPAS_MODE_INFRA) return wpas_start_p2p_client(wpa_s, ssid, addr_allocated); @@ -3409,18 +3717,15 @@ static void wpas_p2p_idle_update(void *ctx, int idle) if (!wpa_s->ap_iface) return; wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not "); - if (idle) { - wpa_printf(MSG_DEBUG,"Calling set group idle time out from idle_update"); + if (idle) wpas_p2p_set_group_idle_timeout(wpa_s); - } else eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); } struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, - int persistent_group, - int group_formation) + struct wpa_ssid *ssid) { struct p2p_group *group; struct p2p_group_config *cfg; @@ -3434,9 +3739,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, if (cfg == NULL) return NULL; - if (persistent_group && wpa_s->conf->persistent_reconnect) + if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect) cfg->persistent_group = 2; - else if (persistent_group) + else if (ssid->p2p_persistent_group) cfg->persistent_group = 1; os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN); if (wpa_s->max_stations && @@ -3444,6 +3749,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, cfg->max_clients = wpa_s->max_stations; else cfg->max_clients = wpa_s->conf->max_num_sta; + os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len); + cfg->ssid_len = ssid->ssid_len; cfg->cb_ctx = wpa_s; cfg->ie_update = wpas_p2p_ie_update; cfg->idle_update = wpas_p2p_idle_update; @@ -3451,7 +3758,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, group = p2p_group_init(wpa_s->global->p2p, cfg); if (group == NULL) os_free(cfg); - if (!group_formation) + if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) p2p_group_notif_formation_done(group); wpa_s->p2p_group = group; return group; @@ -3461,17 +3768,36 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int registrar) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + if (!wpa_s->p2p_in_provisioning) { wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P " "provisioning not in progress"); return; } - /* Clear any stored provisioning info */ - p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr); + if (ssid && ssid->mode == WPAS_MODE_INFRA) { + u8 go_dev_addr[ETH_ALEN]; + os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN); + wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid, + ssid->ssid_len); + /* Clear any stored provisioning info */ + p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr); + } eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); + if (ssid && ssid->mode == WPAS_MODE_INFRA) { + /* + * Use a separate timeout for initial data connection to + * complete to allow the group to be removed automatically if + * something goes wrong in this step before the P2P group idle + * timeout mechanism is taken into use. + */ + eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, + wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + } if (wpa_s->global->p2p) p2p_wps_success_cb(wpa_s->global->p2p, peer_addr); else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) @@ -3492,7 +3818,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, if (wpa_s->go_params) { p2p_clear_provisioning_info( wpa_s->global->p2p, - wpa_s->go_params->peer_interface_addr); + wpa_s->go_params->peer_device_addr); } wpas_notify_p2p_wps_failed(wpa_s, fail); @@ -3500,10 +3826,13 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, - const char *config_method, int join) + const char *config_method, + enum wpas_p2p_prov_disc_use use) { u16 config_methods; + wpa_s->p2p_fallback_to_go_neg = 0; + wpa_s->pending_pd_use = NORMAL_PD; if (os_strncmp(config_method, "display", 7) == 0) config_methods = WPS_CONFIG_DISPLAY; else if (os_strncmp(config_method, "keypad", 6) == 0) @@ -3516,16 +3845,35 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } + if (use == WPAS_P2P_PD_AUTO) { + os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN); + wpa_s->pending_pd_config_methods = config_methods; + wpa_s->p2p_auto_pd = 1; + wpa_s->p2p_auto_join = 0; + wpa_s->pending_pd_before_join = 0; + wpa_s->auto_pd_scan_retry = 0; + wpas_p2p_stop_find(wpa_s); + wpa_s->p2p_join_scan_count = 0; + os_get_time(&wpa_s->p2p_auto_started); + wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld", + wpa_s->p2p_auto_started.sec, + wpa_s->p2p_auto_started.usec); + wpas_p2p_join_scan(wpa_s, NULL); + return 0; + } + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr, - config_methods, join); + config_methods, + use == WPAS_P2P_PD_FOR_JOIN); } if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return -1; return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, - config_methods, join, 0); + config_methods, use == WPAS_P2P_PD_FOR_JOIN, + 0); } @@ -3559,7 +3907,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) return wpa_drv_p2p_find(wpa_s, timeout, type); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || + wpa_s->p2p_in_provisioning) return -1; wpa_supplicant_cancel_sched_scan(wpa_s); @@ -3661,15 +4010,27 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, int ssi_signal) { if (wpa_s->global->p2p_disabled) return 0; if (wpa_s->global->p2p == NULL) return 0; - return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid, - ie, ie_len); + switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid, + ie, ie_len)) { + case P2P_PREQ_NOT_P2P: + wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len, + ssi_signal); + /* fall through */ + case P2P_PREQ_MALFORMED: + case P2P_PREQ_NOT_LISTEN: + case P2P_PREQ_NOT_PROCESSED: + default: /* make gcc happy */ + return 0; + case P2P_PREQ_PROCESSED: + return 1; + } } @@ -3840,6 +4201,11 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) int persistent; int freq; + if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) { + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + } + if (!wpa_s->show_group_started || !ssid) return; @@ -3936,18 +4302,20 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx) return; } - wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate %d" - "group",wpa_s->conf->p2p_group_idle); + wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate " + "group"); wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT; - wpas_p2p_group_delete(wpa_s); + wpas_p2p_group_delete(wpa_s, 0); } static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s) { - unsigned int timeout; + int timeout; + + if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) + wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); - eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group) return; @@ -3959,6 +4327,37 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s) if (timeout == 0) return; + if (timeout < 0) { + if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA) + timeout = 0; /* special client mode no-timeout */ + else + return; + } + + if (wpa_s->p2p_in_provisioning) { + /* + * Use the normal group formation timeout during the + * provisioning phase to avoid terminating this process too + * early due to group idle timeout. + */ + wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout " + "during provisioning"); + return; + } + + if (wpa_s->show_group_started) { + /* + * Use the normal group formation timeout between the end of + * the provisioning phase and completion of 4-way handshake to + * avoid terminating this process too early due to group idle + * timeout. + */ + wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout " + "while waiting for initial 4-way handshake to " + "complete"); + return; + } + wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds", timeout); eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout, @@ -3967,26 +4366,42 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s) void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, - u16 reason_code, const u8 *ie, size_t ie_len) + u16 reason_code, const u8 *ie, size_t ie_len, + int locally_generated) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) return; - p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); + if (!locally_generated) + p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, + ie_len); + + if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated && + wpa_s->current_ssid && + wpa_s->current_ssid->p2p_group && + wpa_s->current_ssid->mode == WPAS_MODE_INFRA) { + wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group " + "session is ending"); + wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION; + wpas_p2p_group_delete(wpa_s, 0); + } } void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, - u16 reason_code, const u8 *ie, size_t ie_len) + u16 reason_code, const u8 *ie, size_t ie_len, + int locally_generated) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) return; - p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); + if (!locally_generated) + p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, + ie_len); } @@ -4102,6 +4517,14 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s) wpa_printf(MSG_ERROR, "P2P: Own oper channel update " "failed: %d", ret); } + + if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) { + if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan, + wpa_s->conf->p2p_pref_chan) < 0) { + wpa_printf(MSG_ERROR, "P2P: Preferred channel list " + "update failed"); + } + } } @@ -4200,8 +4623,9 @@ void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s) wpas_p2p_disable_cross_connect(wpa_s); else wpas_p2p_enable_cross_connect(wpa_s); - if (!wpa_s->ap_iface) - eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); + if (!wpa_s->ap_iface && + eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) + wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); } @@ -4211,10 +4635,7 @@ void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s) if (!wpa_s->ap_iface && !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout, wpa_s, NULL)) - { - wpa_printf(MSG_DEBUG,"Calling set grouple idle_timeout from notif_disconnected"); wpas_p2p_set_group_idle_timeout(wpa_s); - } } @@ -4316,6 +4737,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer " MACSTR, MAC2STR(peer)); p2p_unauthorize(global->p2p, peer); + found = 1; } wpas_p2p_stop_find(wpa_s); @@ -4331,7 +4753,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) found = 1; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); - wpas_p2p_group_delete(wpa_s); + wpas_p2p_group_delete(wpa_s, 0); break; } } @@ -4353,7 +4775,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not " "being available anymore"); wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE; - wpas_p2p_group_delete(wpa_s); + wpas_p2p_group_delete(wpa_s, 0); } @@ -4400,7 +4822,7 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s) return -1; wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED; - wpas_p2p_group_delete(wpa_s); + wpas_p2p_group_delete(wpa_s, 0); return 0; } @@ -4417,20 +4839,22 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s) void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) - { if (wpa_s->p2p_in_provisioning && ssid->p2p_group && eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL) > 0) { + /** + * Remove the network by scheduling the group formation + * timeout to happen immediately. The teardown code + * needs to be scheduled to run asynch later so that we + * don't delete data from under ourselves unexpectedly. + * Calling wpas_p2p_group_formation_timeout directly + * causes a series of crashes in WPS failure scenarios. + */ wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to " "P2P group network getting removed"); -#ifdef ANDROID_P2P - /* Give time for any Pending WPS Frame exchange */ - eloop_register_timeout(5, 0, wpas_p2p_group_formation_timeout, - wpa_s->parent, NULL); -#else - wpas_p2p_group_formation_timeout(wpa_s->parent, NULL); -#endif + eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); } } @@ -4473,6 +4897,43 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, wpas_p2p_add_persistent_group_client(wpa_s, addr); } + +static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, + 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; + offchannel_send_action_done(wpa_s); + if (group_added) + wpas_p2p_group_delete(group, 1); + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation"); + wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, + wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, + 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, + wpa_s->p2p_persistent_id, + wpa_s->p2p_pd_before_go_neg); +} + + +int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->p2p_fallback_to_go_neg || + wpa_s->p2p_in_provisioning <= 5) + return 0; + + if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0) + return 0; /* peer operating as a GO */ + + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - " + "fallback to GO Negotiation"); + wpas_p2p_fallback_to_go_neg(wpa_s, 1); + + return 1; +} + #ifdef ANDROID_P2P int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq) { @@ -4503,7 +4964,7 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq) wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel" "concurrent mode frequency conflict"); iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT; - wpas_p2p_group_delete(iface); + wpas_p2p_group_delete(iface, 0); } else { /* Existing connection has the priority. Disable the newly * selected network and let the application know about it. |