ath5k: Allow ath5k to support virtual STA and AP interfaces.
authorBen Greear <greearb@candelatech.com>
Thu, 30 Sep 2010 19:22:58 +0000 (12:22 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 5 Oct 2010 17:35:23 +0000 (13:35 -0400)
Support up to 4 virtual APs and as many virtual STA interfaces
as desired.

This patch is ported forward from a patch that Patrick McHardy
did for me against 2.6.31.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Acked-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/reset.c

index 94cc3354f3a6fef8f7d3fda8fd4540de57772793..2ed327a8d690765ab810a1b691c1ef3d2de71de1 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/ethtool.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/etherdevice.h>
 
 #include <net/ieee80211_radiotap.h>
 
@@ -509,8 +510,71 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
        }
 }
 
+struct ath_vif_iter_data {
+       const u8        *hw_macaddr;
+       u8              mask[ETH_ALEN];
+       u8              active_mac[ETH_ALEN]; /* first active MAC */
+       bool            need_set_hw_addr;
+       bool            found_active;
+       bool            any_assoc;
+};
+
+static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath_vif_iter_data *iter_data = data;
+       int i;
+
+       if (iter_data->hw_macaddr)
+               for (i = 0; i < ETH_ALEN; i++)
+                       iter_data->mask[i] &=
+                               ~(iter_data->hw_macaddr[i] ^ mac[i]);
+
+       if (!iter_data->found_active) {
+               iter_data->found_active = true;
+               memcpy(iter_data->active_mac, mac, ETH_ALEN);
+       }
+
+       if (iter_data->need_set_hw_addr && iter_data->hw_macaddr)
+               if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0)
+                       iter_data->need_set_hw_addr = false;
+
+       if (!iter_data->any_assoc) {
+               struct ath5k_vif *avf = (void *)vif->drv_priv;
+               if (avf->assoc)
+                       iter_data->any_assoc = true;
+       }
+}
+
+void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif)
+{
+       struct ath_common *common = ath5k_hw_common(sc->ah);
+       struct ath_vif_iter_data iter_data;
+
+       /*
+        * Use the hardware MAC address as reference, the hardware uses it
+        * together with the BSSID mask when matching addresses.
+        */
+       iter_data.hw_macaddr = common->macaddr;
+       memset(&iter_data.mask, 0xff, ETH_ALEN);
+       iter_data.found_active = false;
+       iter_data.need_set_hw_addr = true;
+
+       if (vif)
+               ath_vif_iter(&iter_data, vif->addr, vif);
+
+       /* Get list of all active MAC addresses */
+       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+                                                  &iter_data);
+       memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN);
+
+       if (iter_data.need_set_hw_addr && iter_data.found_active)
+               ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac);
+
+       ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+}
+
 static void
-ath5k_mode_setup(struct ath5k_softc *sc)
+ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = sc->ah;
        u32 rfilt;
@@ -520,7 +584,7 @@ ath5k_mode_setup(struct ath5k_softc *sc)
        ath5k_hw_set_rx_filter(ah, rfilt);
 
        if (ath5k_hw_hasbssidmask(ah))
-               ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+               ath5k_update_bssid_mask(sc, vif);
 
        /* configure operational mode */
        ath5k_hw_set_opmode(ah, sc->opmode);
@@ -698,13 +762,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
                flags |= AR5K_TXDESC_RTSENA;
                cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
                duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
-                       sc->vif, pktlen, info));
+                       info->control.vif, pktlen, info));
        }
        if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                flags |= AR5K_TXDESC_CTSENA;
                cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
                duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
-                       sc->vif, pktlen, info));
+                       info->control.vif, pktlen, info));
        }
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), padsize,
@@ -806,10 +870,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
                list_add_tail(&bf->list, &sc->txbuf);
        }
 
-       /* beacon buffer */
-       bf->desc = ds;
-       bf->daddr = da;
-       sc->bbuf = bf;
+       /* beacon buffers */
+       INIT_LIST_HEAD(&sc->bcbuf);
+       for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+               bf->desc = ds;
+               bf->daddr = da;
+               list_add_tail(&bf->list, &sc->bcbuf);
+       }
 
        return 0;
 err_free:
@@ -824,11 +891,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
 {
        struct ath5k_buf *bf;
 
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
        list_for_each_entry(bf, &sc->txbuf, list)
                ath5k_txbuf_free_skb(sc, bf);
        list_for_each_entry(bf, &sc->rxbuf, list)
                ath5k_rxbuf_free_skb(sc, bf);
+       list_for_each_entry(bf, &sc->bcbuf, list)
+               ath5k_txbuf_free_skb(sc, bf);
 
        /* Free memory associated with all descriptors */
        pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
@@ -837,7 +905,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
 
        kfree(sc->bufptr);
        sc->bufptr = NULL;
-       sc->bbuf = NULL;
 }
 
 
