diff mbox

[RFC] rt2x00: specify iface_combinations to allow for multi-bss operation

Message ID 1344029551-17959-1-git-send-email-fercerpav@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Paul Fertser Aug. 3, 2012, 9:32 p.m. UTC
This patch makes all rt2x00 drivers tell mac80211 about possible
interface combinations they support. Only combinations allowed so far
are 4 APs for rt61pci and rt73usb; 8 APs for rt2800{pci,usb}.

The driver-specific code in add_interface is now redudant and thus
removed.

However, real-life testing on RT3052F SoC showed that neither WPA-PSK +
Open nor 2 WPA-PSK APs work properly (though both APs beacon properly).
No other tests were performed.

Signed-off-by: Paul Fertser <fercerpav@gmail.com>
---
 drivers/net/wireless/rt2x00/rt2400pci.c |    2 -
 drivers/net/wireless/rt2x00/rt2500pci.c |    2 -
 drivers/net/wireless/rt2x00/rt2500usb.c |    2 -
 drivers/net/wireless/rt2x00/rt2800pci.c |    3 +-
 drivers/net/wireless/rt2x00/rt2800usb.c |    3 +-
 drivers/net/wireless/rt2x00/rt2x00.h    |    9 +++++-
 drivers/net/wireless/rt2x00/rt2x00dev.c |   38 ++++++++++++++++++++++++++++-
 drivers/net/wireless/rt2x00/rt2x00mac.c |   40 -------------------------------
 drivers/net/wireless/rt2x00/rt61pci.c   |    3 +-
 drivers/net/wireless/rt2x00/rt73usb.c   |    3 +-
 10 files changed, 48 insertions(+), 57 deletions(-)

Comments

Gertjan van Wingerde Aug. 6, 2012, 7:17 a.m. UTC | #1
Hi Paul,

On Fri, Aug 3, 2012 at 11:32 PM, Paul Fertser <fercerpav@gmail.com> wrote:
> This patch makes all rt2x00 drivers tell mac80211 about possible
> interface combinations they support. Only combinations allowed so far
> are 4 APs for rt61pci and rt73usb; 8 APs for rt2800{pci,usb}.
>
> The driver-specific code in add_interface is now redudant and thus
> removed.
>
> However, real-life testing on RT3052F SoC showed that neither WPA-PSK +
> Open nor 2 WPA-PSK APs work properly (though both APs beacon properly).
> No other tests were performed.
>
> Signed-off-by: Paul Fertser <fercerpav@gmail.com>

I wonder if it is possible to find a less intrusive solution.that
doesn't require changes
to the lowlevel drivers and doesn't need the exporting of the
interface combination structures
outside of the base rt2x00 module.

I can imagine that you select the right structure to use based on the
current max_sta_intf
and max_ap_intf variables of the rt2x00dev structure inside
rt2x00mac.c and leave it with that.

