}
}
+ 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];
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);
}
}
+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)
{
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()
* @channels: List of channels
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()
* Returns: 0 if P2P module is idle or 1 if an operation is in progress
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;
*/
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,
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,
}
+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
}
+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)
{
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);
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 */
{ 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 },
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;
}
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)
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;
}
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);
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 "
} 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;
}
}
- 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);
"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 "
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);
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");
+ }
}
}
"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",