struct rtl818x_csr *map;
        void (*rf_init)(struct ieee80211_hw *);
        int mode;
+       int if_id;
 
        /* rtl8187 specific */
        struct ieee80211_channel channels[14];
 
        if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
                tmp |= RTL8187_TX_FLAG_RTS;
                hdr->rts_duration =
-                       ieee80211_rts_duration(dev, skb->len, control);
+                       ieee80211_rts_duration(dev, priv->if_id, skb->len, control);
        }
        if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
                tmp |= RTL8187_TX_FLAG_CTS;
        struct rtl8187_priv *priv = dev->priv;
        int i;
 
+       priv->if_id = if_id;
+
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 
 
 /**
  * ieee80211_rts_get - RTS frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  * the next RTS frame from the 802.11 code. The low-level is responsible
  * for calling this function before and RTS frame is needed.
  */
-void ieee80211_rts_get(struct ieee80211_hw *hw,
+void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
                       const void *frame, size_t frame_len,
                       const struct ieee80211_tx_control *frame_txctl,
                       struct ieee80211_rts *rts);
 /**
  * ieee80211_rts_duration - Get the duration field for an RTS frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  *
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
  */
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
                              size_t frame_len,
                              const struct ieee80211_tx_control *frame_txctl);
 
 /**
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
  * for calling this function before and CTS-to-self frame is needed.
  */
-void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
                             const void *frame, size_t frame_len,
                             const struct ieee80211_tx_control *frame_txctl,
                             struct ieee80211_cts *cts);
 /**
  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  *
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
  */
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
                                    size_t frame_len,
                                    const struct ieee80211_tx_control *frame_txctl);
 
 /**
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame.
  * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
  *
  * Calculate the duration field of some generic frame, given its
  * length and transmission rate (in 100kbps).
  */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
                                        size_t frame_len,
                                        int rate);
 
 
                        struct ieee80211_tx_control *control;
                        unsigned int unicast:1;
                        unsigned int ps_buffered:1;
-                       unsigned int short_preamble:1;
                        unsigned int probe_last_frag:1;
                        struct ieee80211_hw_mode *mode;
                        struct ieee80211_rate *rate;
        unsigned int promisc:1;
        unsigned int use_protection:1; /* CTS protect ERP frames */
 
+       /* use short preamble with IEEE 802.11b: this flag is set when the AP
+        * or beacon generator reports that there are no present stations that
+        * cannot support short preambles */
+       unsigned int short_preamble:1;
+
        struct net_device_stats stats;
        int drop_unencrypted;
        int eapol; /* 0 = process EAPOL frames as normal data frames,
        int fragmentation_threshold;
        int short_retry_limit; /* dot11ShortRetryLimit */
        int long_retry_limit; /* dot11LongRetryLimit */
-       int short_preamble; /* use short preamble with IEEE 802.11b */
 
        struct crypto_blkcipher *wep_tx_tfm;
        struct crypto_blkcipher *wep_rx_tfm;
 
                break;
 
        case PRISM2_PARAM_PREAMBLE:
-               local->short_preamble = value;
+               if (sdata->type != IEEE80211_IF_TYPE_AP)
+                       ret = -ENOENT;
+               else
+                       sdata->short_preamble = value;
                break;
 
        case PRISM2_PARAM_STAT_TIME:
                break;
 
        case PRISM2_PARAM_PREAMBLE:
-               *param = local->short_preamble;
+               *param = sdata->short_preamble;
                break;
 
        case PRISM2_PARAM_STAT_TIME:
 
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+       int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
 
        if (use_protection != sdata->use_protection) {
                if (net_ratelimit()) {
                }
                sdata->use_protection = use_protection;
        }
+
+       if (!preamble_mode != sdata->short_preamble) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: switched to %s barker preamble"
+                              " (BSSID=" MAC_FMT ")\n",
+                              dev->name,
+                              (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?
+                                       "short" : "long",
+                              MAC_ARG(ifsta->bssid));
+               }
+               sdata->short_preamble = !preamble_mode;
+       }
 }
 
 
                ieee80211_sta_send_associnfo(dev, ifsta);
        } else {
                netif_carrier_off(dev);
+               sdata->short_preamble = 0;
                sdata->use_protection = 0;
                memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
        }
                               "for IBSS beacon\n", dev->name);
                        break;
                }
