diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index aa1f29187..21d3c7ee0 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1550,8 +1550,15 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) } } + p2p_channels_dump(p2p, "own channels", &p2p->channels); + p2p_channels_dump(p2p, "peer channels", &peer->channels); p2p_channels_intersect(&p2p->channels, &peer->channels, &intersection); + if (go) { + p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq); + p2p_channels_dump(p2p, "intersection after no-GO removal", + &intersection); + } freqs = 0; for (i = 0; i < intersection.reg_classes; i++) { struct p2p_reg_class *c = &intersection.reg_class[i]; @@ -2402,6 +2409,7 @@ void p2p_deinit(struct p2p_data *p2p) wpabuf_free(p2p->sd_resp); os_free(p2p->after_scan_tx); p2p_remove_wps_vendor_extensions(p2p); + os_free(p2p->no_go_freq.range); os_free(p2p); } @@ -3933,6 +3941,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, } +int p2p_set_no_go_freq(struct p2p_data *p2p, + const struct wpa_freq_range_list *list) +{ + struct wpa_freq_range *tmp; + + if (list == NULL || list->num == 0) { + os_free(p2p->no_go_freq.range); + p2p->no_go_freq.range = NULL; + p2p->no_go_freq.num = 0; + return 0; + } + + tmp = os_calloc(list->num, sizeof(struct wpa_freq_range)); + if (tmp == NULL) + return -1; + os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range)); + os_free(p2p->no_go_freq.range); + p2p->no_go_freq.range = tmp; + p2p->no_go_freq.num = list->num; + p2p_dbg(p2p, "Updated no GO chan list"); + + return 0; +} + + int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, u8 *iface_addr) { diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 9b6921e55..db7ca9d85 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1648,6 +1648,14 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels, */ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq); +/** + * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation + * @p2p: P2P module context from p2p_init() + * @freq: Channel frequency in MHz + * Returns: 0 if channel not usable for P2P, 1 if usable for P2P + */ +int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq); + /** * p2p_get_pref_freq - Get channel from preferred channel list * @p2p: P2P module context from p2p_init() @@ -1764,6 +1772,15 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, const struct p2p_channel *pref_chan); +/** + * p2p_set_no_go_freq - Set no GO channel ranges + * @p2p: P2P module context from p2p_init() + * @list: Channel ranges or %NULL to remove restriction + * Returns: 0 on success, -1 on failure + */ +int p2p_set_no_go_freq(struct p2p_data *p2p, + const struct wpa_freq_range_list *list); + /** * p2p_in_progress - Check whether a P2P operation is progress * @p2p: P2P module context from p2p_init() diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 9e9d2eea4..1c0aeb000 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -479,6 +479,9 @@ static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, p2p_channels_dump(p2p, "peer channels", &dev->channels); p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection); p2p_channels_dump(p2p, "intersection", &intersection); + p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq); + p2p_channels_dump(p2p, "intersection after no-GO removal", + &intersection); if (intersection.reg_classes == 0 || intersection.reg_class[0].channels == 0) { *status = P2P_SC_FAIL_NO_COMMON_CHANNELS; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 3631abd1e..e5075ae1d 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -316,6 +316,8 @@ struct p2p_data { */ struct p2p_channels channels; + struct wpa_freq_range_list no_go_freq; + enum p2p_pending_action_state { P2P_NO_PENDING_ACTION, P2P_PENDING_GO_NEG_REQUEST, @@ -570,6 +572,8 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel); void p2p_channels_intersect(const struct p2p_channels *a, const struct p2p_channels *b, struct p2p_channels *res); +void p2p_channels_remove_freqs(struct p2p_channels *chan, + const struct wpa_freq_range_list *list); int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class, u8 channel); void p2p_channels_dump(struct p2p_data *p2p, const char *title, diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index 8489b535c..b7bbfcf74 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -204,6 +204,42 @@ void p2p_channels_intersect(const struct p2p_channels *a, } +void p2p_channels_remove_freqs(struct p2p_channels *chan, + const struct wpa_freq_range_list *list) +{ + size_t o, c; + + if (list == NULL) + return; + + o = 0; + while (o < chan->reg_classes) { + struct p2p_reg_class *op = &chan->reg_class[o]; + + c = 0; + while (c < op->channels) { + int freq = p2p_channel_to_freq(op->reg_class, + op->channel[c]); + if (freq > 0 && freq_range_list_includes(list, freq)) { + op->channels--; + os_memmove(&op->channel[c], + &op->channel[c + 1], + op->channels - c); + } else + c++; + } + + if (op->channels == 0) { + chan->reg_classes--; + os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1], + (chan->reg_classes - o) * + sizeof(struct p2p_reg_class)); + } else + o++; + } +} + + /** * p2p_channels_includes - Check whether a channel is included in the list * @channels: List of supported channels @@ -254,6 +290,17 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq) } +int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq) +{ + u8 op_reg_class, op_channel; + if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0) + return 0; + return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, + op_channel) && + !freq_range_list_includes(&p2p->no_go_freq, freq); +} + + unsigned int p2p_get_pref_freq(struct p2p_data *p2p, const struct p2p_channels *channels) { diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 66ee30a3f..d9f2bc268 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1936,6 +1936,7 @@ void wpa_config_free(struct wpa_config *config) os_free(config->p2p_ssid_postfix); os_free(config->pssid); os_free(config->p2p_pref_chan); + os_free(config->p2p_no_go_freq.range); os_free(config->autoscan); os_free(config->freq_list); wpabuf_free(config->wps_nfc_dh_pubkey); @@ -3079,6 +3080,26 @@ fail: wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line); return -1; } + + +static int wpa_config_process_p2p_no_go_freq( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + int ret; + + ret = freq_range_list_parse(&config->p2p_no_go_freq, pos); + if (ret < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line); + return -1; + } + + wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items", + config->p2p_no_go_freq.num); + + return 0; +} + #endif /* CONFIG_P2P */ @@ -3229,6 +3250,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS }, { INT(p2p_group_idle), 0 }, { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN }, + { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN }, { INT(p2p_go_ht40), 0 }, { INT(p2p_disabled), 0 }, { INT(p2p_no_group_iface), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 2e558fdb4..de8ba9e07 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -605,6 +605,7 @@ struct wpa_config { int p2p_intra_bss; unsigned int num_p2p_pref_chan; struct p2p_channel *p2p_pref_chan; + struct wpa_freq_range_list p2p_no_go_freq; int p2p_ignore_shared_freq; struct wpabuf *wps_vendor_ext_m1; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index b8fff70cc..75b302263 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -941,6 +941,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) } fprintf(f, "\n"); } + if (config->p2p_no_go_freq.num) { + char *val = freq_range_list_str(&config->p2p_no_go_freq); + if (val) { + fprintf(f, "p2p_no_go_freq=%s\n", val); + os_free(val); + } + } if (config->p2p_go_ht40) fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40); if (config->p2p_disabled) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 817232b30..8e7a45b26 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3386,6 +3386,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) global->p2p, wpa_s->conf->wps_vendor_ext[i]); } + p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq); + return 0; } @@ -4313,8 +4315,8 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz " "band"); if (wpa_s->best_24_freq > 0 && - p2p_supported_freq(wpa_s->global->p2p, - wpa_s->best_24_freq)) { + p2p_supported_freq_go(wpa_s->global->p2p, + wpa_s->best_24_freq)) { freq = wpa_s->best_24_freq; wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band " "channel: %d MHz", freq); @@ -4330,7 +4332,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz " "band"); if (wpa_s->best_5_freq > 0 && - p2p_supported_freq(wpa_s->global->p2p, + p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_5_freq)) { freq = wpa_s->best_5_freq; wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band " @@ -4338,7 +4340,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) } else { os_get_random((u8 *) &r, sizeof(r)); freq = 5180 + (r % 4) * 20; - if (!p2p_supported_freq(wpa_s->global->p2p, freq)) { + if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: Could not select " "5 GHz channel for P2P group"); return -1; @@ -4348,7 +4350,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) } } - if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) { + if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO " "(%u MHz) is not supported for P2P uses", freq); @@ -4401,24 +4403,24 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, "frequency %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_overall_freq > 0 && - p2p_supported_freq(wpa_s->global->p2p, - wpa_s->best_overall_freq) && + p2p_supported_freq_go(wpa_s->global->p2p, + wpa_s->best_overall_freq) && freq_included(channels, wpa_s->best_overall_freq)) { params->freq = wpa_s->best_overall_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall " "channel %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_24_freq > 0 && - p2p_supported_freq(wpa_s->global->p2p, - wpa_s->best_24_freq) && + p2p_supported_freq_go(wpa_s->global->p2p, + wpa_s->best_24_freq) && freq_included(channels, wpa_s->best_24_freq)) { params->freq = wpa_s->best_24_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz " "channel %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_5_freq > 0 && - p2p_supported_freq(wpa_s->global->p2p, - wpa_s->best_5_freq) && + p2p_supported_freq_go(wpa_s->global->p2p, + wpa_s->best_5_freq) && freq_included(channels, wpa_s->best_5_freq)) { params->freq = wpa_s->best_5_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz " @@ -4564,7 +4566,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, NULL)) return -1; if (params.freq && - !p2p_supported_freq(wpa_s->global->p2p, params.freq)) { + !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) { wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO " "(%u MHz) is not supported for P2P uses", params.freq); @@ -5605,6 +5607,11 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s) wpa_printf(MSG_ERROR, "P2P: Preferred channel list " "update failed"); } + + if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) { + wpa_printf(MSG_ERROR, "P2P: No GO channel list " + "update failed"); + } } } diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index d79381916..9268446fa 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -615,6 +615,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan", + "p2p_no_go_freq", "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface", "p2p_ignore_shared_freq", "country", "bss_max_count", "bss_expiration_age", "bss_expiration_scan_count",