P2P: Allow peer to propose channel in invitation process
Make Invitation process for re-invoking a persistent group behave similarly to GO Negotiation as far as channel negotiation is concerned. The Operating Channel value (if present) is used as a starting point if the local device does not have a forced operating channel (e.g., due to concurrent use). Channel lists from devices are then compared to check that the selected channel is in the intersection. If not, channel is selected based on GO Negotiation channel rules (best channel preferences etc.). Invitation Request is rejected if no common channel can be selected. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
7759fba1c2
commit
2cd0758441
4 changed files with 80 additions and 10 deletions
|
@ -336,7 +336,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void p2p_reselect_channel(struct p2p_data *p2p,
|
void p2p_reselect_channel(struct p2p_data *p2p,
|
||||||
struct p2p_channels *intersection)
|
struct p2p_channels *intersection)
|
||||||
{
|
{
|
||||||
struct p2p_reg_class *cl;
|
struct p2p_reg_class *cl;
|
||||||
|
|
|
@ -642,6 +642,8 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
|
||||||
const u8 *data, size_t len);
|
const u8 *data, size_t len);
|
||||||
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
|
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
|
||||||
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
|
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
|
||||||
|
void p2p_reselect_channel(struct p2p_data *p2p,
|
||||||
|
struct p2p_channels *intersection);
|
||||||
|
|
||||||
/* p2p_pd.c */
|
/* p2p_pd.c */
|
||||||
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
|
|
|
@ -233,6 +233,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op_freq) {
|
if (op_freq) {
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
|
||||||
|
"processing forced frequency %d MHz", op_freq);
|
||||||
if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
|
if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
|
||||||
®_class, &channel) < 0) {
|
®_class, &channel) < 0) {
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
@ -256,24 +258,89 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
if (status == P2P_SC_SUCCESS)
|
if (status == P2P_SC_SUCCESS)
|
||||||
channels = &intersection;
|
channels = &intersection;
|
||||||
} else {
|
} else {
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"P2P: No forced channel from invitation processing - "
|
||||||
|
"figure out best one to use");
|
||||||
|
|
||||||
|
p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
|
||||||
|
&intersection);
|
||||||
|
/* Default to own configuration as a starting point */
|
||||||
|
p2p->op_reg_class = p2p->cfg->op_reg_class;
|
||||||
|
p2p->op_channel = p2p->cfg->op_channel;
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own default "
|
||||||
|
"op_class %d channel %d",
|
||||||
|
p2p->op_reg_class, p2p->op_channel);
|
||||||
|
|
||||||
|
/* Use peer preference if specified and compatible */
|
||||||
|
if (msg.operating_channel) {
|
||||||
|
int req_freq;
|
||||||
|
req_freq = p2p_channel_to_freq(
|
||||||
|
(const char *) msg.operating_channel,
|
||||||
|
msg.operating_channel[3],
|
||||||
|
msg.operating_channel[4]);
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
|
||||||
|
"operating channel preference: %d MHz",
|
||||||
|
req_freq);
|
||||||
|
if (req_freq > 0 &&
|
||||||
|
p2p_channels_includes(&intersection,
|
||||||
|
msg.operating_channel[3],
|
||||||
|
msg.operating_channel[4])) {
|
||||||
|
p2p->op_reg_class = msg.operating_channel[3];
|
||||||
|
p2p->op_channel = msg.operating_channel[4];
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"P2P: Use peer preference op_class %d "
|
||||||
|
"channel %d",
|
||||||
|
p2p->op_reg_class, p2p->op_channel);
|
||||||
|
} else {
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"P2P: Cannot use peer channel "
|
||||||
|
"preference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
|
||||||
|
p2p->op_channel)) {
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"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);
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"P2P: Re-selection result: op_class %d "
|
||||||
|
"channel %d",
|
||||||
|
p2p->op_reg_class, p2p->op_channel);
|
||||||
|
if (!p2p_channels_includes(&intersection,
|
||||||
|
p2p->op_reg_class,
|
||||||
|
p2p->op_channel)) {
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
"P2P: Peer does not support selected "
|
||||||
|
"operating channel (reg_class=%u "
|
||||||
|
"channel=%u)",
|
||||||
|
p2p->op_reg_class, p2p->op_channel);
|
||||||
|
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
op_freq = p2p_channel_to_freq(p2p->cfg->country,
|
op_freq = p2p_channel_to_freq(p2p->cfg->country,
|
||||||
p2p->cfg->op_reg_class,
|
p2p->op_reg_class,
|
||||||
p2p->cfg->op_channel);
|
p2p->op_channel);
|
||||||
if (op_freq < 0) {
|
if (op_freq < 0) {
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
"P2P: Unknown operational channel "
|
"P2P: Unknown operational channel "
|
||||||
"(country=%c%c reg_class=%u channel=%u)",
|
"(country=%c%c reg_class=%u channel=%u)",
|
||||||
p2p->cfg->country[0], p2p->cfg->country[1],
|
p2p->cfg->country[0], p2p->cfg->country[1],
|
||||||
p2p->cfg->op_reg_class, p2p->cfg->op_channel);
|
p2p->op_reg_class, p2p->op_channel);
|
||||||
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
|
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
|
||||||
|
"channel - %d MHz", op_freq);
|
||||||
|
|
||||||
p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
|
|
||||||
&intersection);
|
|
||||||
if (status == P2P_SC_SUCCESS) {
|
if (status == P2P_SC_SUCCESS) {
|
||||||
reg_class = p2p->cfg->op_reg_class;
|
reg_class = p2p->op_reg_class;
|
||||||
channel = p2p->cfg->op_channel;
|
channel = p2p->op_channel;
|
||||||
channels = &intersection;
|
channels = &intersection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2249,8 +2249,9 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
|
||||||
" was accepted; op_freq=%d MHz",
|
" was accepted; op_freq=%d MHz",
|
||||||
MAC2STR(sa), op_freq);
|
MAC2STR(sa), op_freq);
|
||||||
if (s) {
|
if (s) {
|
||||||
|
int go = s->mode == WPAS_MODE_P2P_GO;
|
||||||
wpas_p2p_group_add_persistent(
|
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) {
|
} else if (bssid) {
|
||||||
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
|
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
|
||||||
wpa_s->p2p_wps_method, 0);
|
wpa_s->p2p_wps_method, 0);
|
||||||
|
|
Loading…
Reference in a new issue