diff options
author | Ahmad Kholaif <akholaif@qca.qualcomm.com> | 2015-07-24 08:23:24 +0000 |
---|---|---|
committer | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-04-01 16:47:41 +0530 |
commit | e71f6421063579aa56e3d04efaaec820538df88b (patch) | |
tree | 724e4f99477b084592673efdb46de5bdd4474653 /src | |
parent | d8dfb429d1b8e8428926daf83d066d29645a6a1c (diff) | |
download | android_external_wpa_supplicant_8-e71f6421063579aa56e3d04efaaec820538df88b.tar.gz android_external_wpa_supplicant_8-e71f6421063579aa56e3d04efaaec820538df88b.tar.bz2 android_external_wpa_supplicant_8-e71f6421063579aa56e3d04efaaec820538df88b.zip |
P2P: Process preferred frequency list as part of GO Neg Req/Resp
When processing a GO Negotiation Request and Response, if local driver
supports the preferred channel list extension, then:
- Check if peer's preference for operating channel is already included
in our preferred channel list and if so, take the oper_channel as is.
- If peer's preference for operating channel is not in local device's
preferred channel list and peer device has provided its preferred
frequency list in the GO Negotiation Request/Response, then find a
channel that is common for both preferred channel lists and use it
for oper_channel.
- If peer's preference for operating channel is not in local device's
preferred channel list and peer device doesn't use preferred channel
list extension, i.e., no preferred channel list in GO Negotiation
Request/Response, then look for a channel that is common for local
device's preferred channel list and peer's list of supported channels
and use it for oper_channel.
- In case no common channel is found, use the peer's preference for
oper_channel as is.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Git-commit: 6cc364946cd30681cd1e3a2ca061173be3227d11
Git-repo: git://w1.fi/srv/git/hostap.git
Change-Id: I2ba4cddfd03c741ee82ecbefe64617080e720d3e
CRs-fixed: 887890
Diffstat (limited to 'src')
-rw-r--r-- | src/p2p/p2p_go_neg.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 4752b294..ab225111 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -545,6 +545,195 @@ int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, } +static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, + struct p2p_device *dev, + struct p2p_message *msg, + unsigned freq_list[], unsigned int size) +{ + u8 op_class, op_channel; + unsigned int oper_freq, i, j; + int found = 0; + + p2p_dbg(p2p, + "Peer didn't provide a preferred frequency list, see if any of our preferred channels are supported by peer device"); + + /* + * Search for a common channel in our preferred frequency list which is + * also supported by the peer device. + */ + for (i = 0; i < size && !found; i++) { + /* + * Make sure that the common frequency is: + * 1. Supported by peer + * 2. Allowed for P2P use. + */ + oper_freq = freq_list[i]; + if (p2p_freq_to_channel(oper_freq, &op_class, + &op_channel) < 0) { + p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq); + continue; + } + if (!p2p_channels_includes(&p2p->cfg->channels, + op_class, op_channel) && + (go || !p2p_channels_includes(&p2p->cfg->cli_channels, + op_class, op_channel))) { + p2p_dbg(p2p, + "Freq %u MHz (oper_class %u channel %u) not allowed for P2P", + oper_freq, op_class, op_channel); + break; + } + for (j = 0; j < msg->channel_list_len; j++) { + + if (op_channel != msg->channel_list[j]) + continue; + + p2p->op_reg_class = op_class; + p2p->op_channel = op_channel; + os_memcpy(&p2p->channels, &p2p->cfg->channels, + sizeof(struct p2p_channels)); + found = 1; + break; + } + } + + if (found) { + p2p_dbg(p2p, + "Freq %d MHz is a preferred channel and is also supported by peer, use it as the operating channel", + oper_freq); + } else { + p2p_dbg(p2p, + "None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel", + dev->oper_freq); + } +} + + +static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, + struct p2p_device *dev, + struct p2p_message *msg, + unsigned freq_list[], unsigned int size) +{ + u8 op_class, op_channel; + unsigned int oper_freq, i, j; + int found = 0; + + /* + * Peer device supports a Preferred Frequency List. + * Search for a common channel in the preferred frequency lists + * of both peer and local devices. + */ + for (i = 0; i < size && !found; i++) { + for (j = 2; j < (msg->pref_freq_list_len / 2); j++) { + oper_freq = p2p_channel_to_freq( + msg->pref_freq_list[2 * j], + msg->pref_freq_list[2 * j + 1]); + if (freq_list[i] != oper_freq) + continue; + + /* + * Make sure that the found frequency is: + * 1. Supported + * 2. Allowed for P2P use. + */ + if (p2p_freq_to_channel(oper_freq, &op_class, + &op_channel) < 0) { + p2p_dbg(p2p, "Unsupported frequency %u MHz", + oper_freq); + continue; + } + + if (!p2p_channels_includes(&p2p->cfg->channels, + op_class, op_channel) && + (go || + !p2p_channels_includes(&p2p->cfg->cli_channels, + op_class, op_channel))) { + p2p_dbg(p2p, + "Freq %u MHz (oper_class %u channel %u) not allowed for P2P", + oper_freq, op_class, op_channel); + break; + } + p2p->op_reg_class = op_class; + p2p->op_channel = op_channel; + os_memcpy(&p2p->channels, &p2p->cfg->channels, + sizeof(struct p2p_channels)); + found = 1; + break; + } + } + + if (found) { + p2p_dbg(p2p, + "Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel", + oper_freq); + } else { + p2p_dbg(p2p, + "No common preferred channels found! Use: %d MHz for oper_channel", + dev->oper_freq); + } +} + + +static void p2p_check_pref_chan(struct p2p_data *p2p, int go, + struct p2p_device *dev, struct p2p_message *msg) +{ + unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size; + unsigned int i; + u8 op_class, op_channel; + + /* + * Use the preferred channel list from the driver only if there is no + * forced_freq, e.g., P2P_CONNECT freq=..., and no preferred operating + * channel hardcoded in the configuration file. + */ + if (!p2p->cfg->get_pref_freq_list || p2p->cfg->num_pref_chan || + (dev->flags & P2P_DEV_FORCE_FREQ) || p2p->cfg->cfg_op_channel) + return; + + /* Obtain our preferred frequency list from driver based on P2P role. */ + size = P2P_MAX_PREF_CHANNELS; + if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size, + freq_list)) + return; + + /* + * Check if peer's preference of operating channel is in + * our preferred channel list. + */ + for (i = 0; i < size; i++) { + if (freq_list[i] == (unsigned int) dev->oper_freq) + break; + } + if (i != size) { + /* Peer operating channel preference matches our preference */ + if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) < + 0) { + p2p_dbg(p2p, + "Peer operating channel preference is unsupported frequency %u MHz", + freq_list[i]); + } else { + p2p->op_reg_class = op_class; + p2p->op_channel = op_channel; + os_memcpy(&p2p->channels, &p2p->cfg->channels, + sizeof(struct p2p_channels)); + return; + } + } + + p2p_dbg(p2p, + "Peer operating channel preference: %d MHz is not in our preferred channel list", + dev->oper_freq); + + /* + Check if peer's preferred channel list is + * _not_ included in the GO Negotiation Request. + */ + if (msg->pref_freq_list_len == 0) + p2p_check_pref_chan_no_recv(p2p, go, dev, msg, freq_list, size); + else + p2p_check_pref_chan_recv(p2p, go, dev, msg, freq_list, size); +} + + void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { @@ -802,6 +991,12 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Peer operating channel preference: %d MHz", dev->oper_freq); + /* + * Use the driver preferred frequency list extension if + * supported. + */ + p2p_check_pref_chan(p2p, go, dev, &msg); + if (msg.config_timeout) { dev->go_timeout = msg.config_timeout[0]; dev->client_timeout = msg.config_timeout[1]; @@ -1153,6 +1348,13 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, if (go && p2p_go_select_channel(p2p, dev, &status) < 0) goto fail; + /* + * Use the driver preferred frequency list extension if local device is + * GO. + */ + if (go) + p2p_check_pref_chan(p2p, go, dev, &msg); + p2p_set_state(p2p, P2P_GO_NEG); p2p_clear_timeout(p2p); |