Patchwork [07/15] supplicant: Allow user-defined defaults for Interworking network blocks.

login
register
mail settings
Submitter Ben Greear
Date March 6, 2014, 12:19 a.m.
Message ID <1394065200-20377-7-git-send-email-greearb@candelatech.com>
Download mbox | patch
Permalink /patch/327244/
State Rejected
Headers show

Comments

Ben Greear - March 6, 2014, 12:19 a.m.
From: Ben Greear <greearb@candelatech.com>

This way users can still configure the HT over-rides and some other
constraints that Interworking has no interest or ability to configure.

Example config file (to disable HT-40 on an Interworking/HS20 interface):

ctrl_interface=/var/run/wpa_supplicant
fast_reauth=1

interworking=1
auto_interworking=1
access_network_type=0

hs20=1

bss_max_count=2000
network={
    interworking_defaults=1
    disable_ht=0
    disable_ht40=1
    disable_sgi=0
    ht_mcs=""
    disable_max_amsdu=-1
    ampdu_factor=-1
    ampdu_density=-1

}

cred={
    username="client2"
    password="lanforge"
    ca_cert="/home/lanforge/ca.pem"
    private_key="/home/lanforge/client.p12"
    private_key_passwd="lanforge"
    realm="lanforge.org"
    domain="lanforge.org"
    eap=TLS

}

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 src/utils/common.c                 |    3 +
 wpa_supplicant/config.c            |   73 ++++++++++++++++++++++++++++++++++++
 wpa_supplicant/config.h            |    1 +
 wpa_supplicant/config_ssid.h       |    7 +++
 wpa_supplicant/interworking.c      |    3 +
 wpa_supplicant/scan.h              |    2 +
 wpa_supplicant/wpa_supplicant.conf |   10 +++++
 7 files changed, 99 insertions(+), 0 deletions(-)
Ben Greear - May 8, 2014, 7:21 p.m.
On 03/05/2014 04:19 PM, greearb@candelatech.com wrote:
> From: Ben Greear <greearb@candelatech.com>
> 
> This way users can still configure the HT over-rides and some other
> constraints that Interworking has no interest or ability to configure.

Jouni:  Would you re-consider this patch?

This one, and a smaller additional patch fixes wpa_supplicant
so that it can do 802.11r and interworking at the same time.

This was just tested with a big client of mine, and they said
there are no other phones or clients around that can do this.

If these patches can get upstream, then that could change...

Thanks,
Ben