@@ -1083,7 +1150,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
        spin_unlock_bh(&sc->rxbuflock);
 
        ath5k_hw_start_rx_dma(ah);      /* enable recv descriptors */
-       ath5k_mode_setup(sc);           /* set filters, etc. */
+       ath5k_mode_setup(sc, NULL);             /* set filters, etc. */
        ath5k_hw_start_rx_pcu(ah);      /* re-enable PCU/DMA engine */
 
        return 0;
@@ -1750,6 +1817,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        int ret;
        struct ath5k_softc *sc = hw->priv;
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct sk_buff *skb;
 
        if (WARN_ON(!vif)) {
@@ -1766,11 +1834,11 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
-       sc->bbuf->skb = skb;
-       ret = ath5k_beacon_setup(sc, sc->bbuf);
+       ath5k_txbuf_free_skb(sc, avf->bbuf);
+       avf->bbuf->skb = skb;
+       ret = ath5k_beacon_setup(sc, avf->bbuf);
        if (ret)
-               sc->bbuf->skb = NULL;
+               avf->bbuf->skb = NULL;
 out:
        return ret;
 }
@@ -1786,16 +1854,14 @@ out:
 static void
 ath5k_beacon_send(struct ath5k_softc *sc)
 {
-       struct ath5k_buf *bf = sc->bbuf;
        struct ath5k_hw *ah = sc->ah;
+       struct ieee80211_vif *vif;
+       struct ath5k_vif *avf;
+       struct ath5k_buf *bf;
        struct sk_buff *skb;
 
        ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
-       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) {
-               ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
-               return;
-       }
        /*
         * Check if the previous beacon has gone out.  If
         * not, don't don't try to post another: skip this
@@ -1824,6 +1890,28 @@ ath5k_beacon_send(struct ath5k_softc *sc)
                sc->bmisscount = 0;
        }
 
+       if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+               u64 tsf = ath5k_hw_get_tsf64(ah);
+               u32 tsftu = TSF_TO_TU(tsf);
+               int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
+               vif = sc->bslot[(slot + 1) % ATH_BCBUF];
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+                       "tsf %llx tsftu %x intval %u slot %u vif %p\n",
+                       (unsigned long long)tsf, tsftu, sc->bintval, slot, vif);
+       } else /* only one interface */
+               vif = sc->bslot[0];
+
+       if (!vif)
+               return;
+
+       avf = (void *)vif->drv_priv;
+       bf = avf->bbuf;
+       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+                       sc->opmode == NL80211_IFTYPE_MONITOR)) {
+               ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+               return;
+       }
+
        /*
         * Stop any current dma and put the new frame on the queue.
         * This should never fail since we check above that no frames
@@ -1836,17 +1924,17 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 
        /* refresh the beacon for AP mode */
        if (sc->opmode == NL80211_IFTYPE_AP)
-               ath5k_beacon_update(sc->hw, sc->vif);
+               ath5k_beacon_update(sc->hw, vif);
 
        ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
        ath5k_hw_start_tx_dma(ah, sc->bhalq);
        ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
                sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 
-       skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+       skb = ieee80211_get_buffered_bc(sc->hw, vif);
        while (skb) {
                ath5k_tx_queue(sc->hw, skb, sc->cabq);
-               skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+               skb = ieee80211_get_buffered_bc(sc->hw, vif);
        }
 
        sc->bsent++;
@@ -1876,6 +1964,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
        u64 hw_tsf;
 
        intval = sc->bintval & AR5K_BEACON_PERIOD;
+       if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+               intval /= ATH_BCBUF;    /* staggered multi-bss beacons */
+               if (intval < 15)
+                       ATH5K_WARN(sc, "intval %u is too low, min 15\n",
+                                  intval);
+       }
        if (WARN_ON(!intval))
                return;
 
@@ -2323,6 +2417,10 @@ ath5k_init(struct ath5k_softc *sc)
                ath_hw_keyreset(common, (u16) i);
 
        ath5k_hw_set_ack_bitrate_high(ah, true);
+
+       for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
+               sc->bslot[i] = NULL;
+
        ret = 0;
 done:
        mmiowb();
@@ -2382,7 +2480,6 @@ ath5k_stop_hw(struct ath5k_softc *sc)
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                                "putting device to sleep\n");
        }
-       ath5k_txbuf_free_skb(sc, sc->bbuf);
 
        mmiowb();
        mutex_unlock(&sc->lock);
@@ -2587,9 +2684,9 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        }
 
        SET_IEEE80211_PERM_ADDR(hw, mac);
+       memcpy(&sc->lladdr, mac, ETH_ALEN);
        /* All MAC address bits matter for ACKs */
