Patchwork [15/23] P2P: add support for using indoor channels

login
register
mail settings
Submitter Ilan Peer
Date July 7, 2014, 11:21 a.m.
Message ID <1404732076-32252-16-git-send-email-ilan.peer@intel.com>
Download mbox | patch
Permalink /patch/367518/
State New
Headers show

Comments

Ilan Peer - July 7, 2014, 11:21 a.m.
Generally, indoor channels cannot be used for P2P operation as
currently there is no way to determine that the device is
operating in an indoor environment.

Add a relaxation to allow using indoor channels, iff the peer
device is going to be the GO and in addition it is identified
as a non-mobile/indoor device based on its WPS device category.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
---
 src/p2p/p2p.c                   |   53 ++++++++++++++++++++++++++++++---------
 src/p2p/p2p.h                   |   18 ++++++++++++-
 src/p2p/p2p_utils.c             |    2 ++
 wpa_supplicant/config.c         |    2 ++
 wpa_supplicant/config.h         |    2 ++
 wpa_supplicant/config_file.c    |    3 +++
 wpa_supplicant/p2p_supplicant.c |   46 +++++++++++++++++++++++++--------
 7 files changed, 103 insertions(+), 23 deletions(-)

Patch

diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 8ebd2ef..8b8379b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1144,7 +1144,9 @@  void p2p_stop_find(struct p2p_data *p2p)
 
 static int p2p_prepare_channel_pref(struct p2p_data *p2p,
 				    unsigned int force_freq,
-				    unsigned int pref_freq, int go)
+				    unsigned int pref_freq,
+				    int go,
+				    unsigned int allow_indoor)
 {
 	u8 op_class, op_channel;
 	unsigned int freq = force_freq ? force_freq : pref_freq;
@@ -1156,12 +1158,18 @@  static int p2p_prepare_channel_pref(struct p2p_data *p2p,
 		return -1;
 	}
 
-	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, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
-			freq, op_class, op_channel);
-		return -1;
+	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+		if (go)
+			goto not_allowed;
+
+		if (!p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+					   op_channel)) {
+			if (!allow_indoor ||
+			    !p2p_channels_includes(&p2p->cfg->indoor_channels,
+						   op_class,
+						   op_channel))
+				goto not_allowed;
+		}
 	}
 
 	p2p->op_reg_class = op_class;
@@ -1178,6 +1186,13 @@  static int p2p_prepare_channel_pref(struct p2p_data *p2p,
 	}
 
 	return 0;
+
+not_allowed:
+
+	p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
+		freq, op_class, op_channel);
+	return -1;
+
 }
 
 
@@ -1276,22 +1291,31 @@  static void p2p_prepare_channel_best(struct p2p_data *p2p)
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
 			unsigned int force_freq, unsigned int pref_freq, int go)
 {
+	unsigned int indoor = p2p_is_indoor_device(&dev->info);
+
 	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
 		force_freq, pref_freq, go);
 	if (force_freq || pref_freq) {
-		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
-		    0)
+		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go,
+					     indoor) < 0)
 			return -1;
 	} else {
 		p2p_prepare_channel_best(p2p);
 	}
+
 	p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
 	if (go)
 		p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
-	else if (!force_freq)
+	else if (!force_freq) {
 		p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
 				   &p2p->channels);
-	p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+		if (indoor)
+			p2p_channels_union(&p2p->channels,
+					   &p2p->cfg->indoor_channels,
+					   &p2p->channels);
+	}
+	p2p_channels_dump(p2p, "after go/cli/indoor filter/add",
+			  &p2p->channels);
 
 	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
 		p2p->op_reg_class, p2p->op_channel,
@@ -2429,6 +2453,7 @@  struct p2p_data * p2p_init(const struct p2p_config *cfg)
 	p2p_dbg(p2p, "initialized");
 	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
 	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+	p2p_channels_dump(p2p, "indoor_channels", &p2p->cfg->indoor_channels);
 
 	return p2p;
 }
