P2P: Support dedicated P2P_DEVICE without separate group interface

Add support for drivers with dedicated P2P_DEVICE interface, but without
group interface concurrency (only a single netdev is used). With such
devices, wpa_supplicant tried to use the p2p_dev interface instead of
the group interface and most P2P operations failed. Extend
wpa_supplicant to use the primary interface instead of a separate group
interface in such cases.

Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
This commit is contained in:
Lior David 2016-01-24 17:36:49 +02:00 committed by Jouni Malinen
parent ba307f8528
commit 96a26ab744
2 changed files with 76 additions and 30 deletions

View file

@ -800,6 +800,8 @@ grp_owner:
s = wpas_p2p_get_persistent_go(wpa_s); s = wpas_p2p_get_persistent_go(wpa_s);
if (!s && !go_wpa_s && p2p_no_group_iface) { if (!s && !go_wpa_s && p2p_no_group_iface) {
p2p_set_intended_addr(wpa_s->global->p2p, p2p_set_intended_addr(wpa_s->global->p2p,
wpa_s->p2p_mgmt ?
wpa_s->parent->own_addr :
wpa_s->own_addr); wpa_s->own_addr);
} else if (!s && !go_wpa_s) { } else if (!s && !go_wpa_s) {
if (wpas_p2p_add_group_interface(wpa_s, if (wpas_p2p_add_group_interface(wpa_s,
@ -949,6 +951,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
return 1; return 1;
} }
/*
* The primary interface was used for P2P group operations, so
* need to reset its p2pdev.
*/
wpa_s->p2pdev = wpa_s->parent;
if (!wpa_s->p2p_go_group_formation_completed) { if (!wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL; wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0; wpa_s->p2p_in_provisioning = 0;
@ -1976,6 +1984,23 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
} }
static void wpas_p2p_clone_config_dh(struct wpa_supplicant *dst,
const struct wpa_supplicant *src)
{
struct wpa_config *d;
const struct wpa_config *s;
d = dst->conf;
s = src->conf;
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
!d->wps_nfc_dh_privkey && !d->wps_nfc_dh_pubkey) {
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
}
}
static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s, static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
char *ifname, size_t len) char *ifname, size_t len)
{ {
@ -2159,6 +2184,7 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{ {
struct wpa_supplicant *wpa_s = ctx; struct wpa_supplicant *wpa_s = ctx;
struct wpa_supplicant *group_wpa_s;
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s); wpa_drv_cancel_remain_on_channel(wpa_s);
@ -2211,7 +2237,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
} }
if (wpa_s->create_p2p_iface) { if (wpa_s->create_p2p_iface) {
struct wpa_supplicant *group_wpa_s = group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go); wpas_p2p_init_group_interface(wpa_s, res->role_go);
if (group_wpa_s == NULL) { if (group_wpa_s == NULL) {
wpas_p2p_remove_pending_group_interface(wpa_s); wpas_p2p_remove_pending_group_interface(wpa_s);
@ -2220,32 +2246,28 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_p2p_group_formation_failed(wpa_s, 1); wpas_p2p_group_formation_failed(wpa_s, 1);
return; return;
} }
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
} else {
group_wpa_s = wpa_s->parent;
wpa_s->global->p2p_group_formation = group_wpa_s;
if (group_wpa_s != wpa_s)
wpas_p2p_clone_config_dh(group_wpa_s, wpa_s);
}
group_wpa_s->p2p_in_provisioning = 1;
group_wpa_s->p2pdev = wpa_s;
if (group_wpa_s != wpa_s) { if (group_wpa_s != wpa_s) {
os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin, os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
sizeof(group_wpa_s->p2p_pin)); sizeof(group_wpa_s->p2p_pin));
group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method; group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
} }
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
group_wpa_s->p2p_in_provisioning = 1;
if (res->role_go) { if (res->role_go) {
wpas_start_wps_go(group_wpa_s, res, 1); wpas_start_wps_go(group_wpa_s, res, 1);
} else { } else {
os_get_reltime(&group_wpa_s->scan_min_time); os_get_reltime(&group_wpa_s->scan_min_time);
wpas_start_wps_enrollee(group_wpa_s, res); wpas_start_wps_enrollee(group_wpa_s, res);
} }
} else {
wpa_s->p2p_in_provisioning = 1;
wpa_s->global->p2p_group_formation = wpa_s;
if (res->role_go) {
wpas_start_wps_go(wpa_s, res, 1);
} else {
os_get_reltime(&wpa_s->scan_min_time);
wpas_start_wps_enrollee(ctx, res);
}
}
wpa_s->p2p_long_listen = 0; wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
@ -2903,6 +2925,10 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
"invitation"); "invitation");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
} }
if (wpa_s->p2p_mgmt)
os_memcpy(group_bssid, wpa_s->parent->own_addr,
ETH_ALEN);
else
os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN); os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
} else if (s->mode == WPAS_MODE_P2P_GO) { } else if (s->mode == WPAS_MODE_P2P_GO) {
*go = 1; *go = 1;
@ -3733,6 +3759,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
return -1; return -1;
} }
p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0'; wpa_s->pending_interface_name[0] = '\0';
return 0; return 0;
} }
@ -4514,8 +4541,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global)
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s) static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{ {
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && if (wpa_s->conf->p2p_no_group_iface)
wpa_s->conf->p2p_no_group_iface)
return 0; /* separate interface disabled per configuration */ return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags & if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE | (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@ -5397,6 +5423,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
if_addr = wpa_s->pending_interface_addr; if_addr = wpa_s->pending_interface_addr;
} else { } else {
if (wpa_s->p2p_mgmt)
if_addr = wpa_s->parent->own_addr;
else
if_addr = wpa_s->own_addr; if_addr = wpa_s->own_addr;
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN); os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
} }
@ -5943,9 +5972,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
struct wpa_supplicant *group_wpa_s; 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 " if (wpa_s->p2p_mgmt) {
"operations"); /*
* We may be called on the p2p_dev interface which
* cannot be used for group operations, so always use
* the primary interface.
*/
wpa_s->parent->p2pdev = wpa_s;
wpa_s = wpa_s->parent;
}
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P: Use primary interface for group operations");
wpa_s->p2p_first_connection_timeout = 0; wpa_s->p2p_first_connection_timeout = 0;
if (wpa_s != wpa_s->p2pdev)
wpas_p2p_clone_config_dh(wpa_s, wpa_s->p2pdev);
return wpa_s; return wpa_s;
} }
@ -6745,7 +6785,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1; return -1;
} }
bssid = wpa_s->pending_interface_addr; bssid = wpa_s->pending_interface_addr;
} else } else if (wpa_s->p2p_mgmt)
bssid = wpa_s->parent->own_addr;
else
bssid = wpa_s->own_addr; bssid = wpa_s->own_addr;
} else { } else {
role = P2P_INVITE_ROLE_CLIENT; role = P2P_INVITE_ROLE_CLIENT;
@ -8671,7 +8713,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
} }
if_addr = wpa_s->pending_interface_addr; if_addr = wpa_s->pending_interface_addr;
} else } else if (wpa_s->p2p_mgmt)
if_addr = wpa_s->parent->own_addr;
else
if_addr = wpa_s->own_addr; if_addr = wpa_s->own_addr;
wpa_s->p2p_nfc_tag_enabled = enabled; wpa_s->p2p_nfc_tag_enabled = enabled;

View file

@ -4840,6 +4840,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
iface = global->ifaces; iface = global->ifaces;
while (iface) { while (iface) {
if (iface->p2pdev == wpa_s)
iface->p2pdev = iface->parent;
if (iface == wpa_s || iface->parent != wpa_s) { if (iface == wpa_s || iface->parent != wpa_s) {
iface = iface->next; iface = iface->next;
continue; continue;