-               control.tx_rate = (local->short_preamble &&
+               control.tx_rate = (sdata->short_preamble &&
                                   (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
                        rate->val2 : rate->val;
                control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 
         * to closest integer */
 
        dur = ieee80211_frame_duration(local, 10, rate, erp,
-                                      local->short_preamble);
+                                      tx->sdata->short_preamble);
 
        if (next_frag_len) {
                /* Frame is fragmented: duration increases with time needed to
                /* next fragment */
                dur += ieee80211_frame_duration(local, next_frag_len,
                                                txrate->rate, erp,
-                                               local->short_preamble);
+                                               tx->sdata->short_preamble);
        }
 
        return dur;
                tx->u.tx.control->rate = tx->u.tx.rate;
        }
        tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
-       if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
-           tx->local->short_preamble &&
-           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-               tx->u.tx.short_preamble = 1;
-               tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
-       }
 
        return TXRX_CONTINUE;
 }
 ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+       u16 fc = le16_to_cpu(hdr->frame_control);
        u16 dur;
        struct ieee80211_tx_control *control = tx->u.tx.control;
        struct ieee80211_hw_mode *mode = tx->u.tx.mode;
            !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
                control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
 
+       /* Transmit data frames using short preambles if the driver supports
+        * short preambles at the selected rate and short preambles are
+        * available on the network at the current point in time. */
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+           (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+           tx->sdata->short_preamble &&
+           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
+               tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+       }
+
        /* Setup duration field for the first fragment of the frame. Duration
         * for remaining fragments will be updated when they are being sent
         * to low-level driver in ieee80211_tx(). */
                        return NULL;
                }
 
-               control->tx_rate = (local->short_preamble &&
+               control->tx_rate = (sdata->short_preamble &&
                                    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
                        rate->val2 : rate->val;
                control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 }
 EXPORT_SYMBOL(ieee80211_beacon_get);
 
-void ieee80211_rts_get(struct ieee80211_hw *hw,
+void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
                       const void *frame, size_t frame_len,
                       const struct ieee80211_tx_control *frame_txctl,
                       struct ieee80211_rts *rts)
 
        fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
        rts->frame_control = cpu_to_le16(fctl);
-       rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl);
+       rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl);
        memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
        memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
 }
 EXPORT_SYMBOL(ieee80211_rts_get);
 
-void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
                             const void *frame, size_t frame_len,
                             const struct ieee80211_tx_control *frame_txctl,
                             struct ieee80211_cts *cts)
 
        fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
        cts->frame_control = cpu_to_le16(fctl);
-       cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl);
+       cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl);
        memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_get);
 
 }
 
 /* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
                                        size_t frame_len, int rate)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
        u16 dur;
        int erp;
 
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
        erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
        dur = ieee80211_frame_duration(local, frame_len, rate,
-                                      erp, local->short_preamble);
+                                      erp, sdata->short_preamble);
 
+       dev_put(bdev);
        return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_generic_frame_duration);
 
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
                              size_t frame_len,
                              const struct ieee80211_tx_control *frame_txctl)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate;
-       int short_preamble = local->short_preamble;
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
+       int short_preamble;
        int erp;
        u16 dur;
 
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+       short_preamble = sdata->short_preamble;
+
        rate = frame_txctl->rts_rate;
        erp = !!(rate->flags & IEEE80211_RATE_ERP);
 
        dur += ieee80211_frame_duration(local, 10, rate->rate,
                                        erp, short_preamble);
 
+       dev_put(bdev);
        return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_rts_duration);
 
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
                                    size_t frame_len,
                                    const struct ieee80211_tx_control *frame_txctl)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate;
-       int short_preamble = local->short_preamble;
+       struct net_device *bdev = dev_get_by_index(if_id);
+       struct ieee80211_sub_if_data *sdata;
+       int short_preamble;
        int erp;
        u16 dur;
 
+       if (unlikely(!bdev))
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+       short_preamble = sdata->short_preamble;
+
        rate = frame_txctl->rts_rate;
        erp = !!(rate->flags & IEEE80211_RATE_ERP);
 
                                                erp, short_preamble);
        }
 
+       dev_put(bdev);
        return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);