@@ -4164,7 +4189,8 @@  void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
 
 void p2p_update_channel_list(struct p2p_data *p2p,
 			     const struct p2p_channels *chan,
-			     const struct p2p_channels *cli_chan)
+			     const struct p2p_channels *cli_chan,
+			     const struct p2p_channels *indoor_chan)
 {
 	p2p_dbg(p2p, "Update channel list");
 	os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
@@ -4172,6 +4198,9 @@  void p2p_update_channel_list(struct p2p_data *p2p,
 	os_memcpy(&p2p->cfg->cli_channels, cli_chan,
 		  sizeof(struct p2p_channels));
 	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+	os_memcpy(&p2p->cfg->indoor_channels, indoor_chan,
+		  sizeof(struct p2p_channels));
+	p2p_channels_dump(p2p, "indoor_channels", &p2p->cfg->indoor_channels);
 }
 
 
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 6f35e24..42657d4 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -311,6 +311,21 @@  struct p2p_config {
 	struct p2p_channels cli_channels;
 
 	/**
+	 * indoor_channels - Additional client channels
+	 *
+	 * This list of channels (if any) will be used when advertising local
+	 * channels during GO Negotiation or Invitation for the cases where the
+	 * local end may become the client and the peer is identified as a non
+	 * mobile device.
+	 * This may allow the peer to become a GO on additional channels if it
+	 * supports these options and is a non mobile device.
+	 * The uses cases for these channels are similar to that of the
+	 * cli_channels, with the exception that they can be used only if
+	 * we identified the peer as a non mobile device.
+	 */
+	struct p2p_channels indoor_channels;
+
+	/**
 	 * num_pref_chan - Number of pref_chan entries
 	 */
 	unsigned int num_pref_chan;
@@ -1753,7 +1768,8 @@  unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
 
 void p2p_update_channel_list(struct p2p_data *p2p,
 			     const struct p2p_channels *chan,
-			     const struct p2p_channels *cli_chan);
+			     const struct p2p_channels *cli_chan,
+			     const struct p2p_channels *indoor_chan);
 
 /**
  * p2p_set_best_channels - Update best channel information
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 06fe385..e7f60e8 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -307,6 +307,8 @@  int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
 	return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
 				     op_channel) ||
 		p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+				      op_channel) ||
+		p2p_channels_includes(&p2p->cfg->indoor_channels, op_reg_class,
 				      op_channel);
 }
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index d3bd8df..322342b 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3276,6 +3276,7 @@  struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
 	config->p2p_go_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE;
 	config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
+	config->p2p_add_cli_chan_indoor = DEFAULT_P2P_ADD_CLI_CHAN_INDOOR;
 	config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
 	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
 	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
@@ -3862,6 +3863,7 @@  static const struct global_parse_data global_fields[] = {
 	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
 	{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
 	{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
+	{ INT_RANGE(p2p_add_cli_chan_indoor, 0, 1), 0 },
 	{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
 	{ INT(p2p_go_ht40), 0 },
 	{ INT(p2p_go_vht), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 7316ad4..e2233b4 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -20,6 +20,7 @@ 
 #define DEFAULT_P2P_INTRA_BSS 1
 #define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
 #define DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN 0
+#define DEFAULT_P2P_ADD_CLI_CHAN_INDOOR 0
 #define DEFAULT_BSS_MAX_COUNT 200
 #define DEFAULT_BSS_EXPIRATION_AGE 180
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
@@ -687,6 +688,7 @@  struct wpa_config {
 	struct p2p_channel *p2p_pref_chan;
 	struct wpa_freq_range_list p2p_no_go_freq;
 	int p2p_add_cli_chan;
+	int p2p_add_cli_chan_indoor;
 	int p2p_ignore_shared_freq;
 	int p2p_optimize_listen_chan;
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index b77e9fa..3bc993e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1041,6 +1041,9 @@  static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 	}
 	if (config->p2p_add_cli_chan)
 		fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
+	if (config->p2p_add_cli_chan_indoor != DEFAULT_P2P_ADD_CLI_CHAN_INDOOR)
+		fprintf(f, "p2p_add_cli_chan_indoor=%d\n",
+			config->p2p_add_cli_chan_indoor);
 	if (config->p2p_optimize_listen_chan !=
 	    DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN)
 		fprintf(f, "p2p_optimize_listen_chan=%d\n",
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 30665c9..ca6c84e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3441,11 +3441,13 @@  static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
 
 static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
 				     struct p2p_channels *chan,
-				     struct p2p_channels *cli_chan)
+				     struct p2p_channels *cli_chan,
+				     struct p2p_channels *ind_chan)
 {
 	int i, cla = 0;
 
 	os_memset(cli_chan, 0, sizeof(*cli_chan));
+	os_memset(ind_chan, 0, sizeof(*ind_chan));
 
 	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
 		   "band");
@@ -3739,7 +3741,7 @@  static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 		return NOT_ALLOWED;
 
 	if (res == INDOOR_ONLY || res2 == INDOOR_ONLY)
-		return NOT_ALLOWED;
+		return INDOOR_ONLY;
 
 	if (res == NO_IR || res2 == NO_IR)
 		return NO_IR;
@@ -3749,10 +3751,11 @@  static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 				   struct p2p_channels *chan,
-				   struct p2p_channels *cli_chan)
+				   struct p2p_channels *cli_chan,
+				   struct p2p_channels *ind_chan)
 {
 	struct hostapd_hw_modes *mode;
-	int cla, op, cli_cla;
+	int cla, op, cli_cla, ind_cla;
 	struct wpa_used_freq_data *freqs;
 	unsigned int num = wpa_s->num_multichan_concurrent;
 
@@ -3760,19 +3763,21 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
 			   "of all supported channels; assume dualband "
 			   "support");
-		return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
+		return wpas_p2p_default_channels(wpa_s, chan, cli_chan,
+						 ind_chan);
 	}
 
 	/* Note: the flow can still be handled even if the allocation fails */
 	freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
 	num = get_shared_radio_freqs_data(wpa_s, freqs, num);
 
-	cla = cli_cla = 0;
+	cla = cli_cla = ind_cla = 0;
 
 	for (op = 0; op_class[op].op_class; op++) {
 		struct p2p_oper_class_map *o = &op_class[op];
 		u8 ch;
 		struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
+		struct p2p_reg_class *indoor_reg = NULL;
 
 		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
 		if (mode == NULL)
@@ -3802,6 +3807,19 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 				}
 				cli_reg->channel[cli_reg->channels] = ch;
 				cli_reg->channels++;
+			} else if (res == INDOOR_ONLY &&
+				   wpa_s->conf->p2p_add_cli_chan_indoor) {
+				if (indoor_reg == NULL) {
+					wpa_printf(MSG_DEBUG,
+						   "P2P: Add operating class %u (indoor)",
+						   o->op_class);
+					indoor_reg =
+						&ind_chan->reg_class[ind_cla];
+					ind_cla++;
+					indoor_reg->reg_class = o->op_class;
+				}
+				indoor_reg->channel[indoor_reg->channels] = ch;
+				indoor_reg->channels++;
 			}
 		}
 		if (reg) {
@@ -3812,10 +3830,15 @@  static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 			wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
 				    cli_reg->channel, cli_reg->channels);
 		}