> ---
>  drivers/net/wireless/rt2x00/rt2400pci.c |    2 -
>  drivers/net/wireless/rt2x00/rt2500pci.c |    2 -
>  drivers/net/wireless/rt2x00/rt2500usb.c |    2 -
>  drivers/net/wireless/rt2x00/rt2800pci.c |    3 +-
>  drivers/net/wireless/rt2x00/rt2800usb.c |    3 +-
>  drivers/net/wireless/rt2x00/rt2x00.h    |    9 +++++-
>  drivers/net/wireless/rt2x00/rt2x00dev.c |   38 ++++++++++++++++++++++++++++-
>  drivers/net/wireless/rt2x00/rt2x00mac.c |   40 -------------------------------
>  drivers/net/wireless/rt2x00/rt61pci.c   |    3 +-
>  drivers/net/wireless/rt2x00/rt73usb.c   |    3 +-
>  10 files changed, 48 insertions(+), 57 deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
> index 8b9dbd7..d44c38a 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -1780,8 +1780,6 @@ static const struct data_queue_desc rt2400pci_queue_atim = {
>
>  static const struct rt2x00_ops rt2400pci_ops = {
>         .name                   = KBUILD_MODNAME,
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 1,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
> index d2cf8a4..0543b27 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -2072,8 +2072,6 @@ static const struct data_queue_desc rt2500pci_queue_atim = {
>
>  static const struct rt2x00_ops rt2500pci_ops = {
>         .name                   = KBUILD_MODNAME,
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 1,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
> index 3aae36b..9f82f24 100644
> --- a/drivers/net/wireless/rt2x00/rt2500usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2500usb.c
> @@ -1887,8 +1887,6 @@ static const struct data_queue_desc rt2500usb_queue_atim = {
>
>  static const struct rt2x00_ops rt2500usb_ops = {
>         .name                   = KBUILD_MODNAME,
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 1,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
> index 235376e..39a2bcd 100644
> --- a/drivers/net/wireless/rt2x00/rt2800pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
> @@ -1214,8 +1214,7 @@ static const struct data_queue_desc rt2800pci_queue_bcn = {
>  static const struct rt2x00_ops rt2800pci_ops = {
>         .name                   = KBUILD_MODNAME,
>         .drv_data_size          = sizeof(struct rt2800_drv_data),
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 8,
> +       .if_comb                = &if_comb_8,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
> index 6cf3365..7f04532 100644
> --- a/drivers/net/wireless/rt2x00/rt2800usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2800usb.c
> @@ -892,8 +892,7 @@ static const struct data_queue_desc rt2800usb_queue_bcn = {
>  static const struct rt2x00_ops rt2800usb_ops = {
>         .name                   = KBUILD_MODNAME,
>         .drv_data_size          = sizeof(struct rt2800_drv_data),
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 8,
> +       .if_comb                = &if_comb_8,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> index 8afb546..8cc2263 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> @@ -655,8 +655,7 @@ struct rt2x00lib_ops {
>  struct rt2x00_ops {
>         const char *name;
>         const unsigned int drv_data_size;
> -       const unsigned int max_sta_intf;
> -       const unsigned int max_ap_intf;
> +       const struct ieee80211_iface_combination *if_comb;
>         const unsigned int eeprom_size;
>         const unsigned int rf_size;
>         const unsigned int tx_queues;
> @@ -741,6 +740,12 @@ enum rt2x00_capability_flags {
>  };
>
>  /*
> + * Supported interface combinations: 4 or 8 APs
> + */
> +extern const struct ieee80211_iface_combination if_comb_4;
> +extern const struct ieee80211_iface_combination if_comb_8;
> +
> +/*
>   * rt2x00 device structure.
>   */
>  struct rt2x00_dev {
> diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
> index a6b88bd..c77fc3a 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00dev.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
> @@ -32,19 +32,52 @@
>  #include "rt2x00.h"
>  #include "rt2x00lib.h"
>
> +static const struct ieee80211_iface_limit if_limit_ap_4[] = {
> +       {
> +               .max = 4,
> +               .types = BIT(NL80211_IFTYPE_AP),
> +       },
> +};
> +
> +static const struct ieee80211_iface_limit if_limit_ap_8[] = {
> +       {
> +               .max = 8,
> +               .types = BIT(NL80211_IFTYPE_AP),
> +       },
> +};
> +
> +const struct ieee80211_iface_combination if_comb_4 = {
> +               .limits = if_limit_ap_4,
> +               .n_limits = ARRAY_SIZE(if_limit_ap_4),
> +               .max_interfaces = 4,
> +               .num_different_channels = 1,
> +};
> +EXPORT_SYMBOL_GPL(if_comb_4);
> +
> +const struct ieee80211_iface_combination if_comb_8 = {
> +               .limits = if_limit_ap_8,
> +               .n_limits = ARRAY_SIZE(if_limit_ap_8),
> +               .max_interfaces = 8,
> +               .num_different_channels = 1,
> +};
> +EXPORT_SYMBOL_GPL(if_comb_8);
> +
>  /*
>   * Utility functions.
>   */
>  u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
>                          struct ieee80211_vif *vif)
>  {
> +       u16 max_interfaces = 1;
>         /*
>          * When in STA mode, bssidx is always 0 otherwise local_address[5]
>          * contains the bss number, see BSS_ID_MASK comments for details.
>          */
>         if (rt2x00dev->intf_sta_count)
>                 return 0;
> -       return vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
> +       if (rt2x00dev->ops->if_comb)
> +               max_interfaces = rt2x00dev->ops->if_comb->max_interfaces;
> +       return vif->addr[5] & (max_interfaces - 1);
>  }
>  EXPORT_SYMBOL_GPL(rt2x00lib_get_bssidx);
>
> @@ -1125,6 +1158,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
>  {
>         int retval = -ENOMEM;
>
> +       rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->ops->if_comb;
> +       rt2x00dev->hw->wiphy->n_iface_combinations = 1;
> +
>         /*
>          * Allocate the driver data memory, if necessary.
>          */

Doestn't this introduce a bug for the rt2400 and rt2500 devices that
do not support
multiple AP interfaces? In that case you set the iface_combinations to
a NULL pointer
(as the if_comb field of the rt2x00dev structure is not initialized
for these drivers),
but you still indicate there is 1 combination.

> diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
> index 4ff26c2..8391b6a 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00mac.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
> @@ -212,46 +212,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
>             !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
>                 return -ENODEV;
>
> -       switch (vif->type) {
> -       case NL80211_IFTYPE_AP:
> -               /*
> -                * We don't support mixed combinations of
> -                * sta and ap interfaces.
> -                */
> -               if (rt2x00dev->intf_sta_count)
> -                       return -ENOBUFS;
> -
> -               /*
> -                * Check if we exceeded the maximum amount
> -                * of supported interfaces.
> -                */
> -               if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf)
> -                       return -ENOBUFS;
> -
> -               break;
> -       case NL80211_IFTYPE_STATION:
> -       case NL80211_IFTYPE_ADHOC:
> -       case NL80211_IFTYPE_MESH_POINT:
> -       case NL80211_IFTYPE_WDS:
> -               /*
> -                * We don't support mixed combinations of
> -                * sta and ap interfaces.
> -                */
> -               if (rt2x00dev->intf_ap_count)
> -                       return -ENOBUFS;
> -
> -               /*
> -                * Check if we exceeded the maximum amount
> -                * of supported interfaces.
> -                */
> -               if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)
> -                       return -ENOBUFS;
> -
> -               break;
> -       default:
> -               return -EINVAL;
> -       }
> -
>         /*
>          * Loop through all beacon queues to find a free
>          * entry. Since there are as much beacon entries
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
> index f322596..d4fb469 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -3037,8 +3037,7 @@ static const struct data_queue_desc rt61pci_queue_bcn = {
>
>  static const struct rt2x00_ops rt61pci_ops = {
>         .name                   = KBUILD_MODNAME,
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 4,
> +       .if_comb                = &if_comb_4,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
> index ba6e434..3ecd3e4 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.c
> +++ b/drivers/net/wireless/rt2x00/rt73usb.c
> @@ -2373,8 +2373,7 @@ static const struct data_queue_desc rt73usb_queue_bcn = {
>
>  static const struct rt2x00_ops rt73usb_ops = {
>         .name                   = KBUILD_MODNAME,
> -       .max_sta_intf           = 1,
> -       .max_ap_intf            = 4,
> +       .if_comb                = &if_comb_4,
>         .eeprom_size            = EEPROM_SIZE,
>         .rf_size                = RF_SIZE,
>         .tx_queues              = NUM_TX_QUEUES,
.
---
Gertjan
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 8b9dbd7..d44c38a 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1780,8 +1780,6 @@  static const struct data_queue_desc rt2400pci_queue_atim = {
 
 static const struct rt2x00_ops rt2400pci_ops = {
 	.name			= KBUILD_MODNAME,
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 1,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index d2cf8a4..0543b27 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -2072,8 +2072,6 @@  static const struct data_queue_desc rt2500pci_queue_atim = {
 
 static const struct rt2x00_ops rt2500pci_ops = {
 	.name			= KBUILD_MODNAME,
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 1,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 3aae36b..9f82f24 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1887,8 +1887,6 @@  static const struct data_queue_desc rt2500usb_queue_atim = {
 
 static const struct rt2x00_ops rt2500usb_ops = {
 	.name			= KBUILD_MODNAME,
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 1,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 235376e..39a2bcd 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1214,8 +1214,7 @@  static const struct data_queue_desc rt2800pci_queue_bcn = {
 static const struct rt2x00_ops rt2800pci_ops = {
 	.name			= KBUILD_MODNAME,
 	.drv_data_size		= sizeof(struct rt2800_drv_data),
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 8,
+	.if_comb		= &if_comb_8,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6cf3365..7f04532 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -892,8 +892,7 @@  static const struct data_queue_desc rt2800usb_queue_bcn = {
 static const struct rt2x00_ops rt2800usb_ops = {
 	.name			= KBUILD_MODNAME,
 	.drv_data_size		= sizeof(struct rt2800_drv_data),
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 8,
+	.if_comb		= &if_comb_8,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8afb546..8cc2263 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -655,8 +655,7 @@  struct rt2x00lib_ops {
 struct rt2x00_ops {
 	const char *name;
 	const unsigned int drv_data_size;
-	const unsigned int max_sta_intf;
-	const unsigned int max_ap_intf;
+	const struct ieee80211_iface_combination *if_comb;
 	const unsigned int eeprom_size;
 	const unsigned int rf_size;
 	const unsigned int tx_queues;
@@ -741,6 +740,12 @@  enum rt2x00_capability_flags {
 };
 
 /*
+ * Supported interface combinations: 4 or 8 APs
+ */
+extern const struct ieee80211_iface_combination if_comb_4;
+extern const struct ieee80211_iface_combination if_comb_8;
+
+/*
  * rt2x00 device structure.
  */
 struct rt2x00_dev {
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index a6b88bd..c77fc3a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -32,19 +32,52 @@ 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
 
+static const struct ieee80211_iface_limit if_limit_ap_4[] = {
+	{
+		.max = 4,
+		.types = BIT(NL80211_IFTYPE_AP),
+	},
+};
+
+static const struct ieee80211_iface_limit if_limit_ap_8[] = {
+	{
+		.max = 8,
+		.types = BIT(NL80211_IFTYPE_AP),
+	},
+};
+
+const struct ieee80211_iface_combination if_comb_4 = {
+		.limits = if_limit_ap_4,
+		.n_limits = ARRAY_SIZE(if_limit_ap_4),
+		.max_interfaces = 4,
+		.num_different_channels = 1,
+};
+EXPORT_SYMBOL_GPL(if_comb_4);
+
+const struct ieee80211_iface_combination if_comb_8 = {
+		.limits = if_limit_ap_8,
+		.n_limits = ARRAY_SIZE(if_limit_ap_8),
+		.max_interfaces = 8,
+		.num_different_channels = 1,
+};
+EXPORT_SYMBOL_GPL(if_comb_8);
+
 /*
  * Utility functions.
  */
 u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
 			 struct ieee80211_vif *vif)
 {
+	u16 max_interfaces = 1;
 	/*
 	 * When in STA mode, bssidx is always 0 otherwise local_address[5]
 	 * contains the bss number, see BSS_ID_MASK comments for details.
 	 */
 	if (rt2x00dev->intf_sta_count)
 		return 0;
-	return vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
+	if (rt2x00dev->ops->if_comb)
+		max_interfaces = rt2x00dev->ops->if_comb->max_interfaces;
+	return vif->addr[5] & (max_interfaces - 1);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_get_bssidx);
 
@@ -1125,6 +1158,9 @@  int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 {
 	int retval = -ENOMEM;
 
+	rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->ops->if_comb;
+	rt2x00dev->hw->wiphy->n_iface_combinations = 1;
+
 	/*
 	 * Allocate the driver data memory, if necessary.
 	 */
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 4ff26c2..8391b6a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -212,46 +212,6 @@  int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
 		return -ENODEV;
 
-	switch (vif->type) {
-	case NL80211_IFTYPE_AP:
-		/*
-		 * We don't support mixed combinations of
-		 * sta and ap interfaces.
-		 */
-		if (rt2x00dev->intf_sta_count)
-			return -ENOBUFS;
-
-		/*
-		 * Check if we exceeded the maximum amount
-		 * of supported interfaces.
-		 */
-		if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf)
-			return -ENOBUFS;
-
-		break;
-	case NL80211_IFTYPE_STATION:
-	case NL80211_IFTYPE_ADHOC:
-	case NL80211_IFTYPE_MESH_POINT:
-	case NL80211_IFTYPE_WDS:
-		/*
-		 * We don't support mixed combinations of
-		 * sta and ap interfaces.
-		 */
-		if (rt2x00dev->intf_ap_count)
-			return -ENOBUFS;
-
-		/*
-		 * Check if we exceeded the maximum amount
-		 * of supported interfaces.
-		 */
-		if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)
-			return -ENOBUFS;
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	/*
 	 * Loop through all beacon queues to find a free
 	 * entry. Since there are as much beacon entries
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f322596..d4fb469 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -3037,8 +3037,7 @@  static const struct data_queue_desc rt61pci_queue_bcn = {
 
 static const struct rt2x00_ops rt61pci_ops = {
 	.name			= KBUILD_MODNAME,
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 4,
+	.if_comb		= &if_comb_4,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index ba6e434..3ecd3e4 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2373,8 +2373,7 @@  static const struct data_queue_desc rt73usb_queue_bcn = {
 
 static const struct rt2x00_ops rt73usb_ops = {
 	.name			= KBUILD_MODNAME,
-	.max_sta_intf		= 1,
-	.max_ap_intf		= 4,
+	.if_comb		= &if_comb_4,
 	.eeprom_size		= EEPROM_SIZE,
 	.rf_size		= RF_SIZE,
 	.tx_queues		= NUM_TX_QUEUES,