[PATCH 1/2] P2P: Honor peer channel preference in reselect_channel
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Thu Oct 8 04:30:48 PDT 2026
When re-selecting the operating channel during P2P invitation, the P2P GO
would pick a random VHT channel even when the peer specified a preferred
operating channel. This caused the group to end up on a different channel
than the one the P2P Client was operating on, which is particularly
problematic in concurrency scenarios where the client is already connected
to an AP.
Pass the peer's preferred frequency to p2p_reselect_channel() and use it
as a fallback before random channel selection.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/p2p/p2p_go_neg.c | 20 +++++++++++++++++---
src/p2p/p2p_i.h | 3 ++-
src/p2p/p2p_invitation.c | 14 ++++++++------
3 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 79cdfa7d25..b3e2bd8075 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -433,6 +433,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
* p2p_reselect_channel - Re-select operating channel based on peer information
* @p2p: P2P module context from p2p_init()
* @intersection: Support channel list intersection from local and peer
+ * @peer_freq: Peer's preferred operating frequency in MHz, or 0 if not
+ * specified
*
* This function is used to re-select the best channel after having received
* information from the peer to allow supported channel lists to be intersected.
@@ -441,7 +443,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
* can be used for Invitation case.
*/
void p2p_reselect_channel(struct p2p_data *p2p,
- struct p2p_channels *intersection)
+ struct p2p_channels *intersection,
+ int peer_freq)
{
struct p2p_reg_class *cl;
int freq;
@@ -515,6 +518,17 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
}
+ /* Honor peer's channel preference over random selection */
+ if (peer_freq > 0 &&
+ p2p_freq_to_channel(peer_freq, &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ p2p_dbg(p2p, "Use peer preferred channel (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
+
/* Try a channel where we might be able to use EDMG */
if (p2p_channel_select(intersection, op_classes_edmg,
&p2p->op_reg_class, &p2p->op_channel) == 0) {
@@ -602,12 +616,12 @@ int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
p2p_dbg(p2p, "Selected operating channel (op_class %u channel %u) not acceptable to the peer",
p2p->op_reg_class, p2p->op_channel);
- p2p_reselect_channel(p2p, &intersection);
+ p2p_reselect_channel(p2p, &intersection, 0);
} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
!p2p->cfg->cfg_op_channel) {
p2p_dbg(p2p, "Try to optimize channel selection with peer information received; previously selected op_class %u channel %u",
p2p->op_reg_class, p2p->op_channel);
- p2p_reselect_channel(p2p, &intersection);
+ p2p_reselect_channel(p2p, &intersection, 0);
}
if (!p2p->ssid_set) {
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index cae7c584ff..fa8ac608ac 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -1013,7 +1013,8 @@ struct wpabuf * p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
void p2p_reselect_channel(struct p2p_data *p2p,
- struct p2p_channels *intersection);
+ struct p2p_channels *intersection,
+ int peer_freq);
void p2p_check_pref_chan(struct p2p_data *p2p, int go,
struct p2p_device *dev, struct p2p_message *msg);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 50e73333ec..70ecab9d30 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -349,6 +349,8 @@ struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (status == P2P_SC_SUCCESS)
channels = &intersection;
} else {
+ int peer_freq = 0;
+
p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
/* Default to own configuration as a starting point */
@@ -369,14 +371,14 @@ struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
#endif /* CONFIG_TESTING_OPTIONS */
/* Use peer preference if specified and compatible */
+
if (msg.operating_channel) {
- int req_freq;
- req_freq = p2p_channel_to_freq(
+ peer_freq = p2p_channel_to_freq(
msg.operating_channel[3],
msg.operating_channel[4]);
p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
- req_freq);
- if (req_freq > 0 &&
+ peer_freq);
+ if (peer_freq > 0 &&
p2p_channels_includes(&intersection,
msg.operating_channel[3],
msg.operating_channel[4])) {
@@ -395,7 +397,7 @@ struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
p2p->op_channel)) {
p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
p2p->op_reg_class, p2p->op_channel);
- p2p_reselect_channel(p2p, &intersection);
+ p2p_reselect_channel(p2p, &intersection, 0);
p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
if (!p2p_channels_includes(&intersection,
@@ -410,7 +412,7 @@ struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
!p2p->cfg->cfg_op_channel) {
p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
p2p->op_reg_class, p2p->op_channel);
- p2p_reselect_channel(p2p, &intersection);
+ p2p_reselect_channel(p2p, &intersection, peer_freq);
}
/*
--
2.53.0
More information about the Hostap
mailing list