+		if (indoor_reg) {
+			wpa_hexdump(MSG_DEBUG, "P2P: Channels (indoor)",
+				    indoor_reg->channel, indoor_reg->channels);
+		}
 	}
 
 	chan->reg_classes = cla;
 	cli_chan->reg_classes = cli_cla;
+	ind_chan->reg_classes = ind_cla;
 
 	os_free(freqs);
 	return 0;
@@ -4155,7 +4178,8 @@  int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 	} else
 		os_memcpy(p2p.country, "XX\x04", 3);
 
-	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels,
+				    &p2p.indoor_channels)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
 			   "channel list");
 		return -1;
@@ -6775,7 +6799,7 @@  void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
 
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 {
-	struct p2p_channels chan, cli_chan;
+	struct p2p_channels chan, cli_chan, ind_chan;
 	struct wpa_supplicant *ifs;
 
 	if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
@@ -6783,13 +6807,15 @@  void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 
 	os_memset(&chan, 0, sizeof(chan));
 	os_memset(&cli_chan, 0, sizeof(cli_chan));
-	if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
+	os_memset(&ind_chan, 0, sizeof(ind_chan));
+	if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan, &ind_chan)) {
 		wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
 			   "channel list");
 		return;
 	}
 
-	p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
+	p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan,
+				&ind_chan);
 
 	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
 		int freq;