-       memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
-       ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+       ath5k_update_bssid_mask(sc, NULL);
 
        regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
        ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
@@ -2687,31 +2784,91 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 {
        struct ath5k_softc *sc = hw->priv;
        int ret;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
 
        mutex_lock(&sc->lock);
-       if (sc->vif) {
-               ret = 0;
+
+       if ((vif->type == NL80211_IFTYPE_AP ||
+            vif->type == NL80211_IFTYPE_ADHOC)
+           && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) {
+               ret = -ELNRNG;
                goto end;
        }
 
-       sc->vif = vif;
+       /* Don't allow other interfaces if one ad-hoc is configured.
+        * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+        * We would need to operate the HW in ad-hoc mode to allow TSF updates
+        * for the IBSS, but this breaks with additional AP or STA interfaces
+        * at the moment. */
+       if (sc->num_adhoc_vifs ||
+           (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
+               ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n");
+               ret = -ELNRNG;
+               goto end;
+       }
 
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
-               sc->opmode = vif->type;
+               avf->opmode = vif->type;
                break;
        default:
                ret = -EOPNOTSUPP;
                goto end;
        }
 
-       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode);
+       sc->nvifs++;
+       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);
 
+       /* Assign the vap/adhoc to a beacon xmit slot. */
+       if ((avf->opmode == NL80211_IFTYPE_AP) ||
+           (avf->opmode == NL80211_IFTYPE_ADHOC)) {
+               int slot;
+
+               WARN_ON(list_empty(&sc->bcbuf));
+               avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
+                                            list);
+               list_del(&avf->bbuf->list);
+
+               avf->bslot = 0;
+               for (slot = 0; slot < ATH_BCBUF; slot++) {
+                       if (!sc->bslot[slot]) {
+                               avf->bslot = slot;
+                               break;
+                       }
+               }
+               BUG_ON(sc->bslot[avf->bslot] != NULL);
+               sc->bslot[avf->bslot] = vif;
+               if (avf->opmode == NL80211_IFTYPE_AP)
+                       sc->num_ap_vifs++;
+               else
+                       sc->num_adhoc_vifs++;
+       }
+
+       /* Set combined mode - when APs are configured, operate in AP mode.
+        * Otherwise use the mode of the new interface. This can currently
+        * only deal with combinations of APs and STAs. Only one ad-hoc
+        * interfaces is allowed above.
+        */
+       if (sc->num_ap_vifs)
+               sc->opmode = NL80211_IFTYPE_AP;
+       else
+               sc->opmode = vif->type;
+
+       ath5k_hw_set_opmode(ah, sc->opmode);
+
+       /* Any MAC address is fine, all others are included through the
+        * filter.
+        */
+       memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
        ath5k_hw_set_lladdr(sc->ah, vif->addr);
-       ath5k_mode_setup(sc);
+
+       memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
+
+       ath5k_mode_setup(sc, vif);
 
        ret = 0;
 end:
@@ -2724,15 +2881,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct ath5k_softc *sc = hw->priv;
-       u8 mac[ETH_ALEN] = {};
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
+       unsigned int i;
 
        mutex_lock(&sc->lock);
-       if (sc->vif != vif)
-               goto end;
+       sc->nvifs--;
+
+       if (avf->bbuf) {
+               ath5k_txbuf_free_skb(sc, avf->bbuf);
+               list_add_tail(&avf->bbuf->list, &sc->bcbuf);
+               for (i = 0; i < ATH_BCBUF; i++) {
+                       if (sc->bslot[i] == vif) {
+                               sc->bslot[i] = NULL;
+                               break;
+                       }
+               }
+               avf->bbuf = NULL;
+       }
+       if (avf->opmode == NL80211_IFTYPE_AP)
+               sc->num_ap_vifs--;
+       else if (avf->opmode == NL80211_IFTYPE_ADHOC)
+               sc->num_adhoc_vifs--;
 
-       ath5k_hw_set_lladdr(sc->ah, mac);
-       sc->vif = NULL;
-end:
+       ath5k_update_bssid_mask(sc, NULL);
        mutex_unlock(&sc->lock);
 }
 
@@ -2815,6 +2986,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
        return ((u64)(mfilt[1]) << 32) | mfilt[0];
 }
 
+static bool ath_any_vif_assoc(struct ath5k_softc *sc)
+{
+       struct ath_vif_iter_data iter_data;
+       iter_data.hw_macaddr = NULL;
+       iter_data.any_assoc = false;
+       iter_data.need_set_hw_addr = false;
+       iter_data.found_active = true;
+
+       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter,
+                                                  &iter_data);
+       return iter_data.any_assoc;
+}
+
 #define SUPPORTED_FIF_FLAGS \
        FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
        FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2885,7 +3069,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 
        /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
        * and probes for any BSSID */
