diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 856f78f52..c753d4939 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -92,6 +92,7 @@ struct p2p_device { #define P2P_DEV_REPORTED_ONCE BIT(15) #define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16) #define P2P_DEV_PD_BEFORE_GO_NEG BIT(17) +#define P2P_DEV_NO_PREF_CHAN BIT(18) unsigned int flags; int status; /* enum p2p_status_code */ diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 918fd4bf1..9cde8bfae 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -62,8 +62,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, p2p->client_timeout); p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? P2P_INVITATION_FLAGS_TYPE : 0); - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, p2p->op_channel); + if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT || + !(peer->flags & P2P_DEV_NO_PREF_CHAN)) + p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p->op_reg_class, + p2p->op_channel); if (p2p->inv_bssid_set) p2p_buf_add_group_bssid(buf, p2p->inv_bssid); p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); @@ -564,6 +567,12 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0) return -1; + if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq && + !pref_freq) + dev->flags |= P2P_DEV_NO_PREF_CHAN; + else + dev->flags &= ~P2P_DEV_NO_PREF_CHAN; + if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { if (!(dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index fb99c7bcd..8447a9044 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -365,7 +365,7 @@ Remove all local services from internal SD query processing. Invitation p2p_invite [persistent=|group=] [peer=address] - [go_dev_addr=address] [freq=] [ht40] + [go_dev_addr=address] [freq=] [ht40] [pref=] Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a persistent group (e.g., persistent=4). If the peer device is the GO of @@ -374,7 +374,11 @@ used to specify which device to invite. go_dev_addr parameter can be used to override the GO device address for Invitation Request should it be not known for some reason (this should not be needed in most cases). When reinvoking a persistent group, the GO device can specify -the frequency for the group with the freq parameter. +the frequency for the group with the freq parameter. When reinvoking a +persistent group, the P2P client device can use freq parameter to force +a specific operating channel (or invitation failure if GO rejects that) +or pref parameter to request a specific channel (while allowing GO to +select to use another channel, if needed). Group Operations diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 06efd2c5a..0804d7184 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -3969,7 +3969,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) int id; struct wpa_ssid *ssid; u8 *_peer = NULL, peer[ETH_ALEN]; - int freq = 0; + int freq = 0, pref_freq = 0; int ht40; id = atoi(cmd); @@ -3996,9 +3996,17 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) return -1; } + pos = os_strstr(cmd, " pref="); + if (pos) { + pos += 6; + pref_freq = atoi(pos); + if (pref_freq <= 0) + return -1; + } + ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40; - return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40); + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 30e0eb3e5..6279f415f 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -630,7 +630,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, if (ssid == NULL || ssid->disabled != 2) goto err; - if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) { + if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0) + { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 4ec6ed117..004cf74b3 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3585,7 +3585,7 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, "(%u MHz) not available for P2P - try to use " "another channel", *oper_freq); *force_freq = 0; - } else if (*oper_freq > 0 && + } else if (*oper_freq > 0 && *pref_freq == 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we " @@ -4583,11 +4583,11 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) /* Invite to reinvoke a persistent group */ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, - int ht40) + int ht40, int pref_freq) { enum p2p_invite_role role; u8 *bssid = NULL, bssid_buf[ETH_ALEN]; - int force_freq = 0, pref_freq = 0, oper_freq = 0; + int force_freq = 0, oper_freq = 0; int res; wpa_s->p2p_persistent_go_freq = freq; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index b6ecf14cf..caeac7c16 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -105,7 +105,7 @@ int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version, int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, - int ht40); + int ht40, int pref_freq); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr); void wpas_p2p_completed(struct wpa_supplicant *wpa_s);