> 
> Example config file (to disable HT-40 on an Interworking/HS20 interface):
> 
> ctrl_interface=/var/run/wpa_supplicant
> fast_reauth=1
> 
> interworking=1
> auto_interworking=1
> access_network_type=0
> 
> hs20=1
> 
> bss_max_count=2000
> network={
>     interworking_defaults=1
>     disable_ht=0
>     disable_ht40=1
>     disable_sgi=0
>     ht_mcs=""
>     disable_max_amsdu=-1
>     ampdu_factor=-1
>     ampdu_density=-1
> 
> }
> 
> cred={
>     username="client2"
>     password="lanforge"
>     ca_cert="/home/lanforge/ca.pem"
>     private_key="/home/lanforge/client.p12"
>     private_key_passwd="lanforge"
>     realm="lanforge.org"
>     domain="lanforge.org"
>     eap=TLS
> 
> }
> 
> Signed-off-by: Ben Greear <greearb@candelatech.com>
> ---
>  src/utils/common.c                 |    3 +
>  wpa_supplicant/config.c            |   73 ++++++++++++++++++++++++++++++++++++
>  wpa_supplicant/config.h            |    1 +
>  wpa_supplicant/config_ssid.h       |    7 +++
>  wpa_supplicant/interworking.c      |    3 +
>  wpa_supplicant/scan.h              |    2 +
>  wpa_supplicant/wpa_supplicant.conf |   10 +++++
>  7 files changed, 99 insertions(+), 0 deletions(-)
> 
> diff --git a/src/utils/common.c b/src/utils/common.c
> index 39751d4..54ab60f 100644
> --- a/src/utils/common.c
> +++ b/src/utils/common.c
> @@ -754,6 +754,9 @@ void int_array_concat(int **res, const int *a)
>  	reslen = int_array_len(*res);
>  	alen = int_array_len(a);
>  
> +	if (alen == 0)
> +		return; /* nothing to concat */
> +
>  	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
>  	if (n == NULL) {
>  		os_free(*res);
> diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
> index 1df9213..dfc9bae 100644
> --- a/wpa_supplicant/config.c
> +++ b/wpa_supplicant/config.c
> @@ -1730,6 +1730,7 @@ static const struct parse_data ssid_fields[] = {
>  	{ INT(ap_max_inactivity) },
>  	{ INT(dtim_period) },
>  	{ INT(beacon_int) },
> +	{ INT_RANGE(interworking_defaults, 0, 1) },
>  };
>  
>  #undef OFFSET
> @@ -2138,6 +2139,77 @@ int wpa_config_remove_network(struct wpa_config *config, int id)
>  
>  
>  /**
> + * wpa_set_user_network_defalts - Configure ssid with network defaults.
> + * @config: Configuration data from wpa_config_read()
> + * @ssid: The SSID to configure.
> + * Looks for first wpa_ssid that has interworking_defaults=1.  If found,
> + * select values are applied to the ssid.  In this way one may configure
> + * options not explicitly dealt with by interworking, such as
> + *   disable_ht=0
> + *   disable_ht40=0
> + *   etc.
> + * If no ssid is found, no action is taken.
> + */
> +void wpa_config_set_user_network_defaults(struct wpa_config *config, struct wpa_ssid *ssid)
> +{
> +	struct wpa_ssid *s = config->ssid;
> +	int i;
> +
> +	while (s) {
> +		if (s->interworking_defaults) {
> +			os_free(ssid->scan_freq);
> +			ssid->scan_freq = NULL;
> +			int_array_concat(&ssid->scan_freq, s->scan_freq);
> +
> +			os_free(ssid->freq_list);
> +			ssid->freq_list = NULL;
> +			int_array_concat(&ssid->freq_list, s->freq_list);
> +
> +			ssid->bg_scan_period = s->bg_scan_period;
> +#ifdef CONFIG_HT_OVERRIDES
> +			ssid->disable_ht = s->disable_ht;
> +			ssid->disable_ht40 = s->disable_ht40;
> +			ssid->disable_sgi = s->disable_sgi;
> +			ssid->disable_max_amsdu = s->disable_max_amsdu;
> +			ssid->ampdu_factor = s->ampdu_factor;
> +			ssid->ampdu_density = s->ampdu_density;
> +
> +			os_free(ssid->ht_mcs);
> +			ssid->ht_mcs = NULL;
> +			if (s->ht_mcs) {
> +				ssid->ht_mcs = strdup(s->ht_mcs);
> +			}
> +#endif
> +#ifdef CONFIG_VHT_OVERRIDES
> +			ssid->disable_vht = s->disable_vht;
> +			ssid->vht_capa = s->vht_capa;
> +			ssid->vht_capa_mask = s->vht_capa_mask;
> +			ssid->vht_rx_mcs_nss_1 = s->vht_rx_mcs_nss_1;
> +			ssid->vht_rx_mcs_nss_2 = s->vht_rx_mcs_nss_2;
> +			ssid->vht_rx_mcs_nss_3 = s->vht_rx_mcs_nss_3;
> +			ssid->vht_rx_mcs_nss_4 = s->vht_rx_mcs_nss_4;
> +			ssid->vht_rx_mcs_nss_5 = s->vht_rx_mcs_nss_5;
> +			ssid->vht_rx_mcs_nss_6 = s->vht_rx_mcs_nss_6;
> +			ssid->vht_rx_mcs_nss_7 = s->vht_rx_mcs_nss_7;
> +			ssid->vht_rx_mcs_nss_8 = s->vht_rx_mcs_nss_8;
> +			ssid->vht_tx_mcs_nss_1 = s->vht_tx_mcs_nss_1;
> +			ssid->vht_tx_mcs_nss_2 = s->vht_tx_mcs_nss_2;
> +			ssid->vht_tx_mcs_nss_3 = s->vht_tx_mcs_nss_3;
> +			ssid->vht_tx_mcs_nss_4 = s->vht_tx_mcs_nss_4;
> +			ssid->vht_tx_mcs_nss_5 = s->vht_tx_mcs_nss_5;
> +			ssid->vht_tx_mcs_nss_6 = s->vht_tx_mcs_nss_6;
> +			ssid->vht_tx_mcs_nss_7 = s->vht_tx_mcs_nss_7;
> +			ssid->vht_tx_mcs_nss_8 = s->vht_tx_mcs_nss_8;
> +#endif /* CONFIG_VHT_OVERRIDES */
> +			return;
> +		}
> +		else {
> +			ssid = ssid->next;
> +		}
> +	}
> +} /* wpa_set_user_network_defaults */
> +
> +/**
>   * wpa_config_set_network_defaults - Set network default values
>   * @ssid: Pointer to network configuration data
>   */
> @@ -2183,6 +2255,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
>  #ifdef CONFIG_IEEE80211W
>  	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
>  #endif /* CONFIG_IEEE80211W */
> +	ssid->interworking_defaults = DEFAULT_INTERWORKING_DEFAULTS;
>  }
>  
>  
> diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
> index 690bfde..ffb8a5f 100644
> --- a/wpa_supplicant/config.h
> +++ b/wpa_supplicant/config.h
> @@ -1039,6 +1039,7 @@ struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
>  struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
>  int wpa_config_remove_network(struct wpa_config *config, int id);
>  void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
> +void wpa_config_set_user_network_defaults(struct wpa_config *config, struct wpa_ssid *ssid);
>  int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
>  		   int line);
>  int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
> diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
> index d515030..4aaf0f1 100644
> --- a/wpa_supplicant/config_ssid.h
> +++ b/wpa_supplicant/config_ssid.h
> @@ -33,6 +33,7 @@
>  #define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
>  #define DEFAULT_AMPDU_FACTOR -1 /* no change */
>  #define DEFAULT_AMPDU_DENSITY -1 /* no change */
> +#define DEFAULT_INTERWORKING_DEFAULTS 0
>  
>  struct psk_list_entry {
>  	struct dl_list list;
> @@ -492,6 +493,12 @@ struct wpa_ssid {
>  	int temporary;
>  
>  	/**
> +	 * interworking_defaults - Whether this network block should be used for
> +	 *    network defaults when creating temporary interworking network blocks.
> +	 */
> +	int interworking_defaults;
> +
> +	/**
>  	 * export_keys - Whether keys may be exported
>  	 *
>  	 * This attribute will be set when keys are determined through
> diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
> index def8f1a..025dcf5 100644
> --- a/wpa_supplicant/interworking.c
> +++ b/wpa_supplicant/interworking.c
> @@ -916,6 +916,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
>  
>  	wpas_notify_network_added(wpa_s, ssid);
>  	wpa_config_set_network_defaults(ssid);
> +	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
>  	ssid->priority = cred->priority;
>  	ssid->temporary = 1;
>  	ssid->ssid = os_zalloc(bss->ssid_len + 1);
> @@ -1451,6 +1452,7 @@ static int interworking_connect_roaming_consortium(
>  	ssid->parent_cred = cred;
>  	wpas_notify_network_added(wpa_s, ssid);
>  	wpa_config_set_network_defaults(ssid);
> +	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
>  	ssid->priority = cred->priority;
>  	ssid->temporary = 1;
>  	ssid->ssid = os_zalloc(bss->ssid_len + 1);
> @@ -1649,6 +1651,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
>  	ssid->parent_cred = cred;
>  	wpas_notify_network_added(wpa_s, ssid);
>  	wpa_config_set_network_defaults(ssid);
> +	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
>  	ssid->priority = cred->priority;
>  	ssid->temporary = 1;
>  	ssid->ssid = os_zalloc(bss->ssid_len + 1);
> diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
> index 59a1cff..052ef21 100644
> --- a/wpa_supplicant/scan.h
> +++ b/wpa_supplicant/scan.h
> @@ -48,4 +48,6 @@ struct wpa_driver_scan_params *
>  wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
>  void wpa_scan_free_params(struct wpa_driver_scan_params *params);
>  
> +void int_array_concat(int **res, const int *a);
> +
>  #endif /* SCAN_H */
> diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
> index 03c6f5f..6cea0ac 100644
> --- a/wpa_supplicant/wpa_supplicant.conf
> +++ b/wpa_supplicant/wpa_supplicant.conf
> @@ -935,6 +935,16 @@ fast_reauth=1
>  # Beacon interval (default: 100 TU)
>  #beacon_int=100
>  
> +# interworking_defaults:  Should this network block's values be used as
> +#   defaults for automatically-created interworking network blocks?
> +#   Not all values will be propagated, but the HT and VHT overrides,
> +#   and a few other values will be.  This will only be used if
> +#   Interworking is active.  Only the first interworking_defaults=1
> +#   network block will be used, so users should only set this value
> +#   in a single network block.
> +# 0 = Not used (default)
> +# 1 = Use this network block's values.
> +
>  # disable_ht: Whether HT (802.11n) should be disabled.
>  # 0 = HT enabled (if AP supports it)
>  # 1 = HT disabled
>
Jouni Malinen - Jan. 31, 2015, 11:02 p.m.
On Thu, May 08, 2014 at 12:21:52PM -0700, Ben Greear wrote:
> On 03/05/2014 04:19 PM, greearb@candelatech.com wrote:
> > This way users can still configure the HT over-rides and some other
> > constraints that Interworking has no interest or ability to configure.
> 
> Jouni:  Would you re-consider this patch?
> 
> This one, and a smaller additional patch fixes wpa_supplicant
> so that it can do 802.11r and interworking at the same time.

I don't think this type of extension of network blocks to yet another
new not-really-a-network-profile use case is the cleanest way of doing
this. FT support should certainly not depend on this (and well, it
doesn't, i.e., FT for Interworking case was enabled automatically based
on driver capabilities).

> > network={
> >     interworking_defaults=1
> >     disable_ht=0
> >     disable_ht40=1
> >     disable_sgi=0
> >     ht_mcs=""
> >     disable_max_amsdu=-1
> >     ampdu_factor=-1
> >     ampdu_density=-1
> > }

None of those parameters seem to make much sense for me apart from some
very special testing purposes. Interworking networks are supposed to
work automatically and without requiring this type of overrides, i.e.,
driver capabilities are supposed to be enabled automatically. I cannot
really think of a real use apart from testing something and that does
not seem like a sufficient justification to add the extra complexity.
Ben Greear - Jan. 31, 2015, 11:17 p.m.
On 01/31/2015 03:02 PM, Jouni Malinen wrote:
> On Thu, May 08, 2014 at 12:21:52PM -0700, Ben Greear wrote:
>> On 03/05/2014 04:19 PM, greearb@candelatech.com wrote:
>>> This way users can still configure the HT over-rides and some other
>>> constraints that Interworking has no interest or ability to configure.
>>
>> Jouni:  Would you re-consider this patch?
>>
>> This one, and a smaller additional patch fixes wpa_supplicant
>> so that it can do 802.11r and interworking at the same time.
>
> I don't think this type of extension of network blocks to yet another
> new not-really-a-network-profile use case is the cleanest way of doing
> this. FT support should certainly not depend on this (and well, it
> doesn't, i.e., FT for Interworking case was enabled automatically based
> on driver capabilities).

I honestly don't even remember why I had this comment about FT and interworking,
it was over a year ago that I originally worked on this...

>>> network={
>>>      interworking_defaults=1
>>>      disable_ht=0
>>>      disable_ht40=1
>>>      disable_sgi=0
>>>      ht_mcs=""
>>>      disable_max_amsdu=-1
>>>      ampdu_factor=-1
>>>      ampdu_density=-1
>>> }
>
> None of those parameters seem to make much sense for me apart from some
> very special testing purposes. Interworking networks are supposed to
> work automatically and without requiring this type of overrides, i.e.,
> driver capabilities are supposed to be enabled automatically. I cannot
> really think of a real use apart from testing something and that does
> not seem like a sufficient justification to add the extra complexity.

It is at least mostly for testing.  I guess there might be cases where someone
would work around bugs or poor performance in their driver or AP by specifying
lower rates (ie, ht_mcs) or force the station to work on HT20 instead of HT40.

That said, testing is interesting too..lord knows a lot of APs could use the extra
testing!

Thanks,
Ben
Jouni Malinen - Jan. 31, 2015, 11:38 p.m.
On Sat, Jan 31, 2015 at 03:17:57PM -0800, Ben Greear wrote:
> It is at least mostly for testing.  I guess there might be cases where someone
> would work around bugs or poor performance in their driver or AP by specifying
> lower rates (ie, ht_mcs) or force the station to work on HT20 instead of HT40.

If there is a broken driver, that driver should be fixed.. This specific
case does not look very helpful for avoiding issues with a specific AP
since Interworking networks are generated for any AP.

> That said, testing is interesting too..lord knows a lot of APs could use the extra
> testing!

No issues with testing in general, but even for that case, it is a bit
difficult to see why HT or VHT would need to be disabled in this way in
wpa_supplicant for Interworking network blocks. It would seem to make
more sense to me to have a global parameter for disabling HT/VHT (or
some subset of those).
Ben Greear - Jan. 31, 2015, 11:49 p.m.
On 01/31/2015 03:38 PM, Jouni Malinen wrote:
> On Sat, Jan 31, 2015 at 03:17:57PM -0800, Ben Greear wrote:
>> It is at least mostly for testing.  I guess there might be cases where someone
>> would work around bugs or poor performance in their driver or AP by specifying
>> lower rates (ie, ht_mcs) or force the station to work on HT20 instead of HT40.
>
> If there is a broken driver, that driver should be fixed.. This specific
> case does not look very helpful for avoiding issues with a specific AP
> since Interworking networks are generated for any AP.
>
>> That said, testing is interesting too..lord knows a lot of APs could use the extra
>> testing!
>
> No issues with testing in general, but even for that case, it is a bit
> difficult to see why HT or VHT would need to be disabled in this way in
> wpa_supplicant for Interworking network blocks. It would seem to make
> more sense to me to have a global parameter for disabling HT/VHT (or
> some subset of those).

I use many virtual interfaces per supplicant, and all of those settings (disable ht, etc) are
already implemented on a per-network-block case.  I just wanted to re-use that logic for
interworking so that I could easily fake a 2x2 MIMO interworking client (or /a or whatever) when
I have an /a/b/g/n 3x3 NIC acting as stations...

If I put this in a global parameter block, then I'd have to basically re-implement
all of the old ways of implementing these options?

Or, am I missing something and it isn't that hard to re-use the existing logic?

Thanks,
Ben


>
>

Patch

diff --git a/src/utils/common.c b/src/utils/common.c
index 39751d4..54ab60f 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -754,6 +754,9 @@  void int_array_concat(int **res, const int *a)
 	reslen = int_array_len(*res);
 	alen = int_array_len(a);
 
+	if (alen == 0)
+		return; /* nothing to concat */
+
 	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
 	if (n == NULL) {
 		os_free(*res);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 1df9213..dfc9bae 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1730,6 +1730,7 @@  static const struct parse_data ssid_fields[] = {
 	{ INT(ap_max_inactivity) },
 	{ INT(dtim_period) },
 	{ INT(beacon_int) },
+	{ INT_RANGE(interworking_defaults, 0, 1) },
 };
 
 #undef OFFSET
@@ -2138,6 +2139,77 @@  int wpa_config_remove_network(struct wpa_config *config, int id)
 
 
 /**
+ * wpa_set_user_network_defalts - Configure ssid with network defaults.
+ * @config: Configuration data from wpa_config_read()
+ * @ssid: The SSID to configure.
+ * Looks for first wpa_ssid that has interworking_defaults=1.  If found,
+ * select values are applied to the ssid.  In this way one may configure
+ * options not explicitly dealt with by interworking, such as
+ *   disable_ht=0
+ *   disable_ht40=0
+ *   etc.
+ * If no ssid is found, no action is taken.
+ */
+void wpa_config_set_user_network_defaults(struct wpa_config *config, struct wpa_ssid *ssid)
+{
+	struct wpa_ssid *s = config->ssid;
+	int i;
+
+	while (s) {
+		if (s->interworking_defaults) {
+			os_free(ssid->scan_freq);
+			ssid->scan_freq = NULL;
+			int_array_concat(&ssid->scan_freq, s->scan_freq);
+
+			os_free(ssid->freq_list);
+			ssid->freq_list = NULL;
+			int_array_concat(&ssid->freq_list, s->freq_list);
+
+			ssid->bg_scan_period = s->bg_scan_period;
+#ifdef CONFIG_HT_OVERRIDES
+			ssid->disable_ht = s->disable_ht;
+			ssid->disable_ht40 = s->disable_ht40;
+			ssid->disable_sgi = s->disable_sgi;
+			ssid->disable_max_amsdu = s->disable_max_amsdu;
+			ssid->ampdu_factor = s->ampdu_factor;
+			ssid->ampdu_density = s->ampdu_density;
+
+			os_free(ssid->ht_mcs);
+			ssid->ht_mcs = NULL;
+			if (s->ht_mcs) {
+				ssid->ht_mcs = strdup(s->ht_mcs);
+			}
+#endif
+#ifdef CONFIG_VHT_OVERRIDES
+			ssid->disable_vht = s->disable_vht;
+			ssid->vht_capa = s->vht_capa;
+			ssid->vht_capa_mask = s->vht_capa_mask;
+			ssid->vht_rx_mcs_nss_1 = s->vht_rx_mcs_nss_1;
+			ssid->vht_rx_mcs_nss_2 = s->vht_rx_mcs_nss_2;
+			ssid->vht_rx_mcs_nss_3 = s->vht_rx_mcs_nss_3;
+			ssid->vht_rx_mcs_nss_4 = s->vht_rx_mcs_nss_4;
+			ssid->vht_rx_mcs_nss_5 = s->vht_rx_mcs_nss_5;
+			ssid->vht_rx_mcs_nss_6 = s->vht_rx_mcs_nss_6;
+			ssid->vht_rx_mcs_nss_7 = s->vht_rx_mcs_nss_7;
+			ssid->vht_rx_mcs_nss_8 = s->vht_rx_mcs_nss_8;
+			ssid->vht_tx_mcs_nss_1 = s->vht_tx_mcs_nss_1;
+			ssid->vht_tx_mcs_nss_2 = s->vht_tx_mcs_nss_2;
+			ssid->vht_tx_mcs_nss_3 = s->vht_tx_mcs_nss_3;
+			ssid->vht_tx_mcs_nss_4 = s->vht_tx_mcs_nss_4;
+			ssid->vht_tx_mcs_nss_5 = s->vht_tx_mcs_nss_5;
+			ssid->vht_tx_mcs_nss_6 = s->vht_tx_mcs_nss_6;
+			ssid->vht_tx_mcs_nss_7 = s->vht_tx_mcs_nss_7;
+			ssid->vht_tx_mcs_nss_8 = s->vht_tx_mcs_nss_8;
+#endif /* CONFIG_VHT_OVERRIDES */
+			return;
+		}
+		else {
+			ssid = ssid->next;
+		}
+	}
+} /* wpa_set_user_network_defaults */
+
+/**
  * wpa_config_set_network_defaults - Set network default values
  * @ssid: Pointer to network configuration data
  */
@@ -2183,6 +2255,7 @@  void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
 #ifdef CONFIG_IEEE80211W
 	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
 #endif /* CONFIG_IEEE80211W */
+	ssid->interworking_defaults = DEFAULT_INTERWORKING_DEFAULTS;
 }
 
 
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 690bfde..ffb8a5f 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1039,6 +1039,7 @@  struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
 struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
 int wpa_config_remove_network(struct wpa_config *config, int id);
 void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
+void wpa_config_set_user_network_defaults(struct wpa_config *config, struct wpa_ssid *ssid);
 int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
 		   int line);
 int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index d515030..4aaf0f1 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -33,6 +33,7 @@ 
 #define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
 #define DEFAULT_AMPDU_FACTOR -1 /* no change */
 #define DEFAULT_AMPDU_DENSITY -1 /* no change */
+#define DEFAULT_INTERWORKING_DEFAULTS 0
 
 struct psk_list_entry {
 	struct dl_list list;
@@ -492,6 +493,12 @@  struct wpa_ssid {
 	int temporary;
 
 	/**
+	 * interworking_defaults - Whether this network block should be used for
+	 *    network defaults when creating temporary interworking network blocks.
+	 */
+	int interworking_defaults;
+
+	/**
 	 * export_keys - Whether keys may be exported
 	 *
 	 * This attribute will be set when keys are determined through
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index def8f1a..025dcf5 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -916,6 +916,7 @@  static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
 
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
+	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
 	ssid->ssid = os_zalloc(bss->ssid_len + 1);
@@ -1451,6 +1452,7 @@  static int interworking_connect_roaming_consortium(
 	ssid->parent_cred = cred;
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
+	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
 	ssid->ssid = os_zalloc(bss->ssid_len + 1);
@@ -1649,6 +1651,7 @@  static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
 	ssid->parent_cred = cred;
 	wpas_notify_network_added(wpa_s, ssid);
 	wpa_config_set_network_defaults(ssid);
+	wpa_config_set_user_network_defaults(wpa_s->conf, ssid);
 	ssid->priority = cred->priority;
 	ssid->temporary = 1;
 	ssid->ssid = os_zalloc(bss->ssid_len + 1);
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 59a1cff..052ef21 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -48,4 +48,6 @@  struct wpa_driver_scan_params *
 wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
 void wpa_scan_free_params(struct wpa_driver_scan_params *params);
 
+void int_array_concat(int **res, const int *a);
+
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 03c6f5f..6cea0ac 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -935,6 +935,16 @@  fast_reauth=1
 # Beacon interval (default: 100 TU)
 #beacon_int=100
 
+# interworking_defaults:  Should this network block's values be used as
+#   defaults for automatically-created interworking network blocks?
+#   Not all values will be propagated, but the HT and VHT overrides,
+#   and a few other values will be.  This will only be used if
+#   Interworking is active.  Only the first interworking_defaults=1
+#   network block will be used, so users should only set this value
+#   in a single network block.
+# 0 = Not used (default)
+# 1 = Use this network block's values.
+
 # disable_ht: Whether HT (802.11n) should be disabled.
 # 0 = HT enabled (if AP supports it)
 # 1 = HT disabled