-       if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+       if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
                rfilt |= AR5K_RX_FILTER_BEACON;
 
        /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
@@ -3070,14 +3254,13 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                                    struct ieee80211_bss_conf *bss_conf,
                                    u32 changes)
 {
+       struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
        unsigned long flags;
 
        mutex_lock(&sc->lock);
-       if (WARN_ON(sc->vif != vif))
-               goto unlock;
 
        if (changes & BSS_CHANGED_BSSID) {
                /* Cache for later use during resets */
@@ -3091,7 +3274,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                sc->bintval = bss_conf->beacon_int;
 
        if (changes & BSS_CHANGED_ASSOC) {
-               sc->assoc = bss_conf->assoc;
+               avf->assoc = bss_conf->assoc;
+               if (bss_conf->assoc)
+                       sc->assoc = bss_conf->assoc;
+               else
+                       sc->assoc = ath_any_vif_assoc(sc);
+
                if (sc->opmode == NL80211_IFTYPE_STATION)
                        set_beacon_filter(hw, sc->assoc);
                ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
@@ -3119,7 +3307,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                       BSS_CHANGED_BEACON_INT))
                ath5k_beacon_config(sc);
 
- unlock:
        mutex_unlock(&sc->lock);
 }
 
@@ -3394,6 +3581,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
                hw->max_rate_tries = 11;
        }
 
+       hw->vif_data_size = sizeof(struct ath5k_vif);
+
        /* Finish private driver data initialization */
        ret = ath5k_attach(pdev, hw);
        if (ret)
index 7f9d0d3018e81a2b40b026808bf6373516e0d002..b9f6d13b7675760757c8eafdea89d95ec14cd251 100644 (file)
@@ -58,8 +58,7 @@
 
 #define        ATH_RXBUF       40              /* number of RX buffers */
 #define        ATH_TXBUF       200             /* number of TX buffers */
-#define ATH_BCBUF      1               /* number of beacon buffers */
-
+#define ATH_BCBUF      4               /* number of beacon buffers */
 #define ATH5K_TXQ_LEN_MAX      (ATH_TXBUF / 4)         /* bufs per queue */
 #define ATH5K_TXQ_LEN_LOW      (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
 
@@ -152,6 +151,14 @@ struct ath5k_statistics {
 #define ATH_CHAN_MAX   (14+14+14+252+20)
 #endif
 
+struct ath5k_vif {
+       bool                    assoc; /* are we associated or not */
+       enum nl80211_iftype     opmode;
+       int                     bslot;
+       struct ath5k_buf        *bbuf; /* beacon buffer */
+       u8                      lladdr[ETH_ALEN];
+};
+
 /* Software Carrier, keeps track of the driver state
  * associated with an instance of a device */
 struct ath5k_softc {
@@ -188,10 +195,11 @@ struct ath5k_softc {
        unsigned int            curmode;        /* current phy mode */
        struct ieee80211_channel *curchan;      /* current h/w channel */
 
-       struct ieee80211_vif *vif;
+       u16                     nvifs;
 
        enum ath5k_int          imask;          /* interrupt mask copy */
 
+       u8                      lladdr[ETH_ALEN];
        u8                      bssidmask[ETH_ALEN];
 
        unsigned int            led_pin,        /* GPIO pin for driving LED */
@@ -219,7 +227,10 @@ struct ath5k_softc {
 
        spinlock_t              block;          /* protects beacon */
        struct tasklet_struct   beacontq;       /* beacon intr tasklet */
-       struct ath5k_buf        *bbuf;          /* beacon buffer */
+       struct list_head        bcbuf;          /* beacon buffer */
+       struct ieee80211_vif    *bslot[ATH_BCBUF];
+       u16                     num_ap_vifs;
+       u16                     num_adhoc_vifs;
        unsigned int            bhalq,          /* SW q for outgoing beacons */
                                bmisscount,     /* missed beacon transmits */
                                bintval,        /* beacon interval in TU */
index 58912cd762d9808c199f78fbdb6ab97f5261e03f..5b179d01f97db16c64bddc97fc0ade0005bf57ee 100644 (file)
@@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
                 * ieee80211_duration() for a brief description of
                 * what rate we should choose to TX ACKs. */
                tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
-                                                       sc->vif, 10, rate));
+                                                       NULL, 10, rate));
 
                ath5k_hw_reg_write(ah, tx_time, reg);
 
@@ -1060,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                 * XXX: rethink this after new mode changes to
                 * mac80211 are integrated */
                if (ah->ah_version == AR5K_AR5212 &&
-                       ah->ah_sc->vif != NULL)
+                       ah->ah_sc->nvifs)
                        ath5k_hw_write_rate_duration(ah, mode);
 
                /*