Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Sat, 26 Dec 2009 00:34:56 +0000 (16:34 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 26 Dec 2009 00:34:56 +0000 (16:34 -0800)
117 files changed:
Documentation/networking/regulatory.txt
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/hw.h
drivers/net/wireless/ath/ar9170/mac.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/libertas/Kconfig
drivers/net/wireless/libertas/Makefile
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/defs.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/ethtool.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/libertas/mesh.h
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2800usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_acx.c
drivers/net/wireless/wl12xx/wl1251_acx.h
drivers/net/wireless/wl12xx/wl1251_debugfs.c
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_init.h
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_tx.c
drivers/net/wireless/wl12xx/wl1251_tx.h
drivers/net/wireless/zd1211rw/zd_usb.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
net/mac80211/Kconfig
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_netdev.h
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tkip.c
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/.gitignore [new file with mode: 0644]
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/core.h
net/wireless/db.txt [new file with mode: 0644]
net/wireless/genregdb.awk [new file with mode: 0644]
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/regdb.h [new file with mode: 0644]
net/wireless/util.c
net/wireless/wext-compat.c

index ee31369..9551622 100644 (file)
@@ -188,3 +188,27 @@ Then in some part of your code after your wiphy has been registered:
                       &mydriver_jp_regdom.reg_rules[i],
                       sizeof(struct ieee80211_reg_rule));
        regulatory_struct_hint(rd);
+
+Statically compiled regulatory database
+---------------------------------------
+
+In most situations the userland solution using CRDA as described
+above is the preferred solution.  However in some cases a set of
+rules built into the kernel itself may be desirable.  To account
+for this situation, a configuration option has been provided
+(i.e. CONFIG_CFG80211_INTERNAL_REGDB).  With this option enabled,
+the wireless database information contained in net/wireless/db.txt is
+used to generate a data structure encoded in net/wireless/regdb.c.
+That option also enables code in net/wireless/reg.c which queries
+the data in regdb.c as an alternative to using CRDA.
+
+The file net/wireless/db.txt should be kept up-to-date with the db.txt
+file available in the git repository here:
+
+    git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
+
+Again, most users in most situations should be using the CRDA package
+provided with their distribution, and in most other situations users
+should be building and using CRDA on their own rather than using
+this option.  If you are not absolutely sure that you should be using
+CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
index 9f94598..b99a8c2 100644 (file)
@@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
        bool has_plcp;
 };
 
-#define AR9170_NUM_MAX_BA_RETRY        5
 #define AR9170_NUM_TID 16
 #define WME_BA_BMP_SIZE         64
 #define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
@@ -143,7 +142,6 @@ struct ar9170_sta_tid {
        u16 tid;
        enum ar9170_tid_state state;
        bool active;
-       u8 retry;
 };
 
 #define AR9170_QUEUE_TIMEOUT           64
@@ -154,6 +152,8 @@ struct ar9170_sta_tid {
 
 #define AR9170_NUM_TX_STATUS           128
 #define AR9170_NUM_TX_AGG_MAX          30
+#define AR9170_NUM_TX_LIMIT_HARD       AR9170_TXQ_DEPTH
+#define AR9170_NUM_TX_LIMIT_SOFT       (AR9170_TXQ_DEPTH - 10)
 
 struct ar9170 {
        struct ieee80211_hw *hw;
@@ -248,13 +248,8 @@ struct ar9170_sta_info {
        unsigned int ampdu_max_len;
 };
 
-#define AR9170_TX_FLAG_WAIT_FOR_ACK    BIT(0)
-#define AR9170_TX_FLAG_NO_ACK          BIT(1)
-#define AR9170_TX_FLAG_BLOCK_ACK       BIT(2)
-
 struct ar9170_tx_info {
        unsigned long timeout;
-       unsigned int flags;
 };
 
 #define IS_STARTED(a)          (((struct ar9170 *)a)->state >= AR9170_STARTED)
index 701ddb7..0a1d4c2 100644 (file)
@@ -276,6 +276,7 @@ struct ar9170_tx_control {
 #define AR9170_TX_MAC_RATE_PROBE               0x8000
 
 /* either-or */
+#define AR9170_TX_PHY_MOD_MASK                 0x00000003
 #define AR9170_TX_PHY_MOD_CCK                  0x00000000
 #define AR9170_TX_PHY_MOD_OFDM                 0x00000001
 #define AR9170_TX_PHY_MOD_HT                   0x00000002
index ddc8c09..857e861 100644 (file)
@@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar)
        ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
                        ar->edcf[0].txop | ar->edcf[1].txop << 16);
        ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
-                       ar->edcf[1].txop | ar->edcf[3].txop << 16);
+                       ar->edcf[2].txop | ar->edcf[3].txop << 16);
 
        ar9170_regwrite_finish();
 
index f9d6db8..20f04ab 100644 (file)
@@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
        return ar9170_get_seq_h((void *) txc->frame_data);
 }
 
+static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
+{
+       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
 static inline u16 ar9170_get_tid(struct sk_buff *skb)
 {
        struct ar9170_tx_control *txc = (void *) skb->data;
-       struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
-       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+       return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
 }
 
 #define GET_NEXT_SEQ(seq)      ((seq + 1) & 0x0fff)
@@ -213,10 +216,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
        struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
        struct ieee80211_hdr *hdr = (void *) txc->frame_data;
 
-       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
+       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
                          "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
               wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
-              ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
+              ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
               le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
               jiffies_to_msecs(arinfo->timeout - jiffies));
 }
@@ -430,7 +433,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        spin_lock_irqsave(&ar->tx_stats_lock, flags);
        ar->tx_stats[queue].len--;
 
-       if (skb_queue_empty(&ar->tx_pending[queue])) {
+       if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
 #ifdef AR9170_QUEUE_STOP_DEBUG
                printk(KERN_DEBUG "%s: wake queue %d\n",
                       wiphy_name(ar->hw->wiphy), queue);
@@ -440,22 +443,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        }
        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
-       if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
-               ar9170_tx_ampdu_callback(ar, skb);
-       } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
-               arinfo->timeout = jiffies +
-                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
-               skb_queue_tail(&ar->tx_status[queue], skb);
-       } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
+       if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
                ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
        } else {
-#ifdef AR9170_QUEUE_DEBUG
-               printk(KERN_DEBUG "%s: unsupported frame flags!\n",
-                      wiphy_name(ar->hw->wiphy));
-               ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-               dev_kfree_skb_any(skb);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       ar9170_tx_ampdu_callback(ar, skb);
+               } else {
+                       arinfo->timeout = jiffies +
+                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+                       skb_queue_tail(&ar->tx_status[queue], skb);
+               }
        }
 
        if (!ar->tx_stats[queue].len &&
@@ -1407,17 +1405,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
             (is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       if (unlikely(!info->control.sta))
-                               goto err_out;
-
-                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-                       arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
-
-                       goto out;
-               }
-
-               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
                /*
                 * WARNING:
                 * Putting the QoS queue bits into an unexplored territory is
@@ -1431,12 +1418,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
                txc->phy_control |=
                        cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
-               arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK;
-       } else {
-               arinfo->flags = AR9170_TX_FLAG_NO_ACK;
+
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       if (unlikely(!info->control.sta))
+                               goto err_out;
+
+                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+               } else {
+                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
+               }
        }
 
-out:
        return 0;
 
 err_out:
@@ -1671,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar)
                 * tell the FW/HW that this is the last frame,
                 * that way it will wait for the immediate block ack.
                 */
-               if (likely(skb_peek_tail(&agg)))
-                       ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+               ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
 
 #ifdef AR9170_TXAGG_DEBUG
                printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
@@ -1716,6 +1707,21 @@ static void ar9170_tx(struct ar9170 *ar)
 
        for (i = 0; i < __AR9170_NUM_TXQ; i++) {
                spin_lock_irqsave(&ar->tx_stats_lock, flags);
+               frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
+                            skb_queue_len(&ar->tx_pending[i]));
+
+               if (remaining_space < frames) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
+                              "remaining slots:%d, needed:%d\n",
+                              wiphy_name(ar->hw->wiphy), i, remaining_space,
+                              frames);
+#endif /* AR9170_QUEUE_DEBUG */
+                       frames = remaining_space;
+               }
+
+               ar->tx_stats[i].len += frames;
+               ar->tx_stats[i].count += frames;
                if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: queue %d full\n",
@@ -1733,25 +1739,8 @@ static void ar9170_tx(struct ar9170 *ar)
                        __ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_STOP_DEBUG */
                        ieee80211_stop_queue(ar->hw, i);
-                       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-                       continue;
                }
 
-               frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
-                            skb_queue_len(&ar->tx_pending[i]));
-
-               if (remaining_space < frames) {
-#ifdef AR9170_QUEUE_DEBUG
-                       printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
-                              "remaining slots:%d, needed:%d\n",
-                              wiphy_name(ar->hw->wiphy), i, remaining_space,
-                              frames);
-#endif /* AR9170_QUEUE_DEBUG */
-                       frames = remaining_space;
-               }
-
-               ar->tx_stats[i].len += frames;
-               ar->tx_stats[i].count += frames;
                spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
                if (!frames)
@@ -1773,7 +1762,7 @@ static void ar9170_tx(struct ar9170 *ar)
                        arinfo->timeout = jiffies +
                                          msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-                       if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
                                atomic_inc(&ar->tx_ampdu_pending);
 
 #ifdef AR9170_QUEUE_DEBUG
@@ -1784,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar)
 
                        err = ar->tx(ar, skb);
                        if (unlikely(err)) {
-                               if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                               if (info->flags & IEEE80211_TX_CTL_AMPDU)
                                        atomic_dec(&ar->tx_ampdu_pending);
 
                                frames_failed++;
@@ -2366,7 +2355,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
                        sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
                        sta_info->agg[i].active = false;
                        sta_info->agg[i].ssn = 0;
-                       sta_info->agg[i].retry = 0;
                        sta_info->agg[i].tid = i;
                        INIT_LIST_HEAD(&sta_info->agg[i].list);
                        skb_queue_head_init(&sta_info->agg[i].queue);
index e0799d9..0f36118 100644 (file)
@@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cde, 0x0023) },
        /* Z-Com UB82 ABG */
        { USB_DEVICE(0x0cde, 0x0026) },
+       /* Sphairon Homelink 1202 */
+       { USB_DEVICE(0x0cde, 0x0027) },
        /* Arcadyan WN7512 */
        { USB_DEVICE(0x083a, 0xf522) },
        /* Planex GWUS300 */
index e2cef2f..9f1f523 100644 (file)
@@ -453,7 +453,6 @@ struct ath_softc {
        int irq;
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
-       spinlock_t ani_lock;
        spinlock_t sc_pm_lock;
        struct mutex mutex;
 
index b66f72d..592f1b7 100644 (file)
@@ -289,23 +289,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
        if (sc->cur_rate_table == NULL)
                return 0;
 
-       max = 80 + sc->cur_rate_table->rate_cnt * 64;
+       max = 80 + sc->cur_rate_table->rate_cnt * 1024;
        buf = kmalloc(max + 1, GFP_KERNEL);
        if (buf == NULL)
                return 0;
        buf[max] = 0;
 
-       len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
-                      "Retries", "XRetries", "PER");
+       len += sprintf(buf, "%6s %6s %6s "
+                      "%10s %10s %10s %10s\n",
+                      "HT", "MCS", "Rate",
+                      "Success", "Retries", "XRetries", "PER");
 
        for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
                u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
                struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
+               char mcs[5];
+               char htmode[5];
+               int used_mcs = 0, used_htmode = 0;
+
+               if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) {
+                       used_mcs = snprintf(mcs, 5, "%d",
+                               sc->cur_rate_table->info[i].ratecode);
+
+                       if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy))
+                               used_htmode = snprintf(htmode, 5, "HT40");
+                       else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy))
+                               used_htmode = snprintf(htmode, 5, "HT20");
+                       else
+                               used_htmode = snprintf(htmode, 5, "????");
+               }
+
+               mcs[used_mcs] = '\0';
+               htmode[used_htmode] = '\0';
 
                len += snprintf(buf + len, max - len,
-                       "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
-                       (ratekbps % 1000) / 100, stats->success,
-                       stats->retries, stats->xretries,
+                       "%6s %6s %3u.%d: "
+                       "%10u %10u %10u %10u\n",
+                       htmode,
+                       mcs,
+                       ratekbps / 1000,
+                       (ratekbps % 1000) / 100,
+                       stats->success,
+                       stats->retries,
+                       stats->xretries,
                        stats->per);
        }
 
index 2ec61f0..9474f9f 100644 (file)
@@ -343,30 +343,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
        return true;
 }
 
-static const char *ath9k_hw_devname(u16 devid)
-{
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-               return "Atheros 5416";
-       case AR5416_DEVID_PCIE:
-               return "Atheros 5418";
-       case AR9160_DEVID_PCI:
-               return "Atheros 9160";
-       case AR5416_AR9100_DEVID:
-               return "Atheros 9100";
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-               return "Atheros 9280";
-       case AR9285_DEVID_PCIE:
-               return "Atheros 9285";
-       case AR5416_DEVID_AR9287_PCI:
-       case AR5416_DEVID_AR9287_PCIE:
-               return "Atheros 9287";
-       }
-
-       return NULL;
-}
-
 static void ath9k_hw_init_config(struct ath_hw *ah)
 {
        int i;
@@ -392,7 +368,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
                ah->config.spurchans[i][1] = AR_NO_SPUR;
        }
 
-       ah->config.intr_mitigation = true;
+       ah->config.rx_intr_mitigation = true;
 
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -1184,7 +1160,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
 
-       if (ah->config.intr_mitigation)
+       if (ah->config.rx_intr_mitigation)
                ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
        else
                ah->mask_reg |= AR_IMR_RXOK;
@@ -1266,12 +1242,6 @@ static void ath9k_hw_init_user_settings(struct ath_hw *ah)
                ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
 }
 
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
-{
-       return vendorid == ATHEROS_VENDOR_ID ?
-               ath9k_hw_devname(devid) : NULL;
-}
-
 void ath9k_hw_detach(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -2121,7 +2091,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        REG_WRITE(ah, AR_OBS, 8);
 
-       if (ah->config.intr_mitigation) {
+       if (ah->config.rx_intr_mitigation) {
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
        }
@@ -2781,7 +2751,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
 
                *masked = isr & ATH9K_INT_COMMON;
 
-               if (ah->config.intr_mitigation) {
+               if (ah->config.rx_intr_mitigation) {
                        if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
                                *masked |= ATH9K_INT_RX;
                }
@@ -2914,7 +2884,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
        }
        if (ints & ATH9K_INT_RX) {
                mask |= AR_IMR_RXERR;
-               if (ah->config.intr_mitigation)
+               if (ah->config.rx_intr_mitigation)
                        mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
                else
                        mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
index e2b0c73..8849450 100644 (file)
@@ -212,7 +212,7 @@ struct ath9k_ops_config {
        u32 cck_trig_low;
        u32 enable_ani;
        int serialize_regmode;
-       bool intr_mitigation;
+       bool rx_intr_mitigation;
 #define SPUR_DISABLE           0
 #define SPUR_ENABLE_IOCTL      1
 #define SPUR_ENABLE_EEPROM     2
index 9e68c1a..3f5b887 100644 (file)
@@ -363,14 +363,6 @@ static void ath_ani_calibrate(unsigned long data)
        short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
                ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
 
-       /*
-       * don't calibrate when we're scanning.
-       * we are most likely not on our home channel.
-       */
-       spin_lock(&sc->ani_lock);
-       if (sc->sc_flags & SC_OP_SCANNING)
-               goto set_timer;
-
        /* Only calibrate if awake */
        if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
                goto set_timer;
@@ -437,7 +429,6 @@ static void ath_ani_calibrate(unsigned long data)
        ath9k_ps_restore(sc);
 
 set_timer:
-       spin_unlock(&sc->ani_lock);
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -1610,7 +1601,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
        spin_lock_init(&sc->sc_serial_rw);
-       spin_lock_init(&sc->ani_lock);
        spin_lock_init(&sc->sc_pm_lock);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
@@ -3119,6 +3109,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        mutex_lock(&sc->mutex);
        if (ath9k_wiphy_scanning(sc)) {
@@ -3134,10 +3125,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 
        aphy->state = ATH_WIPHY_SCAN;
        ath9k_wiphy_pause_all_forced(sc, aphy);
-
-       spin_lock_bh(&sc->ani_lock);
        sc->sc_flags |= SC_OP_SCANNING;
-       spin_unlock_bh(&sc->ani_lock);
+       del_timer_sync(&common->ani.timer);
+       cancel_delayed_work_sync(&sc->tx_complete_work);
        mutex_unlock(&sc->mutex);
 }
 
@@ -3145,13 +3135,14 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        mutex_lock(&sc->mutex);
-       spin_lock_bh(&sc->ani_lock);
        aphy->state = ATH_WIPHY_ACTIVE;
        sc->sc_flags &= ~SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_FULL_RESET;
-       spin_unlock_bh(&sc->ani_lock);
+       ath_start_ani(common);
+       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
        ath_beacon_config(sc, NULL);
        mutex_unlock(&sc->mutex);
 }
index 9eb96f5..4f6d6fd 100644 (file)
@@ -57,6 +57,10 @@ enum {
                                || (_phy == WLAN_RC_PHY_HT_40_DS)       \
                                || (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \
                                || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_20(_phy)   ((_phy == WLAN_RC_PHY_HT_20_SS)         \
+                               || (_phy == WLAN_RC_PHY_HT_20_DS)       \
+                               || (_phy == WLAN_RC_PHY_HT_20_SS_HGI)   \
+                               || (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
 #define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)         \
                                || (_phy == WLAN_RC_PHY_HT_40_DS)       \
                                || (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \
index ff9b5c8..d707328 100644 (file)
@@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
        int events = 0;
        u16 ev;
 
+       /* Detect early interrupt before driver is fully configued */
+       if (!dev->base_addr) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
+                              dev->name);
+               }
+               return IRQ_HANDLED;
+       }
+
        iface = netdev_priv(dev);
        local = iface->local;
 
index 8414178..0db1fda 100644 (file)
@@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .load_ucode = iwl5000_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
@@ -140,7 +141,7 @@ static struct iwl_lib_ops iwl1000_lib = {
         },
 };
 
-static struct iwl_ops iwl1000_ops = {
+static const struct iwl_ops iwl1000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl1000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -173,7 +174,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
index e413bd3..d1bab14 100644 (file)
@@ -2810,7 +2810,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
 };
 
-static struct iwl_ops iwl3945_ops = {
+static const struct iwl_ops iwl3945_ops = {
        .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
index ecc23ec..28f6eb5 100644 (file)
@@ -227,7 +227,8 @@ extern void iwl3945_rx_replenish(void *data);
 extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                        struct ieee80211_hdr *hdr,int left);
-extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                                      char **buf, bool display);
 extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
 
 /*
index 484c5fd..78706ce 100644 (file)
@@ -2208,7 +2208,7 @@ static struct iwl_lib_ops iwl4965_lib = {
        },
 };
 
-static struct iwl_ops iwl4965_ops = {
+static const struct iwl_ops iwl4965_ops = {
        .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
@@ -2239,7 +2239,6 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 /* Module firmware */
index 33a5866..ec6b276 100644 (file)
@@ -1466,6 +1466,7 @@ struct iwl_lib_ops iwl5000_lib = {
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
@@ -1518,6 +1519,7 @@ static struct iwl_lib_ops iwl5150_lib = {
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
@@ -1555,7 +1557,7 @@ static struct iwl_lib_ops iwl5150_lib = {
         },
 };
 
-static struct iwl_ops iwl5000_ops = {
+static const struct iwl_ops iwl5000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -1563,7 +1565,7 @@ static struct iwl_ops iwl5000_ops = {
        .led = &iwlagn_led_ops,
 };
 
-static struct iwl_ops iwl5150_ops = {
+static const struct iwl_ops iwl5150_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5150_lib,
        .hcmd = &iwl5000_hcmd,
@@ -1599,7 +1601,6 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1668,7 +1669,6 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1692,7 +1692,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1716,7 +1715,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
index 74e5710..a5a0ed4 100644 (file)
@@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = {
        .load_ucode = iwl5000_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
@@ -252,7 +253,7 @@ static struct iwl_lib_ops iwl6000_lib = {
         },
 };
 
-static struct iwl_ops iwl6000_ops = {
+static const struct iwl_ops iwl6000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl6000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -267,7 +268,7 @@ static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
        .calc_rssi = iwl5000_calc_rssi,
 };
 
-static struct iwl_ops iwl6050_ops = {
+static const struct iwl_ops iwl6050_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl6000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -306,7 +307,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -455,7 +454,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
index 1c9866d..771b03c 100644 (file)
@@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)
        iwl_send_statistics_request(priv, CMD_ASYNC, false);
 }
 
+
+static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
+                                       u32 start_idx, u32 num_events,
+                                       u32 mode)
+{
+       u32 i;
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+       unsigned long reg_flags;
+
+       if (mode == 0)
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
+       else
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
+
+       /* Make sure device is powered up for SRAM reads */
+       spin_lock_irqsave(&priv->reg_lock, reg_flags);
+       if (iwl_grab_nic_access(priv)) {
+               spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+               return;
+       }
+
+       /* Set starting address; reads will auto-increment */
+       _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+       rmb();
+
+       /*
+        * "time" is actually "data" for mode 0 (no timestamp).
+        * place event id # at far right for easier visual parsing.
+        */
+       for (i = 0; i < num_events; i++) {
+               ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               if (mode == 0) {
+                       trace_iwlwifi_dev_ucode_cont_event(priv,
+                                                       0, time, ev);
+               } else {
+                       data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+                       trace_iwlwifi_dev_ucode_cont_event(priv,
+                                               time, data, ev);
+               }
+       }
+       /* Allow device to power down */
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+}
+
+void iwl_continuous_event_trace(struct iwl_priv *priv)
+{
+       u32 capacity;   /* event log capacity in # entries */
+       u32 base;       /* SRAM byte address of event log header */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+       if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               capacity = iwl_read_targ_mem(priv, base);
+               num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+               mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+               next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+       } else
+               return;
+
+       if (num_wraps == priv->event_log.num_wraps) {
+               iwl_print_cont_event_trace(priv,
+                                      base, priv->event_log.next_entry,
+                                      next_entry - priv->event_log.next_entry,
+                                      mode);
+               priv->event_log.non_wraps_count++;
+       } else {
+               if ((num_wraps - priv->event_log.num_wraps) > 1)
+                       priv->event_log.wraps_more_count++;
+               else
+                       priv->event_log.wraps_once_count++;
+               trace_iwlwifi_dev_ucode_wrap_event(priv,
+                               num_wraps - priv->event_log.num_wraps,
+                               next_entry, priv->event_log.next_entry);
+               if (next_entry < priv->event_log.next_entry) {
+                       iwl_print_cont_event_trace(priv, base,
+                              priv->event_log.next_entry,
+                              capacity - priv->event_log.next_entry,
+                              mode);
+
+                       iwl_print_cont_event_trace(priv, base, 0,
+                               next_entry, mode);
+               } else {
+                       iwl_print_cont_event_trace(priv, base,
+                              next_entry, capacity - next_entry,
+                              mode);
+
+                       iwl_print_cont_event_trace(priv, base, 0,
+                               next_entry, mode);
+               }
+       }
+       priv->event_log.num_wraps = num_wraps;
+       priv->event_log.next_entry = next_entry;
+}
+
+/**
+ * iwl_bg_ucode_trace - Timer callback to log ucode event
+ *
+ * The timer is continually set to execute every
+ * UCODE_TRACE_PERIOD milliseconds after the last timer expired
+ * this function is to perform continuous uCode event logging operation
+ * if enabled
+ */
+static void iwl_bg_ucode_trace(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (priv->event_log.ucode_trace) {
+               iwl_continuous_event_trace(priv);
+               /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
+               mod_timer(&priv->ucode_trace,
+                        jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+       }
+}
+
 static void iwl_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
@@ -689,12 +814,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
        unsigned long status = priv->status;
 
-       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
                          (flags & HW_CARD_DISABLED) ? "Kill" : "On",
-                         (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+                         (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+                         (flags & CT_CARD_DISABLED) ?
+                         "Reached" : "Not reached");
 
        if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
-                    RF_CARD_DISABLED)) {
+                    CT_CARD_DISABLED)) {
 
                iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
                            CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
@@ -708,10 +835,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                        iwl_write_direct32(priv, HBUS_TARG_MBX_C,
                                        HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
                }
-               if (flags & RF_CARD_DISABLED)
+               if (flags & CT_CARD_DISABLED)
                        iwl_tt_enter_ct_kill(priv);
        }
-       if (!(flags & RF_CARD_DISABLED))
+       if (!(flags & CT_CARD_DISABLED))
                iwl_tt_exit_ct_kill(priv);
 
        if (flags & HW_CARD_DISABLED)
@@ -1705,8 +1832,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
  * iwl_print_event_log - Dump error event log to syslog
  *
  */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                              u32 num_events, u32 mode,
+                              int pos, char **buf, size_t bufsz)
 {
        u32 i;
        u32 base;       /* SRAM byte address of event log header */
@@ -1716,7 +1844,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        unsigned long reg_flags;
 
        if (num_events == 0)
-               return;
+               return pos;
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
        else
@@ -1744,27 +1872,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
                time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        /* data, ev */
-                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
-                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOG:0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                                       time, ev);
+                               IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+                                       time, ev);
+                       }
                } else {
                        data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
                                        time, data, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, time,
+                                       data, ev);
+                       }
                }
        }
 
        /* Allow device to power down */
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       return pos;
 }
 
 /**
  * iwl_print_last_event_logs - Dump the newest # of event log to syslog
  */
-static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
-                                     u32 num_wraps, u32 next_entry,
-                                     u32 size, u32 mode)
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                   u32 num_wraps, u32 next_entry,
+                                   u32 size, u32 mode,
+                                   int pos, char **buf, size_t bufsz)
 {
        /*
         * display the newest DEFAULT_LOG_ENTRIES entries
@@ -1772,21 +1917,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
         */
        if (num_wraps) {
                if (next_entry < size) {
-                       iwl_print_event_log(priv,
-                                       capacity - (size - next_entry),
-                                       size - next_entry, mode);
-                       iwl_print_event_log(priv, 0,
-                                   next_entry, mode);
+                       pos = iwl_print_event_log(priv,
+                                               capacity - (size - next_entry),
+                                               size - next_entry, mode,
+                                               pos, buf, bufsz);
+                       pos = iwl_print_event_log(priv, 0,
+                                                 next_entry, mode,
+                                                 pos, buf, bufsz);
                } else
-                       iwl_print_event_log(priv, next_entry - size,
-                                   size, mode);
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
        } else {
-               if (next_entry < size)
-                       iwl_print_event_log(priv, 0, next_entry, mode);
-               else
-                       iwl_print_event_log(priv, next_entry - size,
-                                           size, mode);
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv, 0, next_entry,
+                                                 mode, pos, buf, bufsz);
+               } else {
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+               }
        }
+       return pos;
 }
 
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
@@ -1794,7 +1944,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
 
 #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
 
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1802,6 +1953,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
+       int pos = 0;
+       size_t bufsz = 0;
 
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
@@ -1812,7 +1965,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                IWL_ERR(priv,
                        "Invalid event log pointer 0x%08X for %s uCode\n",
                        base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
-               return;
+               return pos;
        }
 
        /* event log header */
@@ -1838,7 +1991,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
+               return pos;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1853,6 +2006,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return pos;
+       }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /*
                 * if uCode has wrapped back to top of log,
@@ -1860,17 +2022,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                 * i.e the next one that uCode would fill.
                 */
                if (num_wraps)
-                       iwl_print_event_log(priv, next_entry,
-                                           capacity - next_entry, mode);
+                       pos = iwl_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
                /* (then/else) start at top of log */
-               iwl_print_event_log(priv, 0, next_entry, mode);
+               pos = iwl_print_event_log(priv, 0,
+                                         next_entry, mode, pos, buf, bufsz);
        } else
-               iwl_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode);
+               pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                               next_entry, size, mode,
+                                               pos, buf, bufsz);
 #else
-       iwl_print_last_event_logs(priv, capacity, num_wraps,
-                               next_entry, size, mode);
+       pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode,
+                                       pos, buf, bufsz);
 #endif
+       return pos;
 }
 
 /**
@@ -2456,6 +2623,10 @@ static int iwl_setup_mac(struct iwl_priv *priv)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
+       if (priv->cfg->sku & IWL_SKU_N)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
        hw->sta_data_size = sizeof(struct iwl_station_priv);
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
@@ -3126,6 +3297,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        priv->statistics_periodic.data = (unsigned long)priv;
        priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
+
        if (!priv->cfg->use_isr_legacy)
                tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                        iwl_irq_tasklet, (unsigned long)priv);
@@ -3144,6 +3319,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->beacon_update);
        del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
 }
 
 static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3188,6 +3364,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
index 95a57b3..dc61906 100644 (file)
@@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
 static int iwl_sensitivity_write(struct iwl_priv *priv)
 {
-       int ret = 0;
        struct iwl_sensitivity_cmd cmd ;
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
@@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
               sizeof(u16)*HD_TABLE_SIZE);
 
-       ret = iwl_send_cmd(priv, &cmd_out);
-       if (ret)
-               IWL_ERR(priv, "SENSITIVITY_CMD failed\n");
-
-       return ret;
+       return iwl_send_cmd(priv, &cmd_out);
 }
 
 void iwl_init_sensitivity(struct iwl_priv *priv)
index e915075..28f3800 100644 (file)
@@ -2510,7 +2510,7 @@ struct iwl_card_state_notif {
 
 #define HW_CARD_DISABLED   0x01
 #define SW_CARD_DISABLED   0x02
-#define RF_CARD_DISABLED   0x04
+#define CT_CARD_DISABLED   0x04
 #define RXON_CARD_DISABLED 0x10
 
 struct iwl_ct_kill_config {
index 574d366..e3b96b4 100644 (file)
@@ -450,8 +450,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
        if (priv->cfg->ht_greenfield_support)
                ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-       ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
-                            (priv->cfg->sm_ps_mode << 2));
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
        if (priv->hw_params.ht40_channel & BIT(band)) {
                ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -636,7 +634,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
 
 static bool is_single_rx_stream(struct iwl_priv *priv)
 {
-       return !priv->current_ht_config.is_ht ||
+       return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
               priv->current_ht_config.single_chain_sufficient;
 }
 
@@ -1003,28 +1001,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
  */
 static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
 {
-       int idle_cnt = active_cnt;
-       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-
-       /* # Rx chains when idling and maybe trying to save power */
-       switch (priv->cfg->sm_ps_mode) {
-       case WLAN_HT_CAP_SM_PS_STATIC:
-               idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
-               break;
-       case WLAN_HT_CAP_SM_PS_DYNAMIC:
-               idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
-                       IWL_NUM_IDLE_CHAINS_SINGLE;
-               break;
-       case WLAN_HT_CAP_SM_PS_DISABLED:
-               break;
-       case WLAN_HT_CAP_SM_PS_INVALID:
+       /* # Rx chains when idling, depending on SMPS mode */
+       switch (priv->current_ht_config.smps) {
+       case IEEE80211_SMPS_STATIC:
+       case IEEE80211_SMPS_DYNAMIC:
+               return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_OFF:
+               return active_cnt;
        default:
-               IWL_ERR(priv, "invalid sm_ps mode %u\n",
-                       priv->cfg->sm_ps_mode);
-               WARN_ON(1);
-               break;
+               WARN(1, "invalid SMPS mode %d",
+                    priv->current_ht_config.smps);
+               return active_cnt;
        }
-       return idle_cnt;
 }
 
 /* up to 4 chains */
@@ -1363,7 +1351,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
        priv->cfg->ops->lib->dump_nic_error_log(priv);
-       priv->cfg->ops->lib->dump_nic_event_log(priv, false);
+       if (priv->cfg->ops->lib->dump_csr)
+               priv->cfg->ops->lib->dump_csr(priv);
+       priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
                iwl_print_rx_config_cmd(priv);
@@ -2684,6 +2674,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
        }
 
+       if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+                      IEEE80211_CONF_CHANGE_CHANNEL)) {
+               /* mac80211 uses static for non-HT which is what we want */
+               priv->current_ht_config.smps = conf->smps_mode;
+
+               /*
+                * Recalculate chain counts.
+                *
+                * If monitor mode is enabled then mac80211 will
+                * set up the SM PS mode to OFF if an HT channel is
+                * configured.
+                */
+               if (priv->cfg->ops->hcmd->set_rxon_chain)
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+       }
 
        /* during scanning mac80211 will delay channel setting until
         * scan finish with changed = 0
@@ -2780,10 +2785,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_tx_power(priv, conf->power_level, false);
        }
 
-       /* call to ensure that 4965 rx_chain is set properly in monitor mode */
-       if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
@@ -3191,6 +3192,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
 EXPORT_SYMBOL(iwl_update_stats);
 #endif
 
+const static char *get_csr_string(int cmd)
+{
+       switch (cmd) {
+               IWL_CMD(CSR_HW_IF_CONFIG_REG);
+               IWL_CMD(CSR_INT_COALESCING);
+               IWL_CMD(CSR_INT);
+               IWL_CMD(CSR_INT_MASK);
+               IWL_CMD(CSR_FH_INT_STATUS);
+               IWL_CMD(CSR_GPIO_IN);
+               IWL_CMD(CSR_RESET);
+               IWL_CMD(CSR_GP_CNTRL);
+               IWL_CMD(CSR_HW_REV);
+               IWL_CMD(CSR_EEPROM_REG);
+               IWL_CMD(CSR_EEPROM_GP);
+               IWL_CMD(CSR_OTP_GP_REG);
+               IWL_CMD(CSR_GIO_REG);
+               IWL_CMD(CSR_GP_UCODE_REG);
+               IWL_CMD(CSR_GP_DRIVER_REG);
+               IWL_CMD(CSR_UCODE_DRV_GP1);
+               IWL_CMD(CSR_UCODE_DRV_GP2);
+               IWL_CMD(CSR_LED_REG);
+               IWL_CMD(CSR_DRAM_INT_TBL_REG);
+               IWL_CMD(CSR_GIO_CHICKEN_BITS);
+               IWL_CMD(CSR_ANA_PLL_CFG);
+               IWL_CMD(CSR_HW_REV_WA_REG);
+               IWL_CMD(CSR_DBG_HPET_MEM_REG);
+       default:
+               return "UNKNOWN";
+
+       }
+}
+
+void iwl_dump_csr(struct iwl_priv *priv)
+{
+       int i;
+       u32 csr_tbl[] = {
+               CSR_HW_IF_CONFIG_REG,
+               CSR_INT_COALESCING,
+               CSR_INT,
+               CSR_INT_MASK,
+               CSR_FH_INT_STATUS,
+               CSR_GPIO_IN,
+               CSR_RESET,
+               CSR_GP_CNTRL,
+               CSR_HW_REV,
+               CSR_EEPROM_REG,
+               CSR_EEPROM_GP,
+               CSR_OTP_GP_REG,
+               CSR_GIO_REG,
+               CSR_GP_UCODE_REG,
+               CSR_GP_DRIVER_REG,
+               CSR_UCODE_DRV_GP1,
+               CSR_UCODE_DRV_GP2,
+               CSR_LED_REG,
+               CSR_DRAM_INT_TBL_REG,
+               CSR_GIO_CHICKEN_BITS,
+               CSR_ANA_PLL_CFG,
+               CSR_HW_REV_WA_REG,
+               CSR_DBG_HPET_MEM_REG
+       };
+       IWL_ERR(priv, "CSR values:\n");
+       IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
+               "CSR_INT_PERIODIC_REG)\n");
+       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
+               IWL_ERR(priv, "  %25s: 0X%08x\n",
+                       get_csr_string(csr_tbl[i]),
+                       iwl_read32(priv, csr_tbl[i]));
+       }
+}
+EXPORT_SYMBOL(iwl_dump_csr);
+
 #ifdef CONFIG_PM
 
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
index 27ca859..308f679 100644 (file)
@@ -169,8 +169,10 @@ struct iwl_lib_ops {
        int (*is_valid_rtc_data_addr)(u32 addr);
        /* 1st ucode load */
        int (*load_ucode)(struct iwl_priv *priv);
-       void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
+       int (*dump_nic_event_log)(struct iwl_priv *priv,
+                                 bool full_log, char **buf, bool display);
        void (*dump_nic_error_log)(struct iwl_priv *priv);
+       void (*dump_csr)(struct iwl_priv *priv);
        int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
        /* power management */
        struct iwl_apm_ops apm_ops;
@@ -230,7 +232,6 @@ struct iwl_mod_params {
  * @chain_noise_num_beacons: number of beacons used to compute chain noise
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
- * @sm_ps_mode: spatial multiplexing power save mode
  * @support_wimax_coexist: support wimax/wifi co-exist
  *
  * We enable the driver to be backward compatible wrt API version. The
@@ -287,7 +288,6 @@ struct iwl_cfg {
        const bool supports_idle;
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
-       u8 sm_ps_mode;
        const bool support_wimax_coexist;
 };
 
@@ -581,7 +581,9 @@ int iwl_pci_resume(struct pci_dev *pdev);
 *  Error Handling Debugging
 ******************************************************/
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+int iwl_dump_nic_event_log(struct iwl_priv *priv,
+                          bool full_log, char **buf, bool display);
+void iwl_dump_csr(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUG
 void iwl_print_rx_config_cmd(struct iwl_priv *priv);
 #else
index d61293a..58e0462 100644 (file)
@@ -109,6 +109,8 @@ struct iwl_debugfs {
                struct dentry *file_power_save_status;
                struct dentry *file_clear_ucode_statistics;
                struct dentry *file_clear_traffic_statistics;
+               struct dentry *file_csr;
+               struct dentry *file_ucode_tracing;
        } dbgfs_debug_files;
        u32 sram_offset;
        u32 sram_len;
index 21e0f66..ee5aed1 100644 (file)
@@ -420,6 +420,23 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        return ret;
 }
 
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -ENOMEM;
+
+       pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true);
+       if (pos && buf) {
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+               kfree(buf);
+       }
+       return ret;
+}
+
 static ssize_t iwl_dbgfs_log_event_write(struct file *file,
                                        const char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -436,7 +453,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
        if (sscanf(buf, "%d", &event_log_flag) != 1)
                return -EFAULT;
        if (event_log_flag == 1)
-               priv->cfg->ops->lib->dump_nic_event_log(priv, true);
+               priv->cfg->ops->lib->dump_nic_event_log(priv, true,
+                                                       NULL, false);
 
        return count;
 }
@@ -859,7 +877,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
 }
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
-DEBUGFS_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_FILE_OPS(nvm);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(channels);
@@ -1845,6 +1863,80 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int csr;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &csr) != 1)
+               return -EFAULT;
+
+       if (priv->cfg->ops->lib->dump_csr)
+               priv->cfg->ops->lib->dump_csr(priv);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[128];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
+                       priv->event_log.ucode_trace ? "On" : "Off");
+       pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
+                       priv->event_log.non_wraps_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
+                       priv->event_log.wraps_once_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
+                       priv->event_log.wraps_more_count);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int trace;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &trace) != 1)
+               return -EFAULT;
+
+       if (trace) {
+               priv->event_log.ucode_trace = true;
+               /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
+               mod_timer(&priv->ucode_trace,
+                       jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+       } else {
+               priv->event_log.ucode_trace = false;
+               del_timer_sync(&priv->ucode_trace);
+       }
+
+       return count;
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1859,6 +1951,8 @@ DEBUGFS_READ_FILE_OPS(tx_power);
 DEBUGFS_READ_FILE_OPS(power_save_status);
 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
+DEBUGFS_WRITE_FILE_OPS(csr);
+DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
 
 /*
  * Create the debugfs files and directories
@@ -1889,7 +1983,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
        DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
        DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
+       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
        DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
        DEBUGFS_ADD_FILE(status, data, S_IRUSR);
@@ -1909,12 +2003,14 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
        DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
        DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
                DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);
        }
        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
@@ -1966,6 +2062,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
                        file_clear_ucode_statistics);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_clear_traffic_statistics);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
                DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_ucode_rx_stats);
@@ -1977,6 +2074,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
                        file_sensitivity);
                DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_chain_noise);
+               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+                       file_ucode_tracing);
        }
        DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
index 165d1f6..42f9b17 100644 (file)
@@ -512,6 +512,7 @@ struct iwl_ht_config {
        bool is_ht;
        bool is_40mhz;
        bool single_chain_sufficient;
+       enum ieee80211_smps_mode smps; /* current smps mode */
        /* BSS related data */
        u8 extension_chan_offset;
        u8 ht_protection;
@@ -984,6 +985,32 @@ struct iwl_switch_rxon {
        __le16 channel;
 };
 
+/*
+ * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
+ * to perform continuous uCode event logging operation if enabled
+ */
+#define UCODE_TRACE_PERIOD (100)
+
+/*
+ * iwl_event_log: current uCode event log position
+ *
+ * @ucode_trace: enable/disable ucode continuous trace timer
+ * @num_wraps: how many times the event buffer wraps
+ * @next_entry:  the entry just before the next one that uCode would fill
+ * @non_wraps_count: counter for no wrap detected when dump ucode events
+ * @wraps_once_count: counter for wrap once detected when dump ucode events
+ * @wraps_more_count: counter for wrap more than once detected
+ *                   when dump ucode events
+ */
+struct iwl_event_log {
+       bool ucode_trace;
+       u32 num_wraps;
+       u32 next_entry;
+       int non_wraps_count;
+       int wraps_once_count;
+       int wraps_more_count;
+};
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1261,6 +1288,7 @@ struct iwl_priv {
        u32 disable_tx_power_cal;
        struct work_struct run_time_calib_work;
        struct timer_list statistics_periodic;
+       struct timer_list ucode_trace;
        bool hw_ready;
        /*For 3945*/
 #define IWL_DEFAULT_TX_POWER 0x0F
@@ -1268,6 +1296,8 @@ struct iwl_priv {
        struct iwl3945_notif_statistics statistics_39;
 
        u32 sta_supp_rates;
+
+       struct iwl_event_log event_log;
 }; /*iwl_priv */
 
 static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
index e7d88d1..bf46308 100644 (file)
@@ -11,4 +11,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
 #endif
index 2136196..0819f99 100644 (file)
@@ -64,6 +64,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
        TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
 );
 
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_ucode
+
+TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
+       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_ARGS(priv, time, data, ev),
+       TP_STRUCT__entry(
+               PRIV_ENTRY
+
+               __field(u32, time)
+               __field(u32, data)
+               __field(u32, ev)
+       ),
+       TP_fast_assign(
+               PRIV_ASSIGN;
+               __entry->time = time;
+               __entry->data = data;
+               __entry->ev = ev;
+       ),
+       TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
+                 __entry->priv, __entry->time, __entry->data, __entry->ev)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
+       TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_ARGS(priv, wraps, n_entry, p_entry),
+       TP_STRUCT__entry(
+               PRIV_ENTRY
+
+               __field(u32, wraps)
+               __field(u32, n_entry)
+               __field(u32, p_entry)
+       ),
+       TP_fast_assign(
+               PRIV_ASSIGN;
+               __entry->wraps = wraps;
+               __entry->n_entry = n_entry;
+               __entry->p_entry = p_entry;
+       ),
+       TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
+                 __entry->priv, __entry->wraps, __entry->n_entry,
+                 __entry->p_entry)
+);
+
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi
 
index e5d8fa3..6533122 100644 (file)
@@ -1559,8 +1559,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
  * iwl3945_print_event_log - Dump error event log to syslog
  *
  */
-static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                                 u32 num_events, u32 mode,
+                                 int pos, char **buf, size_t bufsz)
 {
        u32 i;
        u32 base;       /* SRAM byte address of event log header */
@@ -1570,7 +1571,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
        unsigned long reg_flags;
 
        if (num_events == 0)
-               return;
+               return pos;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 
@@ -1596,26 +1597,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
                time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        /* data, ev */
-                       IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                                                             time, ev);
+                       }
                } else {
                        data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-                       IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "%010u\t0x%08x\t%04u\n",
+                                       time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, time,
+                                                             data, ev);
+                       }
                }
        }
 
        /* Allow device to power down */
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       return pos;
 }
 
 /**
  * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
  */
-static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
                                      u32 num_wraps, u32 next_entry,
-                                     u32 size, u32 mode)
+                                     u32 size, u32 mode,
+                                     int pos, char **buf, size_t bufsz)
 {
        /*
         * display the newest DEFAULT_LOG_ENTRIES entries
@@ -1623,21 +1641,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
         */
        if (num_wraps) {
                if (next_entry < size) {
-                       iwl3945_print_event_log(priv,
-                                       capacity - (size - next_entry),
-                                       size - next_entry, mode);
-                       iwl3945_print_event_log(priv, 0,
-                                   next_entry, mode);
+                       pos = iwl3945_print_event_log(priv,
+                                            capacity - (size - next_entry),
+                                            size - next_entry, mode,
+                                            pos, buf, bufsz);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                } else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                   size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        } else {
                if (next_entry < size)
-                       iwl3945_print_event_log(priv, 0, next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                           size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        }
+       return pos;
 }
 
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
@@ -1645,7 +1670,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
 
 #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
 
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1653,11 +1679,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
+       int pos = 0;
+       size_t bufsz = 0;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
        if (!iwl3945_hw_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return;
+               return pos;
        }
 
        /* event log header */
@@ -1683,7 +1711,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
+               return pos;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1699,25 +1727,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                  size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return pos;
+       }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /* if uCode has wrapped back to top of log,
                 * start at the oldest entry,
                 * i.e the next one that uCode would fill.
                 */
                if (num_wraps)
-                       iwl3945_print_event_log(priv, next_entry,
-                                   capacity - next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
 
                /* (then/else) start at top of log */
-               iwl3945_print_event_log(priv, 0, next_entry, mode);
+               pos = iwl3945_print_event_log(priv, 0, next_entry, mode,
+                                             pos, buf, bufsz);
        } else
-               iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode);
+               pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                                   next_entry, size, mode,
+                                                   pos, buf, bufsz);
 #else
-       iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                               next_entry, size, mode);
+       pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                           next_entry, size, mode,
+                                           pos, buf, bufsz);
 #endif
-
+       return pos;
 }
 
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
index 6d6ed74..d32adea 100644 (file)
@@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
        struct iwm_umac_notif_mgt_frame *mgt_frame =
                        (struct iwm_umac_notif_mgt_frame *)buf;
        struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
-       u8 *ie;
 
        IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
                    le16_to_cpu(mgt_frame->len));
 
        if (ieee80211_is_assoc_req(mgt->frame_control)) {
-               ie = mgt->u.assoc_req.variable;;
-               iwm->req_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+                                 - offsetof(struct ieee80211_mgmt,
+                                            u.assoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
-               ie = mgt->u.reassoc_req.variable;;
-               iwm->req_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+                                 - offsetof(struct ieee80211_mgmt,
+                                            u.reassoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
-               ie = mgt->u.assoc_resp.variable;;
-               iwm->resp_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+                                  - offsetof(struct ieee80211_mgmt,
+                                             u.assoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
-               ie = mgt->u.reassoc_resp.variable;;
-               iwm->resp_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+                                  - offsetof(struct ieee80211_mgmt,
+                                             u.reassoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
@@ -1534,6 +1533,33 @@ static void classify8023(struct sk_buff *skb)
        }
 }
 
+static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
+{
+       struct wireless_dev *wdev = iwm_to_wdev(iwm);
+       struct net_device *ndev = iwm_to_ndev(iwm);
+       struct sk_buff_head list;
+       struct sk_buff *frame;
+
+       IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
+
+       __skb_queue_head_init(&list);
+       ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
+
+       while ((frame = __skb_dequeue(&list))) {
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += frame->len;
+
+               frame->protocol = eth_type_trans(frame, ndev);
+               frame->ip_summed = CHECKSUM_NONE;
+               memset(frame->cb, 0, sizeof(frame->cb));
+
+               if (netif_rx_ni(frame) == NET_RX_DROP) {
+                       IWM_ERR(iwm, "Packet dropped\n");
+                       ndev->stats.rx_dropped++;
+               }
+       }
+}
+
 static void iwm_rx_process_packet(struct iwm_priv *iwm,
                                  struct iwm_rx_packet *packet,
                                  struct iwm_rx_ticket_node *ticket_node)
@@ -1548,25 +1574,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
        switch (le16_to_cpu(ticket_node->ticket->action)) {
        case IWM_RX_TICKET_RELEASE:
                IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
-               classify8023(skb);
+
                iwm_rx_adjust_packet(iwm, packet, ticket_node);
+               skb->dev = iwm_to_ndev(iwm);
+               classify8023(skb);
+
+               if (le16_to_cpu(ticket_node->ticket->flags) &
+                   IWM_RX_TICKET_AMSDU_MSK) {
+                       iwm_rx_process_amsdu(iwm, skb);
+                       break;
+               }
+
                ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
                if (ret < 0) {
                        IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
                                   "%d\n", ret);
+                       kfree_skb(packet->skb);
                        break;
                }
 
                IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
 
-               skb->dev = iwm_to_ndev(iwm);
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += skb->len;
+
                skb->protocol = eth_type_trans(skb, ndev);
                skb->ip_summed = CHECKSUM_NONE;
                memset(skb->cb, 0, sizeof(skb->cb));
 
-               ndev->stats.rx_packets++;
-               ndev->stats.rx_bytes += skb->len;
-
                if (netif_rx_ni(skb) == NET_RX_DROP) {
                        IWM_ERR(iwm, "Packet dropped\n");
                        ndev->stats.rx_dropped++;
index 30aa9d4..0485c99 100644 (file)
@@ -37,3 +37,9 @@ config LIBERTAS_DEBUG
        depends on LIBERTAS
        ---help---
          Debugging support.
+
+config LIBERTAS_MESH
+       bool "Enable mesh support"
+       depends on LIBERTAS
+       help
+         This enables Libertas' MESH support, used by e.g. the OLPC people.
index b188cd9..45e870e 100644 (file)
@@ -5,11 +5,11 @@ libertas-y += cmdresp.o
 libertas-y += debugfs.o
 libertas-y += ethtool.o
 libertas-y += main.o
-libertas-y += mesh.o
 libertas-y += rx.o
 libertas-y += scan.o
 libertas-y += tx.o
 libertas-y += wext.o
+libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
 
 usb8xxx-objs += if_usb.o
 libertas_cs-objs += if_cs.o
index 7510673..5e650f3 100644 (file)
@@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
        cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
        cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
        ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
-       if (!ret && cmd_action == CMD_ACT_GET) {
-               priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+       if (!ret && cmd_action == CMD_ACT_GET)
                priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
-       }
 
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
@@ -807,8 +805,7 @@ static int lbs_try_associate(struct lbs_private *priv,
        }
 
        /* Use short preamble only when both the BSS and firmware support it */
-       if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
-           (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+       if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                preamble = RADIO_PREAMBLE_SHORT;
 
        ret = lbs_set_radio(priv, preamble, 1);
@@ -939,8 +936,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
        }
 
        /* Use short preamble only when both the BSS and firmware support it */
-       if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
-           (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+       if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
                lbs_deb_join("AdhocJoin: Short preamble\n");
                preamble = RADIO_PREAMBLE_SHORT;
        }
@@ -1049,7 +1045,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
        struct assoc_request *assoc_req)
 {
        struct cmd_ds_802_11_ad_hoc_start cmd;
-       u8 preamble = RADIO_PREAMBLE_LONG;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
        size_t ratesize = 0;
        u16 tmpcap = 0;
        int ret = 0;
@@ -1057,11 +1053,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
-       if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
-               lbs_deb_join("ADHOC_START: Will use short preamble\n");
-               preamble = RADIO_PREAMBLE_SHORT;
-       }
-
        ret = lbs_set_radio(priv, preamble, 1);
        if (ret)
                goto out;
index 42611be..82371ef 100644 (file)
@@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
        lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
                    cmd.hwifversion, cmd.version);
 
-       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
-       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
-       /* 5.110.22 have mesh command with 0xa3 command id */
-       /* 10.0.0.p0 FW brings in mesh config command with different id */
-       /* Check FW version MSB and initialize mesh_fw_ver */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
-               priv->mesh_fw_ver = MESH_FW_OLD;
-       else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
-               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
-               priv->mesh_fw_ver = MESH_FW_NEW;
-       else
-               priv->mesh_fw_ver = MESH_NONE;
-
        /* Clamp region code to 8-bit since FW spec indicates that it should
         * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
         * returns non-zero high 8 bits here.
@@ -855,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
        if (priv->fwrelease < 0x09000000) {
                switch (preamble) {
                case RADIO_PREAMBLE_SHORT:
-                       if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
-                               goto out;
-                       /* Fall through */
                case RADIO_PREAMBLE_AUTO:
                case RADIO_PREAMBLE_LONG:
                        cmd.control = cpu_to_le16(preamble);
@@ -1011,6 +995,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = 0;
                break;
 
+#ifdef CONFIG_LIBERTAS_MESH
+
        case CMD_BT_ACCESS:
                ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
                break;
@@ -1019,6 +1005,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
                break;
 
+#endif
+
        case CMD_802_11_BEACON_CTRL:
                ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
                break;
@@ -1317,7 +1305,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                if ((priv->psmode != LBS802_11POWERMODECAM) &&
                    (priv->psstate == PS_STATE_FULL_POWER) &&
                    ((priv->connect_status == LBS_CONNECTED) ||
-                   (priv->mesh_connect_status == LBS_CONNECTED))) {
+                   lbs_mesh_connected(priv))) {
                        if (priv->secinfo.WPAenabled ||
                            priv->secinfo.WPA2enabled) {
                                /* check for valid WPA group keys */
index 2862748..cb4138a 100644 (file)
@@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
 int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
 
 
-/* Mesh related */
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
-                   struct cmd_ds_mesh_access *cmd);
-
-int lbs_mesh_config_send(struct lbs_private *priv,
-                        struct cmd_ds_mesh_config *cmd,
-                        uint16_t action, uint16_t type);
-
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
-
-
 /* Commands only used in wext.c, assoc. and scan.c */
 
 int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
index 21d5769..0334a58 100644 (file)
@@ -485,20 +485,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
                break;
 
        case MACREG_INT_CODE_MESH_AUTO_STARTED:
-               /* Ignore spurious autostart events if autostart is disabled */
-               if (!priv->mesh_autostart_enabled) {
-                       lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
-                       break;
-               }
-               lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
-               priv->mesh_connect_status = LBS_CONNECTED;
-               if (priv->mesh_open) {
-                       netif_carrier_on(priv->mesh_dev);
-                       if (!priv->tx_pending_len)
-                               netif_wake_queue(priv->mesh_dev);
-               }
-               priv->mode = IW_MODE_ADHOC;
-               schedule_work(&priv->sync_channel);
+               /* Ignore spurious autostart events */
+               lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
                break;
 
        default:
index 6b6ea9f..ea3f10e 100644 (file)
@@ -397,13 +397,6 @@ enum KEY_INFO_WPA {
        KEY_INFO_WPA_ENABLED = 0x04
 };
 
-/** mesh_fw_ver */
-enum _mesh_fw_ver {
-       MESH_NONE = 0, /* MESH is not supported */
-       MESH_FW_OLD,   /* MESH is supported in FW V5 */
-       MESH_FW_NEW,   /* MESH is supported in FW V10 and newer */
-};
-
 /* Default values for fwt commands. */
 #define FWT_DEFAULT_METRIC 0
 #define FWT_DEFAULT_DIR 1
index 05bb298..c348aff 100644 (file)
@@ -39,15 +39,14 @@ struct lbs_private {
 
        /* Mesh */
        struct net_device *mesh_dev; /* Virtual device */
+#ifdef CONFIG_LIBERTAS_MESH
        u32 mesh_connect_status;
        struct lbs_mesh_stats mstats;
        int mesh_open;
-       int mesh_fw_ver;
-       int mesh_autostart_enabled;
        uint16_t mesh_tlv;
        u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
        u8 mesh_ssid_len;
-       struct work_struct sync_channel;
+#endif
 
        /* Monitor mode */
        struct net_device *rtap_net_dev;
@@ -176,9 +175,7 @@ struct lbs_private {
        struct bss_descriptor *networks;
        struct assoc_request * pending_assoc_req;
        struct assoc_request * in_progress_assoc_req;
-       u16 capability;
        uint16_t enablehwauto;
-       uint16_t ratebitmap;
 
        /* ADHOC */
        u16 beacon_period;
index 63d0203..3804a58 100644 (file)
@@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = {
        .get_drvinfo = lbs_ethtool_get_drvinfo,
        .get_eeprom =  lbs_ethtool_get_eeprom,
        .get_eeprom_len = lbs_ethtool_get_eeprom_len,
+#ifdef CONFIG_LIBERTAS_MESH
        .get_sset_count = lbs_mesh_ethtool_get_sset_count,
        .get_ethtool_stats = lbs_mesh_ethtool_get_stats,
        .get_strings = lbs_mesh_ethtool_get_strings,
+#endif
        .get_wol = lbs_ethtool_get_wol,
        .set_wol = lbs_ethtool_set_wol,
 };
index c2975c8..60bde12 100644 (file)
@@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
                if (priv->monitormode == monitor_mode)
                        return strlen(buf);
                if (!priv->monitormode) {
-                       if (priv->infra_open || priv->mesh_open)
+                       if (priv->infra_open || lbs_mesh_open(priv))
                                return -EBUSY;
                        if (priv->mode == IW_MODE_INFRA)
                                lbs_cmd_80211_deauthenticate(priv,
@@ -622,7 +622,7 @@ static int lbs_thread(void *data)
                                if (priv->connect_status == LBS_CONNECTED)
                                        netif_wake_queue(priv->dev);
                                if (priv->mesh_dev &&
-                                   priv->mesh_connect_status == LBS_CONNECTED)
+                                   lbs_mesh_connected(priv))
                                        netif_wake_queue(priv->mesh_dev);
                        }
                }
@@ -809,18 +809,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
        return 0;
 }
 
-static void lbs_sync_channel_worker(struct work_struct *work)
-{
-       struct lbs_private *priv = container_of(work, struct lbs_private,
-               sync_channel);
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-       if (lbs_update_channel(priv))
-               lbs_pr_info("Channel synchronization failed.");
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-
 static int lbs_init_adapter(struct lbs_private *priv)
 {
        size_t bufsize;
@@ -848,14 +836,12 @@ static int lbs_init_adapter(struct lbs_private *priv)
        memset(priv->current_addr, 0xff, ETH_ALEN);
 
        priv->connect_status = LBS_DISCONNECTED;
-       priv->mesh_connect_status = LBS_DISCONNECTED;
        priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        priv->mode = IW_MODE_INFRA;
        priv->channel = DEFAULT_AD_HOC_CHANNEL;
        priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        priv->radio_on = 1;
        priv->enablehwauto = 1;
-       priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
        priv->psmode = LBS802_11POWERMODECAM;
        priv->psstate = PS_STATE_FULL_POWER;
        priv->is_deep_sleep = 0;
@@ -998,11 +984,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
        INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
        INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
-       INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
-
-       priv->mesh_open = 0;
-       sprintf(priv->mesh_ssid, "mesh");
-       priv->mesh_ssid_len = 4;
 
        priv->wol_criteria = 0xffffffff;
        priv->wol_gpio = 0xff;
@@ -1076,6 +1057,17 @@ void lbs_remove_card(struct lbs_private *priv)
 EXPORT_SYMBOL_GPL(lbs_remove_card);
 
 
+static int lbs_rtap_supported(struct lbs_private *priv)
+{
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+               return 1;
+
+       /* newer firmware use a capability mask */
+       return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
+}
+
+
 int lbs_start_card(struct lbs_private *priv)
 {
        struct net_device *dev = priv->dev;
@@ -1095,12 +1087,14 @@ int lbs_start_card(struct lbs_private *priv)
 
        lbs_update_channel(priv);
 
+       lbs_init_mesh(priv);
+
        /*
         * While rtap isn't related to mesh, only mesh-enabled
         * firmware implements the rtap functionality via
         * CMD_802_11_MONITOR_MODE.
         */
-       if (lbs_init_mesh(priv)) {
+       if (lbs_rtap_supported(priv)) {
                if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
                        lbs_pr_err("cannot register lbs_rtap attribute\n");
        }
@@ -1134,7 +1128,9 @@ void lbs_stop_card(struct lbs_private *priv)
        netif_carrier_off(dev);
 
        lbs_debugfs_remove_one(priv);
-       if (lbs_deinit_mesh(priv))
+       lbs_deinit_mesh(priv);
+
+       if (lbs_rtap_supported(priv))
                device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
 
        /* Delete the timeout of the currently processing command */
index 2f91c9b..954cd00 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
@@ -196,7 +195,14 @@ int lbs_init_mesh(struct lbs_private *priv)
 
        lbs_deb_enter(LBS_DEB_MESH);
 
-       if (priv->mesh_fw_ver == MESH_FW_OLD) {
+       priv->mesh_connect_status = LBS_DISCONNECTED;
+
+       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+       /* 5.110.22 have mesh command with 0xa3 command id */
+       /* 10.0.0.p0 FW brings in mesh config command with different id */
+       /* Check FW version MSB and initialize mesh_fw_ver */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
                /* Enable mesh, if supported, and work out which TLV it uses.
                   0x100 + 291 is an unofficial value used in 5.110.20.pXX
                   0x100 + 37 is the official value used in 5.110.21.pXX
@@ -218,7 +224,9 @@ int lbs_init_mesh(struct lbs_private *priv)
                                            priv->channel))
                                priv->mesh_tlv = 0;
                }
-       } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+       } else
+       if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
                /* 10.0.0.pXX new firmwares should succeed with TLV
                 * 0x100+37; Do not invoke command with old TLV.
                 */
@@ -227,7 +235,12 @@ int lbs_init_mesh(struct lbs_private *priv)
                                    priv->channel))
                        priv->mesh_tlv = 0;
        }
+
+
        if (priv->mesh_tlv) {
+               sprintf(priv->mesh_ssid, "mesh");
+               priv->mesh_ssid_len = 4;
+
                lbs_add_mesh(priv);
 
                if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
@@ -416,10 +429,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
        struct net_device *dev, struct rxpd *rxpd)
 {
        if (priv->mesh_dev) {
-               if (priv->mesh_fw_ver == MESH_FW_OLD) {
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
                        if (rxpd->rx_control & RxPD_MESH_FRAME)
                                dev = priv->mesh_dev;
-               } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+               } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
                        if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
                                dev = priv->mesh_dev;
                }
@@ -432,9 +445,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
        struct net_device *dev, struct txpd *txpd)
 {
        if (dev == priv->mesh_dev) {
-               if (priv->mesh_fw_ver == MESH_FW_OLD)
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
                        txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
-               else if (priv->mesh_fw_ver == MESH_FW_NEW)
+               else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
                        txpd->u.bss.bss_num = MESH_IFACE_ID;
        }
 }
@@ -538,7 +551,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
         * Command id is 0xac for v10 FW along with mesh interface
         * id in bits 14-13-12.
         */
-       if (priv->mesh_fw_ver == MESH_FW_NEW)
+       if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
                command = CMD_MESH_CONFIG |
                          (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
 
index fea9b5d..e257330 100644 (file)
@@ -9,6 +9,8 @@
 #include <net/lib80211.h>
 
 
+#ifdef CONFIG_LIBERTAS_MESH
+
 /* Mesh statistics */
 struct lbs_mesh_stats {
        u32     fwd_bcast_cnt;          /* Fwd: Broadcast counter */
@@ -46,11 +48,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
 /* Command handling */
 
 struct cmd_ds_command;
+struct cmd_ds_mesh_access;
+struct cmd_ds_mesh_config;
 
 int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
        u16 cmd_action, void *pdata_buf);
 int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
        u16 cmd_action, void *pdata_buf);
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+                   struct cmd_ds_mesh_access *cmd);
+int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type);
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
 
 
 /* Persistent configuration */
@@ -75,4 +86,25 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
        uint32_t stringset, uint8_t *s);
 
 
+/* Accessors */
+
+#define lbs_mesh_open(priv) (priv->mesh_open)
+#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
+
+#else
+
+#define lbs_init_mesh(priv)
+#define lbs_deinit_mesh(priv)
+#define lbs_add_mesh(priv)
+#define lbs_remove_mesh(priv)
+#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
+#define lbs_mesh_set_txpd(priv, dev, txpd)
+#define lbs_mesh_config(priv, enable, chan)
+#define lbs_mesh_open(priv) (0)
+#define lbs_mesh_connected(priv) (0)
+
+#endif
+
+
+
 #endif
index c6a6c04..4a0c3e3 100644 (file)
@@ -640,7 +640,7 @@ out:
                if (!priv->tx_pending_len)
                        netif_wake_queue(priv->dev);
        }
-       if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
+       if (priv->mesh_dev && lbs_mesh_connected(priv)) {
                netif_carrier_on(priv->mesh_dev);
                if (!priv->tx_pending_len)
                        netif_wake_queue(priv->mesh_dev);
index 315d1ce..52d244e 100644 (file)
@@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
        if (priv->connect_status == LBS_CONNECTED)
                netif_wake_queue(priv->dev);
 
-       if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
+       if (priv->mesh_dev && lbs_mesh_connected(priv))
                netif_wake_queue(priv->mesh_dev);
 }
 EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
index 4b1aab5..71f88a0 100644 (file)
@@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
        lbs_deb_enter(LBS_DEB_WEXT);
 
        if ((priv->connect_status != LBS_CONNECTED) &&
-               (priv->mesh_connect_status != LBS_CONNECTED))
+               !lbs_mesh_connected(priv))
                memcpy(rates, lbs_bg_rates, MAX_RATES);
        else
                memcpy(rates, priv->curbssparams.rates, MAX_RATES);
@@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
        return 0;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
                         struct iw_point *dwrq, char *extra)
 {
@@ -307,7 +308,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
 
        /* Use nickname to indicate that mesh is on */
 
-       if (priv->mesh_connect_status == LBS_CONNECTED) {
+       if (lbs_mesh_connected(priv)) {
                strncpy(extra, "Mesh", 12);
                extra[12] = '\0';
                dwrq->length = strlen(extra);
@@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
        lbs_deb_leave(LBS_DEB_WEXT);
        return 0;
 }
+#endif
 
 static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
                        struct iw_param *vwrq, char *extra)
@@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev,
        return 0;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int mesh_wlan_get_mode(struct net_device *dev,
                              struct iw_request_info *info, u32 * uwrq,
                              char *extra)
@@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,
        lbs_deb_leave(LBS_DEB_WEXT);
        return 0;
 }
+#endif
 
 static int lbs_get_txpow(struct net_device *dev,
                          struct iw_request_info *info,
@@ -863,7 +867,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 
        /* If we're not associated, all quality values are meaningless */
        if ((priv->connect_status != LBS_CONNECTED) &&
-           (priv->mesh_connect_status != LBS_CONNECTED))
+           !lbs_mesh_connected(priv))
                goto out;
 
        /* Quality by RSSI */
@@ -1010,6 +1014,7 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int lbs_mesh_set_freq(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_freq *fwrq, char *extra)
@@ -1061,6 +1066,7 @@ out:
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
        return ret;
 }
+#endif
 
 static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
                  struct iw_param *vwrq, char *extra)
@@ -2108,6 +2114,7 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int lbs_mesh_get_essid(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *dwrq, char *extra)
@@ -2161,6 +2168,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
        return ret;
 }
+#endif
 
 /**
  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
@@ -2267,7 +2275,13 @@ static const iw_handler lbs_handler[] = {
        (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
        (iw_handler) NULL,              /* SIOCSIWPMKSA */
 };
+struct iw_handler_def lbs_handler_def = {
+       .num_standard   = ARRAY_SIZE(lbs_handler),
+       .standard       = (iw_handler *) lbs_handler,
+       .get_wireless_stats = lbs_get_wireless_stats,
+};
 
+#ifdef CONFIG_LIBERTAS_MESH
 static const iw_handler mesh_wlan_handler[] = {
        (iw_handler) NULL,      /* SIOCSIWCOMMIT */
        (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
@@ -2325,14 +2339,10 @@ static const iw_handler mesh_wlan_handler[] = {
        (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
        (iw_handler) NULL,              /* SIOCSIWPMKSA */
 };
-struct iw_handler_def lbs_handler_def = {
-       .num_standard   = ARRAY_SIZE(lbs_handler),
-       .standard       = (iw_handler *) lbs_handler,
-       .get_wireless_stats = lbs_get_wireless_stats,
-};
 
 struct iw_handler_def mesh_handler_def = {
        .num_standard   = ARRAY_SIZE(mesh_wlan_handler),
        .standard       = (iw_handler *) mesh_wlan_handler,
        .get_wireless_stats = lbs_get_wireless_stats,
 };
+#endif
index 88e4117..718a5f1 100644 (file)
@@ -436,6 +436,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
 }
 
 
+struct mac80211_hwsim_addr_match_data {
+       bool ret;
+       const u8 *addr;
+};
+
+static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
+                                    struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_addr_match_data *md = data;
+       if (memcmp(mac, md->addr, ETH_ALEN) == 0)
+               md->ret = true;
+}
+
+
+static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
+                                     const u8 *addr)
+{
+       struct mac80211_hwsim_addr_match_data md;
+
+       if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0)
+               return true;
+
+       md.ret = false;
+       md.addr = addr;
+       ieee80211_iterate_active_interfaces_atomic(data->hw,
+                                                  mac80211_hwsim_addr_iter,
+                                                  &md);
+
+       return md.ret;
+}
+
+
 static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                                    struct sk_buff *skb)
 {
@@ -488,8 +520,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                if (nskb == NULL)
                        continue;
 
-               if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
-                          ETH_ALEN) == 0)
+               if (mac80211_hwsim_addr_match(data2, hdr->addr1))
                        ack = true;
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
                ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -618,12 +649,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
-
-       printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
+       static const char *chantypes[4] = {
+               [NL80211_CHAN_NO_HT] = "noht",
+               [NL80211_CHAN_HT20] = "ht20",
+               [NL80211_CHAN_HT40MINUS] = "ht40-",
+               [NL80211_CHAN_HT40PLUS] = "ht40+",
+       };
+       static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
+               [IEEE80211_SMPS_AUTOMATIC] = "auto",
+               [IEEE80211_SMPS_OFF] = "off",
+               [IEEE80211_SMPS_STATIC] = "static",
+               [IEEE80211_SMPS_DYNAMIC] = "dynamic",
+       };
+
+       printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
               wiphy_name(hw->wiphy), __func__,
               conf->channel->center_freq,
+              chantypes[conf->channel_type],
               !!(conf->flags & IEEE80211_CONF_IDLE),
-              !!(conf->flags & IEEE80211_CONF_PS));
+              !!(conf->flags & IEEE80211_CONF_PS),
+              smps_modes[conf->smps_mode]);
 
        data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
@@ -827,6 +872,31 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
 }
 #endif
 
+static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      enum ieee80211_ampdu_mlme_action action,
+                                      struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       switch (action) {
+       case IEEE80211_AMPDU_TX_START:
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               break;
+       case IEEE80211_AMPDU_RX_START:
+       case IEEE80211_AMPDU_RX_STOP:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -841,6 +911,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
        .set_tim = mac80211_hwsim_set_tim,
        .conf_tx = mac80211_hwsim_conf_tx,
        CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
+       .ampdu_action = mac80211_hwsim_ampdu_action,
 };
 
 
@@ -1082,7 +1153,9 @@ static int __init init_mac80211_hwsim(void)
                        BIT(NL80211_IFTYPE_MESH_POINT);
 
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
-                           IEEE80211_HW_SIGNAL_DBM;
+                           IEEE80211_HW_SIGNAL_DBM |
+                           IEEE80211_HW_SUPPORTS_STATIC_SMPS |
+                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index 2ecbedb..305c106 100644 (file)
@@ -2594,23 +2594,9 @@ end:
 /*
  * driver/device initialization
  */
-static int bcm4320a_early_init(struct usbnet *usbdev)
-{
-       /* bcm4320a doesn't handle configuration parameters well. Try
-        * set any and you get partially zeroed mac and broken device.
-        */
-
-       return 0;
-}
-
-static int bcm4320b_early_init(struct usbnet *usbdev)
+static void rndis_copy_module_params(struct usbnet *usbdev)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-       char buf[8];
-
-       /* Early initialization settings, setting these won't have effect
-        * if called after generic_rndis_bind().
-        */
 
        priv->param_country[0] = modparam_country[0];
        priv->param_country[1] = modparam_country[1];
@@ -2652,6 +2638,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
                priv->param_workaround_interval = 500;
        else
                priv->param_workaround_interval = modparam_workaround_interval;
+}
+
+static int bcm4320a_early_init(struct usbnet *usbdev)
+{
+       /* copy module parameters for bcm4320a so that iwconfig reports txpower
+        * and workaround parameter is copied to private structure correctly.
+        */
+       rndis_copy_module_params(usbdev);
+
+       /* bcm4320a doesn't handle configuration parameters well. Try
+        * set any and you get partially zeroed mac and broken device.
+        */
+
+       return 0;
+}
+
+static int bcm4320b_early_init(struct usbnet *usbdev)
+{
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+       char buf[8];
+
+       rndis_copy_module_params(usbdev);
+
+       /* Early initialization settings, setting these won't have effect
+        * if called after generic_rndis_bind().
+        */
 
        rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
        rndis_set_config_parameter_str(usbdev, "FrameBursting",
index dfc886f..458378c 100644 (file)
@@ -835,7 +835,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *rxd = entry_priv->desc;
        __le32 *rxwi = (__le32 *)entry->skb->data;
@@ -883,10 +882,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
        if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
+       if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
 
        if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
                rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -927,7 +924,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
         * Remove TXWI descriptor from start of buffer.
         */
        skb_pull(entry->skb, RXWI_DESC_SIZE);
-       skb_trim(entry->skb, rxdesc->size);
 }
 
 /*
index af85d18..40295b4 100644 (file)
@@ -295,9 +295,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
        rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
-       /* Don't use bulk in aggregation when working with USB 1.1 */
-       rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN,
-                          (rt2x00dev->rx->usb_maxpacket == 512));
+       rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
        /*
         * Total room for RX frames in kilobytes, PBF might still exceed
@@ -573,41 +571,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-       __le32 *rxd = (__le32 *)entry->skb->data;
+       __le32 *rxi = (__le32 *)entry->skb->data;
        __le32 *rxwi;
-       u32 rxd0;
+       __le32 *rxd;
+       u32 rxi0;
        u32 rxwi0;
        u32 rxwi1;
        u32 rxwi2;
        u32 rxwi3;
+       u32 rxd0;
+       int rx_pkt_len;
+
+       /*
+        * RX frame format is :
+        * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
+        *          |<------------ rx_pkt_len -------------->|
+        */
+       rt2x00_desc_read(rxi, 0, &rxi0);
+       rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
+
+       rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
+
+       /*
+        * FIXME : we need to check for rx_pkt_len validity
+        */
+       rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
 
        /*
         * Copy descriptor to the skbdesc->desc buffer, making it safe from
         * moving of frame data in rt2x00usb.
         */
-       memcpy(skbdesc->desc, rxd, skbdesc->desc_len);
-       rxd = (__le32 *)skbdesc->desc;
-       rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)];
+       memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
 
        /*
         * It is now safe to read the descriptor on all architectures.
         */
-       rt2x00_desc_read(rxd, 0, &rxd0);
        rt2x00_desc_read(rxwi, 0, &rxwi0);
        rt2x00_desc_read(rxwi, 1, &rxwi1);
        rt2x00_desc_read(rxwi, 2, &rxwi2);
        rt2x00_desc_read(rxwi, 3, &rxwi3);
+       rt2x00_desc_read(rxd, 0, &rxd0);
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR))
+       if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
        if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
                rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
                rxdesc->cipher_status =
-                   rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR);
+                   rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
        }
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) {
+       if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
                 * decryption. Unfortunately the descriptor doesn't contain
@@ -622,13 +636,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                        rxdesc->flags |= RX_FLAG_MMIC_ERROR;
        }
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS))
+       if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) {
+       if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
 
        if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
                rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -663,7 +675,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
         * Remove RXWI descriptor from start of buffer.
         */
        skb_pull(entry->skb, skbdesc->desc_len);
-       skb_trim(entry->skb, rxdesc->size);
 }
 
 /*
index 1e4340a..d1d8ae9 100644 (file)
@@ -79,6 +79,8 @@
  */
 #define TXINFO_DESC_SIZE               ( 1 * sizeof(__le32) )
 #define RXINFO_DESC_SIZE               ( 1 * sizeof(__le32) )
+#define RXWI_DESC_SIZE                 ( 4 * sizeof(__le32) )
+#define RXD_DESC_SIZE                  ( 1 * sizeof(__le32) )
 
 /*
  * TX Info structure
 #define TXINFO_W0_USB_DMA_NEXT_VALID   FIELD32(0x40000000)
 #define TXINFO_W0_USB_DMA_TX_BURST     FIELD32(0x80000000)
 
+/*
+ * RX Info structure
+ */
+
+/*
+ * Word 0
+ */
+
+#define RXINFO_W0_USB_DMA_RX_PKT_LEN   FIELD32(0x0000ffff)
+
+/*
+ * RX WI structure
+ */
+
+/*
+ * Word0
+ */
+#define RXWI_W0_WIRELESS_CLI_ID                FIELD32(0x000000ff)
+#define RXWI_W0_KEY_INDEX              FIELD32(0x00000300)
+#define RXWI_W0_BSSID                  FIELD32(0x00001c00)
+#define RXWI_W0_UDF                    FIELD32(0x0000e000)
+#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT  FIELD32(0x0fff0000)
+#define RXWI_W0_TID                    FIELD32(0xf0000000)
+
+/*
+ * Word1
+ */
+#define RXWI_W1_FRAG                   FIELD32(0x0000000f)
+#define RXWI_W1_SEQUENCE               FIELD32(0x0000fff0)
+#define RXWI_W1_MCS                    FIELD32(0x007f0000)
+#define RXWI_W1_BW                     FIELD32(0x00800000)
+#define RXWI_W1_SHORT_GI               FIELD32(0x01000000)
+#define RXWI_W1_STBC                   FIELD32(0x06000000)
+#define RXWI_W1_PHYMODE                        FIELD32(0xc0000000)
+
+/*
+ * Word2
+ */
+#define RXWI_W2_RSSI0                  FIELD32(0x000000ff)
+#define RXWI_W2_RSSI1                  FIELD32(0x0000ff00)
+#define RXWI_W2_RSSI2                  FIELD32(0x00ff0000)
+
+/*
+ * Word3
+ */
+#define RXWI_W3_SNR0                   FIELD32(0x000000ff)
+#define RXWI_W3_SNR1                   FIELD32(0x0000ff00)
+
 /*
  * RX descriptor format for RX Ring.
  */
  * AMSDU: rx with 802.3 header, not 802.11 header.
  */
 
-#define RXINFO_W0_BA                   FIELD32(0x00000001)
-#define RXINFO_W0_DATA                 FIELD32(0x00000002)
-#define RXINFO_W0_NULLDATA             FIELD32(0x00000004)
-#define RXINFO_W0_FRAG                 FIELD32(0x00000008)
-#define RXINFO_W0_UNICAST_TO_ME                FIELD32(0x00000010)
-#define RXINFO_W0_MULTICAST            FIELD32(0x00000020)
-#define RXINFO_W0_BROADCAST            FIELD32(0x00000040)
-#define RXINFO_W0_MY_BSS               FIELD32(0x00000080)
-#define RXINFO_W0_CRC_ERROR            FIELD32(0x00000100)
-#define RXINFO_W0_CIPHER_ERROR         FIELD32(0x00000600)
-#define RXINFO_W0_AMSDU                        FIELD32(0x00000800)
-#define RXINFO_W0_HTC                  FIELD32(0x00001000)
-#define RXINFO_W0_RSSI                 FIELD32(0x00002000)
-#define RXINFO_W0_L2PAD                        FIELD32(0x00004000)
-#define RXINFO_W0_AMPDU                        FIELD32(0x00008000)
-#define RXINFO_W0_DECRYPTED            FIELD32(0x00010000)
-#define RXINFO_W0_PLCP_RSSI            FIELD32(0x00020000)
-#define RXINFO_W0_CIPHER_ALG           FIELD32(0x00040000)
-#define RXINFO_W0_LAST_AMSDU           FIELD32(0x00080000)
-#define RXINFO_W0_PLCP_SIGNAL          FIELD32(0xfff00000)
+#define RXD_W0_BA                      FIELD32(0x00000001)
+#define RXD_W0_DATA                    FIELD32(0x00000002)
+#define RXD_W0_NULLDATA                        FIELD32(0x00000004)
+#define RXD_W0_FRAG                    FIELD32(0x00000008)
+#define RXD_W0_UNICAST_TO_ME           FIELD32(0x00000010)
+#define RXD_W0_MULTICAST               FIELD32(0x00000020)
+#define RXD_W0_BROADCAST               FIELD32(0x00000040)
+#define RXD_W0_MY_BSS                  FIELD32(0x00000080)
+#define RXD_W0_CRC_ERROR               FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR            FIELD32(0x00000600)
+#define RXD_W0_AMSDU                   FIELD32(0x00000800)
+#define RXD_W0_HTC                     FIELD32(0x00001000)
+#define RXD_W0_RSSI                    FIELD32(0x00002000)
+#define RXD_W0_L2PAD                   FIELD32(0x00004000)
+#define RXD_W0_AMPDU                   FIELD32(0x00008000)
+#define RXD_W0_DECRYPTED               FIELD32(0x00010000)
+#define RXD_W0_PLCP_RSSI               FIELD32(0x00020000)
+#define RXD_W0_CIPHER_ALG              FIELD32(0x00040000)
+#define RXD_W0_LAST_AMSDU              FIELD32(0x00080000)
+#define RXD_W0_PLCP_SIGNAL             FIELD32(0xfff00000)
 
 #endif /* RT2800USB_H */
index 4d841c0..194dae0 100644 (file)
 #define GET_DURATION(__size, __rate)   (((__size) * 8 * 10) / (__rate))
 #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
 
+/*
+ * Determine the number of L2 padding bytes required between the header and
+ * the payload.
+ */
+#define L2PAD_SIZE(__hdrlen)   (-(__hdrlen) & 3)
+
 /*
  * Determine the alignment requirement,
  * to make sure the 802.11 payload is padded to a 4-byte boundrary
index 06c43ca..d7711e4 100644 (file)
@@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
        memset(&rxdesc, 0, sizeof(rxdesc));
        rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
 
-       /* Trim buffer to correct size */
-       skb_trim(entry->skb, rxdesc.size);
-
        /*
         * The data behind the ieee80211 header must be
         * aligned on a 4 byte boundary.
@@ -404,11 +401,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
            (rxdesc.flags & RX_FLAG_IV_STRIPPED))
                rt2x00crypto_rx_insert_iv(entry->skb, header_length,
                                          &rxdesc);
-       else if (rxdesc.dev_flags & RXDONE_L2PAD)
+       else if (header_length &&
+                (rxdesc.size > header_length) &&
+                (rxdesc.dev_flags & RXDONE_L2PAD))
                rt2x00queue_remove_l2pad(entry->skb, header_length);
        else
                rt2x00queue_align_payload(entry->skb, header_length);
 
+       /* Trim buffer to correct size */
+       skb_trim(entry->skb, rxdesc.size);
+
        /*
         * Check if the frame was received using HT. In that case,
         * the rate is the MCS index and should be passed to mac80211
index 0feb4d0..801be43 100644 (file)
@@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
 {
        unsigned int i;
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return 0;
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
                rt2x00pci_register_read(rt2x00dev, offset, reg);
                if (!rt2x00_get_field32(*reg, field))
index 239afc7..3d8fb68 100644 (file)
@@ -177,55 +177,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
 
 void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       unsigned int frame_length = skb->len;
+       unsigned int payload_length = skb->len - header_length;
        unsigned int header_align = ALIGN_SIZE(skb, 0);
        unsigned int payload_align = ALIGN_SIZE(skb, header_length);
-       unsigned int l2pad = 4 - (payload_align - header_align);
+       unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
 
-       if (header_align == payload_align) {
-               /*
-                * Both header and payload must be moved the same
-                * amount of bytes to align them properly. This means
-                * we don't use the L2 padding but just move the entire
-                * frame.
-                */
-               rt2x00queue_align_frame(skb);
-       } else if (!payload_align) {
-               /*
-                * Simple L2 padding, only the header needs to be moved,
-                * the payload is already properly aligned.
-                */
-               skb_push(skb, header_align);
-               memmove(skb->data, skb->data + header_align, frame_length);
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       } else {
-               /*
-                *
-                * Complicated L2 padding, both header and payload need
-                * to be moved. By default we only move to the start
-                * of the buffer, so our header alignment needs to be
-                * increased if there is not enough room for the header
-                * to be moved.
-                */
-               if (payload_align > header_align)
-                       header_align += 4;
+       /*
+        * Adjust the header alignment if the payload needs to be moved more
+        * than the header.
+        */
+       if (payload_align > header_align)
+               header_align += 4;
+
+       /* There is nothing to do if no alignment is needed */
+       if (!header_align)
+               return;
+
+       /* Reserve the amount of space needed in front of the frame */
+       skb_push(skb, header_align);
+
+       /*
+        * Move the header.
+        */
+       memmove(skb->data, skb->data + header_align, header_length);
 
-               skb_push(skb, header_align);
-               memmove(skb->data, skb->data + header_align, header_length);
+       /* Move the payload, if present and if required */
+       if (payload_length && payload_align)
                memmove(skb->data + header_length + l2pad,
                        skb->data + header_length + l2pad + payload_align,
-                       frame_length - header_length);
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
+                       payload_length);
+
+       /* Trim the skb to the correct size */
+       skb_trim(skb, header_length + l2pad + payload_length);
 }
 
 void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       unsigned int l2pad = 4 - (header_length & 3);
+       unsigned int l2pad = L2PAD_SIZE(header_length);
 
-       if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
+       if (!l2pad)
                return;
 
        memmove(skb->data + l2pad, skb->data, header_length);
@@ -346,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
         * Header and alignment information.
         */
        txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-       txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length);
+       if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) &&
+           (entry->skb->len > txdesc->header_length))
+               txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);
 
        /*
         * Check whether this frame is to be acked.
@@ -387,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 
        /*
         * Beacons and probe responses require the tsf timestamp
-        * to be inserted into the frame.
+        * to be inserted into the frame, except for a frame that has been injected
+        * through a monitor interface. This latter is needed for testing a
+        * monitor interface.
         */
-       if (ieee80211_is_beacon(hdr->frame_control) ||
-           ieee80211_is_probe_resp(hdr->frame_control))
+       if ((ieee80211_is_beacon(hdr->frame_control) ||
+           ieee80211_is_probe_resp(hdr->frame_control)) &&
+           (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
                __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
 
        /*
index 70775e5..c1e482b 100644 (file)
@@ -92,8 +92,6 @@ enum data_queue_qid {
  * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
  * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
  *     mac80211 but was stripped for processing by the driver.
- * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
- *     the padded bytes are located between header and payload.
  * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
  *     don't try to pass it back.
  */
@@ -101,8 +99,7 @@ enum skb_frame_desc_flags {
        SKBDESC_DMA_MAPPED_RX = 1 << 0,
        SKBDESC_DMA_MAPPED_TX = 1 << 1,
        SKBDESC_IV_STRIPPED = 1 << 2,
-       SKBDESC_L2_PADDED = 1 << 3,
-       SKBDESC_NOT_MAC80211 = 1 << 4,
+       SKBDESC_NOT_MAC80211 = 1 << 3,
 };
 
 /**
index ced3b6a..6ce88d3 100644 (file)
@@ -2354,6 +2354,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
index a1a3dd1..8a40a14 100644 (file)
@@ -132,7 +132,6 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 
                        rx_status.antenna = (flags2 >> 15) & 1;
                        /* TODO: improve signal/rssi reporting */
-                       rx_status.qual = flags2 & 0xFF;
                        rx_status.signal = (flags2 >> 8) & 0x7F;
                        /* XXX: is this correct? */
                        rx_status.rate_idx = (flags >> 20) & 0xF;
index 054533f..6301578 100644 (file)
@@ -247,6 +247,7 @@ struct wl1251_debugfs {
        struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
 
        struct dentry *tx_queue_len;
+       struct dentry *tx_queue_status;
 
        struct dentry *retry_count;
        struct dentry *excessive_retries;
index acfa086..beff084 100644 (file)
@@ -976,3 +976,72 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop)
+{
+       struct wl1251_acx_ac_cfg *acx;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
+                    "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->ac = ac;
+       acx->cw_min = cw_min;
+       acx->cw_max = cw_max;
+       acx->aifsn = aifs;
+       acx->txop_limit = txop;
+
+       ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("acx ac cfg failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+                      enum wl1251_acx_channel_type type,
+                      u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+                      enum wl1251_acx_ack_policy ack_policy)
+{
+       struct wl1251_acx_tid_cfg *acx;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d "
+                    "ps_scheme %d ack_policy %d", queue, type, tsid,
+                    ps_scheme, ack_policy);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->queue = queue;
+       acx->type = type;
+       acx->tsid = tsid;
+       acx->ps_scheme = ps_scheme;
+       acx->ack_policy = ack_policy;
+
+       ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("acx tid cfg failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 6523714..26160c4 100644 (file)
@@ -1166,6 +1166,87 @@ struct wl1251_acx_wr_tbtt_and_dtim {
        u8  padding;
 } __attribute__ ((packed));
 
+struct wl1251_acx_ac_cfg {
+       struct acx_header header;
+
+       /*
+        * Access Category - The TX queue's access category
+        * (refer to AccessCategory_enum)
+        */
+       u8 ac;
+
+       /*
+        * The contention window minimum size (in slots) for
+        * the access class.
+        */
+       u8 cw_min;
+
+       /*
+        * The contention window maximum size (in slots) for
+        * the access class.
+        */
+       u16 cw_max;
+
+       /* The AIF value (in slots) for the access class. */
+       u8 aifsn;
+
+       u8 reserved;
+
+       /* The TX Op Limit (in microseconds) for the access class. */
+       u16 txop_limit;
+} __attribute__ ((packed));
+
+
+enum wl1251_acx_channel_type {
+       CHANNEL_TYPE_DCF        = 0,
+       CHANNEL_TYPE_EDCF       = 1,
+       CHANNEL_TYPE_HCCA       = 2,
+};
+
+enum wl1251_acx_ps_scheme {
+       /* regular ps: simple sending of packets */
+       WL1251_ACX_PS_SCHEME_LEGACY     = 0,
+
+       /* sending a packet triggers a unscheduled apsd downstream */
+       WL1251_ACX_PS_SCHEME_UPSD_TRIGGER       = 1,
+
+       /* a pspoll packet will be sent before every data packet */
+       WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL      = 2,
+
+       /* scheduled apsd mode */
+       WL1251_ACX_PS_SCHEME_SAPSD              = 3,
+};
+
+enum wl1251_acx_ack_policy {
+       WL1251_ACX_ACK_POLICY_LEGACY    = 0,
+       WL1251_ACX_ACK_POLICY_NO_ACK    = 1,
+       WL1251_ACX_ACK_POLICY_BLOCK     = 2,
+};
+
+struct wl1251_acx_tid_cfg {
+       struct acx_header header;
+
+       /* tx queue id number (0-7) */
+       u8 queue;
+
+       /* channel access type for the queue, enum wl1251_acx_channel_type */
+       u8 type;
+
+       /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */
+       u8 tsid;
+
+       /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */
+       u8 ps_scheme;
+
+       /* the tx queue ack policy, enum wl1251_acx_ack_policy */
+       u8 ack_policy;
+
+       u8 padding[3];
+
+       /* not supported */
+       u32 apsdconf[2];
+} __attribute__ ((packed));
+
 /*************************************************************************
 
     Host Interrupt Register (WiLink -> Host)
@@ -1322,5 +1403,11 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
 int wl1251_acx_rate_policies(struct wl1251 *wl);
 int wl1251_acx_mem_cfg(struct wl1251 *wl);
 int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop);
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+                      enum wl1251_acx_channel_type type,
+                      u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+                      enum wl1251_acx_ack_policy ack_policy);
 
 #endif /* __WL1251_ACX_H__ */
index a007230..0ccba57 100644 (file)
@@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = {
        .open = wl1251_open_file_generic,
 };
 
+static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wl1251 *wl = file->private_data;
+       char buf[3], status;
+       int len;
+
+       if (wl->tx_queue_stopped)
+               status = 's';
+       else
+               status = 'r';
+
+       len = scnprintf(buf, sizeof(buf), "%c\n", status);
+       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations tx_queue_status_ops = {
+       .read = tx_queue_status_read,
+       .open = wl1251_open_file_generic,
+};
+
 static void wl1251_debugfs_delete_files(struct wl1251 *wl)
 {
        DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl)
        DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
 
        DEBUGFS_DEL(tx_queue_len);
+       DEBUGFS_DEL(tx_queue_status);
        DEBUGFS_DEL(retry_count);
        DEBUGFS_DEL(excessive_retries);
 }
@@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl)
        DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
 
        DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
+       DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir);
        DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
        DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
 
index 5cb5733..5aad56e 100644 (file)
@@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
                        goto out;
        }
 
+       wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
+       wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
+       wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
+       wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
+
 out:
        kfree(config);
        return ret;
index b3b25ec..269cefb 100644 (file)
 
 #include "wl1251.h"
 
+enum {
+       /* best effort/legacy */
+       AC_BE = 0,
+
+       /* background */
+       AC_BK = 1,
+
+       /* video */
+       AC_VI = 2,
+
+       /* voice */
+       AC_VO = 3,
+
+       /* broadcast dummy access category */
+       AC_BCAST = 4,
+
+       NUM_ACCESS_CATEGORIES = 4
+};
+
+/* following are defult values for the IE fields*/
+#define CWMIN_BK  15
+#define CWMIN_BE  15
+#define CWMIN_VI  7
+#define CWMIN_VO  3
+#define CWMAX_BK  1023
+#define CWMAX_BE  63
+#define CWMAX_VI  15
+#define CWMAX_VO  7
+
+/* slot number setting to start transmission at PIFS interval */
+#define AIFS_PIFS 1
+
+/*
+ * slot number setting to start transmission at DIFS interval - normal DCF
+ * access
+ */
+#define AIFS_DIFS 2
+
+#define AIFSN_BK  7
+#define AIFSN_BE  3
+#define AIFSN_VI  AIFS_PIFS
+#define AIFSN_VO  AIFS_PIFS
+#define TXOP_BK   0
+#define TXOP_BE   0
+#define TXOP_VI   3008
+#define TXOP_VO   1504
+
 int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
 int wl1251_hw_init_templates_config(struct wl1251 *wl);
 int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
index 2f50a25..6aeffbe 100644 (file)
@@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * the queue here, otherwise the queue will get too long.
         */
        if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+               wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
                ieee80211_stop_queues(wl->hw);
 
                /*
@@ -640,20 +641,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                 * through the bss_info_changed() hook.
                 */
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               if (ret < 0)
+                       goto out_sleep;
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm disabled");
 
                wl->psm_requested = false;
 
-               if (wl->psm)
+               if (wl->psm) {
                        ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+                       if (ret < 0)
+                               goto out_sleep;
+               }
        }
 
        if (conf->power_level != wl->power_level) {
                ret = wl1251_acx_tx_power(wl, conf->power_level);
                if (ret < 0)
-                       goto out;
+                       goto out_sleep;
 
                wl->power_level = conf->power_level;
        }
@@ -1273,6 +1279,43 @@ static struct ieee80211_channel wl1251_channels[] = {
        { .hw_value = 13, .center_freq = 2472},
 };
 
+static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                            const struct ieee80211_tx_queue_params *params)
+{
+       struct wl1251 *wl = hw->priv;
+       int ret;
+
+       mutex_lock(&wl->mutex);
+
+       wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue),
+                               params->cw_min, params->cw_max,
+                               params->aifs, params->txop);
+       if (ret < 0)
+               goto out_sleep;
+
+       ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue),
+                                CHANNEL_TYPE_EDCF,
+                                wl1251_tx_get_queue(queue),
+                                WL1251_ACX_PS_SCHEME_LEGACY,
+                                WL1251_ACX_ACK_POLICY_LEGACY);
+       if (ret < 0)
+               goto out_sleep;
+
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+
+       return ret;
+}
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1251_band_2ghz = {
        .channels = wl1251_channels,
@@ -1293,6 +1336,7 @@ static const struct ieee80211_ops wl1251_ops = {
        .hw_scan = wl1251_op_hw_scan,
        .bss_info_changed = wl1251_op_bss_info_changed,
        .set_rts_threshold = wl1251_op_set_rts_threshold,
+       .conf_tx = wl1251_op_conf_tx,
 };
 
 static int wl1251_register_hw(struct wl1251 *wl)
@@ -1338,6 +1382,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
        wl->hw->wiphy->max_scan_ssids = 1;
        wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
 
+       wl->hw->queues = 4;
+
        ret = wl1251_register_hw(wl);
        if (ret)
                goto out;
index 9931b19..851dfb6 100644 (file)
@@ -26,7 +26,8 @@
 #include "wl1251_cmd.h"
 #include "wl1251_io.h"
 
-#define WL1251_WAKEUP_TIMEOUT 2000
+/* in ms */
+#define WL1251_WAKEUP_TIMEOUT 100
 
 void wl1251_elp_work(struct work_struct *work)
 {
@@ -67,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
 
 int wl1251_ps_elp_wakeup(struct wl1251 *wl)
 {
-       unsigned long timeout;
+       unsigned long timeout, start;
        u32 elp_reg;
 
        if (!wl->elp)
@@ -75,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
 
        wl1251_debug(DEBUG_PSM, "waking up chip from elp");
 
+       start = jiffies;
        timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
 
        wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
@@ -95,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
        }
 
        wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
-                    jiffies_to_msecs(jiffies) -
-                    (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
+                    jiffies_to_msecs(jiffies - start));
 
        wl->elp = false;
 
index f84cc89..b567322 100644 (file)
@@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
        if (wl->rx_current_buffer)
                rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
 
-       skb = dev_alloc_skb(length);
+       skb = __dev_alloc_skb(length, GFP_KERNEL);
        if (!skb) {
                wl1251_error("Couldn't allocate RX frame");
                return;
index f859706..c822318 100644 (file)
@@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
        tx_hdr->expiry_time = cpu_to_le32(1 << 16);
        tx_hdr->id = id;
 
-       /* FIXME: how to get the correct queue id? */
-       tx_hdr->xmit_queue = 0;
+       tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb));
 
        wl1251_tx_control(tx_hdr, control, fc);
        wl1251_tx_frag_block_num(tx_hdr);
@@ -220,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
                        /* align the buffer on a 4-byte boundary */
                        skb_reserve(skb, offset);
                        memmove(skb->data, src, skb->len);
+                       tx_hdr = (struct tx_double_buffer_desc *) skb->data;
                } else {
                        wl1251_info("No handler, fixme!");
                        return -EINVAL;
@@ -237,8 +237,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
 
        wl1251_mem_write(wl, addr, skb->data, len);
 
-       wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
-                    tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
+       wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x "
+                    "queue %d", tx_hdr->id, skb, tx_hdr->length,
+                    tx_hdr->rate, tx_hdr->xmit_queue);
 
        return 0;
 }
index 7c1c166..55856c6 100644 (file)
@@ -26,6 +26,7 @@
 #define __WL1251_TX_H__
 
 #include <linux/bitops.h>
+#include "wl1251_acx.h"
 
 /*
  *
@@ -209,6 +210,22 @@ struct tx_result {
        u8 done_2;
 } __attribute__ ((packed));
 
+static inline int wl1251_tx_get_queue(int queue)
+{
+       switch (queue) {
+       case 0:
+               return QOS_AC_VO;
+       case 1:
+               return QOS_AC_VI;
+       case 2:
+               return QOS_AC_BE;
+       case 3:
+               return QOS_AC_BK;
+       default:
+               return QOS_AC_BE;
+       }
+}
+
 void wl1251_tx_work(struct work_struct *work);
 void wl1251_tx_complete(struct wl1251 *wl);
 void wl1251_tx_flush(struct wl1251 *wl);
index ac19ecd..4daf1c9 100644 (file)
@@ -1078,11 +1078,15 @@ static int eject_installer(struct usb_interface *intf)
        int r;
 
        /* Find bulk out endpoint */
-       endpoint = &iface_desc->endpoint[1].desc;
-       if (usb_endpoint_dir_out(endpoint) &&
-           usb_endpoint_xfer_bulk(endpoint)) {
-               bulk_out_ep = endpoint->bEndpointAddress;
-       } else {
+       for (r = 1; r >= 0; r--) {
+               endpoint = &iface_desc->endpoint[r].desc;
+               if (usb_endpoint_dir_out(endpoint) &&
+                   usb_endpoint_xfer_bulk(endpoint)) {
+                       bulk_out_ep = endpoint->bEndpointAddress;
+                       break;
+               }
+       }
+       if (r == -1) {
                dev_err(&udev->dev,
                        "zd1211rw: Could not find bulk out endpoint\n");
                return -ENODEV;
index 163c840..d62edc7 100644 (file)
@@ -707,6 +707,10 @@ struct ieee80211_mgmt {
                                        u8 action;
                                        u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
                                } __attribute__ ((packed)) sa_query;
+                               struct {
+                                       u8 action;
+                                       u8 smps_control;
+                               } __attribute__ ((packed)) ht_smps;
                        } u;
                } __attribute__ ((packed)) action;
        } u;
@@ -771,7 +775,10 @@ struct ieee80211_bar {
 /**
  * struct ieee80211_mcs_info - MCS information
  * @rx_mask: RX mask
- * @rx_highest: highest supported RX rate
+ * @rx_highest: highest supported RX rate. If set represents
+ *     the highest supported RX data rate in units of 1 Mbps.
+ *     If this field is 0 this value should not be used to
+ *     consider the highest RX data rate supported.
  * @tx_params: TX parameters
  */
 struct ieee80211_mcs_info {
@@ -824,6 +831,7 @@ struct ieee80211_ht_cap {
 #define IEEE80211_HT_CAP_LDPC_CODING           0x0001
 #define IEEE80211_HT_CAP_SUP_WIDTH_20_40       0x0002
 #define IEEE80211_HT_CAP_SM_PS                 0x000C
+#define                IEEE80211_HT_CAP_SM_PS_SHIFT    2
 #define IEEE80211_HT_CAP_GRN_FLD               0x0010
 #define IEEE80211_HT_CAP_SGI_20                        0x0020
 #define IEEE80211_HT_CAP_SGI_40                        0x0040
@@ -839,6 +847,7 @@ struct ieee80211_ht_cap {
 /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
 #define IEEE80211_HT_AMPDU_PARM_FACTOR         0x03
 #define IEEE80211_HT_AMPDU_PARM_DENSITY                0x1C
+#define                IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT   2
 
 /*
  * Maximum length of AMPDU that the STA can receive.
@@ -922,12 +931,17 @@ struct ieee80211_ht_info {
 #define IEEE80211_MAX_AMPDU_BUF 0x40
 
 
-/* Spatial Multiplexing Power Save Modes */
+/* Spatial Multiplexing Power Save Modes (for capability) */
 #define WLAN_HT_CAP_SM_PS_STATIC       0
 #define WLAN_HT_CAP_SM_PS_DYNAMIC      1
 #define WLAN_HT_CAP_SM_PS_INVALID      2
 #define WLAN_HT_CAP_SM_PS_DISABLED     3
 
+/* for SM power control field lower two bits */
+#define WLAN_HT_SMPS_CONTROL_DISABLED  0
+#define WLAN_HT_SMPS_CONTROL_STATIC    1
+#define WLAN_HT_SMPS_CONTROL_DYNAMIC   3
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
@@ -1150,6 +1164,18 @@ enum ieee80211_spectrum_mgmt_actioncode {
        WLAN_ACTION_SPCT_CHL_SWITCH = 4,
 };
 
+/* HT action codes */
+enum ieee80211_ht_actioncode {
+       WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0,
+       WLAN_HT_ACTION_SMPS = 1,
+       WLAN_HT_ACTION_PSMP = 2,
+       WLAN_HT_ACTION_PCO_PHASE = 3,
+       WLAN_HT_ACTION_CSI = 4,
+       WLAN_HT_ACTION_NONCOMPRESSED_BF = 5,
+       WLAN_HT_ACTION_COMPRESSED_BF = 6,
+       WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
+};
+
 /* Security key length */
 enum ieee80211_key_len {
        WLAN_KEY_LEN_WEP40 = 5,
index 0884b9a..542a477 100644 (file)
@@ -1578,7 +1578,7 @@ unsigned int ieee80211_hdrlen(__le16 fc);
  * @addr: the device MAC address
  * @iftype: the virtual interface type
  */
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype);
 
 /**
@@ -1589,9 +1589,27 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
  * @bssid: the network bssid (used only for iftype STATION and ADHOC)
  * @qos: build 802.11 QoS data frame
  */
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype, u8 *bssid, bool qos);
 
+/**
+ * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
+ *
+ * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
+ * 802.3 frames. The @list will be empty if the decode fails. The
+ * @skb is consumed after the function returns.
+ *
+ * @skb: The input IEEE 802.11n A-MSDU frame.
+ * @list: The output list of 802.3 frames. It must be allocated and
+ *     initialized by by the caller.
+ * @addr: The device MAC address.
+ * @iftype: The device interface type.
+ * @extra_headroom: The hardware extra headroom for SKBs in the @list.
+ */
+void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom);
+
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
index 538d6b7..494ac69 100644 (file)
@@ -597,8 +597,10 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed
  * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
+ * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
  */
 enum ieee80211_conf_changed {
+       IEEE80211_CONF_CHANGE_SMPS              = BIT(1),
        IEEE80211_CONF_CHANGE_LISTEN_INTERVAL   = BIT(2),
        IEEE80211_CONF_CHANGE_MONITOR           = BIT(3),
        IEEE80211_CONF_CHANGE_PS                = BIT(4),
@@ -608,6 +610,21 @@ enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_IDLE              = BIT(8),
 };
 
+/**
+ * enum ieee80211_smps_mode - spatial multiplexing power save mode
+ *
+ * @
+ */
+enum ieee80211_smps_mode {
+       IEEE80211_SMPS_AUTOMATIC,
+       IEEE80211_SMPS_OFF,
+       IEEE80211_SMPS_STATIC,
+       IEEE80211_SMPS_DYNAMIC,
+
+       /* keep last */
+       IEEE80211_SMPS_NUM_MODES,
+};
+
 /**
  * struct ieee80211_conf - configuration of the device
  *
@@ -636,6 +653,10 @@ enum ieee80211_conf_changed {
  * @short_frame_max_tx_count: Maximum number of transmissions for a "short"
  *    frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
  *    number of transmissions not the number of retries
+ *
+ * @smps_mode: spatial multiplexing powersave mode; note that
+ *     %IEEE80211_SMPS_STATIC is used when the device is not
+ *     configured for an HT channel
  */
 struct ieee80211_conf {
        u32 flags;
@@ -648,6 +669,7 @@ struct ieee80211_conf {
 
        struct ieee80211_channel *channel;
        enum nl80211_channel_type channel_type;
+       enum ieee80211_smps_mode smps_mode;
 };
 
 /**
@@ -659,12 +681,14 @@ struct ieee80211_conf {
  * @type: type of this virtual interface
  * @bss_conf: BSS configuration for this interface, either our own
  *     or the BSS we're associated to
+ * @addr: address of this interface
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
  */
 struct ieee80211_vif {
        enum nl80211_iftype type;
        struct ieee80211_bss_conf bss_conf;
+       u8 addr[ETH_ALEN];
        /* must be last */
        u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
 };
@@ -928,6 +952,16 @@ enum ieee80211_tkip_key_type {
  * @IEEE80211_HW_BEACON_FILTER:
  *     Hardware supports dropping of irrelevant beacon frames to
  *     avoid waking up cpu.
+ *
+ * @IEEE80211_HW_SUPPORTS_STATIC_SMPS:
+ *     Hardware supports static spatial multiplexing powersave,
+ *     ie. can turn off all but one chain even on HT connections
+ *     that should be using more chains.
+ *
+ * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS:
+ *     Hardware supports dynamic spatial multiplexing powersave,
+ *     ie. can turn off all but one chain and then wake the rest
+ *     up as required after, for example, rts/cts handshake.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -945,6 +979,8 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_DYNAMIC_PS                = 1<<12,
        IEEE80211_HW_MFP_CAPABLE                        = 1<<13,
        IEEE80211_HW_BEACON_FILTER                      = 1<<14,
+       IEEE80211_HW_SUPPORTS_STATIC_SMPS               = 1<<15,
+       IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS              = 1<<16,
 };
 
 /**
@@ -1212,6 +1248,31 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * signal strength threshold checking.
  */
 
+/**
+ * DOC: Spatial multiplexing power save
+ *
+ * SMPS (Spatial multiplexing power save) is a mechanism to conserve
+ * power in an 802.11n implementation. For details on the mechanism
+ * and rationale, please refer to 802.11 (as amended by 802.11n-2009)
+ * "11.2.3 SM power save".
+ *
+ * The mac80211 implementation is capable of sending action frames
+ * to update the AP about the station's SMPS mode, and will instruct
+ * the driver to enter the specific mode. It will also announce the
+ * requested SMPS mode during the association handshake. Hardware
+ * support for this feature is required, and can be indicated by
+ * hardware flags.
+ *
+ * The default mode will be "automatic", which nl80211/cfg80211
+ * defines to be dynamic SMPS in (regular) powersave, and SMPS
+ * turned off otherwise.
+ *
+ * To support this feature, the driver must set the appropriate
+ * hardware support flags, and handle the SMPS flag to the config()
+ * operation. It will then with this mechanism be instructed to
+ * enter the requested SMPS mode while associated to an HT AP.
+ */
+
 /**
  * DOC: Frame filtering
  *
index a10d508..a952b7f 100644 (file)
@@ -96,18 +96,6 @@ menuconfig MAC80211_DEBUG_MENU
        ---help---
          This option collects various mac80211 debug settings.
 
-config MAC80211_DEBUG_PACKET_ALIGNMENT
-       bool "Enable packet alignment debugging"
-       depends on MAC80211_DEBUG_MENU
-       ---help---
-         This option is recommended for driver authors and strongly
-         discouraged for everybody else, it will trigger a warning
-         when a driver hands mac80211 a buffer that is aligned in
-         a way that will cause problems with the IP stack on some
-         architectures.
-
-         Say N unless you're writing a mac80211 based driver.
-
 config MAC80211_NOINLINE
        bool "Do not inline TX/RX handlers"
        depends on MAC80211_DEBUG_MENU
index 51c7dc3..a978e66 100644 (file)
@@ -41,8 +41,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
               sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       if (drv_ampdu_action(local, &sta->sdata->vif,
-                            IEEE80211_AMPDU_RX_STOP,
+       if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
                             &sta->sta, tid, NULL))
                printk(KERN_DEBUG "HW problem - can not stop rx "
                                "aggregation for tid %d\n", tid);
@@ -83,12 +82,11 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
                                        u16 initiator, u16 reason)
 {
-       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -136,7 +134,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
 
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer "
-                      "for addba resp frame\n", sdata->dev->name);
+                      "for addba resp frame\n", sdata->name);
                return;
        }
 
@@ -144,10 +142,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -281,8 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                goto end;
        }
 
-       ret = drv_ampdu_action(local, &sta->sdata->vif,
-                              IEEE80211_AMPDU_RX_START,
+       ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
                               &sta->sta, tid, &start_seq_num);
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
index 5e3a7ec..ceda366 100644 (file)
@@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
-                               "for addba request frame\n", sdata->dev->name);
+                               "for addba request frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer for "
-                       "bar frame\n", sdata->dev->name);
+                       "bar frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
                                         IEEE80211_STYPE_BACK_REQ);
        memcpy(bar->ra, ra, ETH_ALEN);
-       memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
        bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
        bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
        bar_control |= (u16)(tid << 12);
@@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
-       ret = drv_ampdu_action(local, &sta->sdata->vif,
+       ret = drv_ampdu_action(local, sta->sdata,
                               IEEE80211_AMPDU_TX_STOP,
                               &sta->sta, tid, NULL);
 
@@ -303,8 +303,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
 
        start_seq_num = sta->tid_seq[tid];
 
-       ret = drv_ampdu_action(local, &sdata->vif,
-                              IEEE80211_AMPDU_TX_START,
+       ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
                               pubsta, tid, &start_seq_num);
 
        if (ret) {
@@ -420,7 +419,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
        ieee80211_agg_splice_finish(local, sta, tid);
        spin_unlock(&local->ampdu_lock);
 
-       drv_ampdu_action(local, &sta->sdata->vif,
+       drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
                         &sta->sta, tid, NULL);
 }
@@ -441,7 +440,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        }
 
        rcu_read_lock();
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
                rcu_read_unlock();
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -489,7 +488,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
-                              "dropping start BA session", skb->dev->name);
+                              "dropping start BA session", sdata->name);
 #endif
                return;
        }
@@ -564,7 +563,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        rcu_read_lock();
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %pM\n", ra);
@@ -621,7 +620,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
-                              "dropping stop BA session", skb->dev->name);
+                              "dropping stop BA session", sdata->name);
 #endif
                return;
        }
index 6dc3579..63843e3 100644 (file)
@@ -150,7 +150,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get(sdata, mac_addr);
                if (!sta) {
                        ieee80211_key_free(key);
                        err = -ENOENT;
@@ -181,7 +181,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
        if (mac_addr) {
                ret = -ENOENT;
 
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get(sdata, mac_addr);
                if (!sta)
                        goto out_unlock;
 
@@ -228,7 +228,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get(sdata, mac_addr);
                if (!sta)
                        goto out;
 
@@ -415,15 +415,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
        int ret = -ENOENT;
 
        rcu_read_lock();
 
-       /* XXX: verify sta->dev == dev */
-
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get(sdata, mac);
        if (sta) {
                ret = 0;
                sta_set_sinfo(sta, sinfo);
@@ -732,7 +730,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        } else
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (compare_ether_addr(mac, dev->dev_addr) == 0)
+       if (compare_ether_addr(mac, sdata->vif.addr) == 0)
                return -EINVAL;
 
        if (is_multicast_ether_addr(mac))
@@ -779,8 +777,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (mac) {
                rcu_read_lock();
 
-               /* XXX: get sta belonging to dev */
-               sta = sta_info_get(local, mac);
+               sta = sta_info_get(sdata, mac);
                if (!sta) {
                        rcu_read_unlock();
                        return -ENOENT;
@@ -801,14 +798,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                    u8 *mac,
                                    struct station_parameters *params)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
 
        rcu_read_lock();
 
-       /* XXX: get sta belonging to dev */
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get(sdata, mac);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -847,7 +844,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -856,7 +852,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -895,7 +891,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
                                    struct net_device *dev,
                                    u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -904,7 +899,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1324,6 +1319,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 }
 #endif
 
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+                            enum ieee80211_smps_mode smps_mode)
+{
+       const u8 *ap;
+       enum ieee80211_smps_mode old_req;
+       int err;
+
+       old_req = sdata->u.mgd.req_smps;
+       sdata->u.mgd.req_smps = smps_mode;
+
+       if (old_req == smps_mode &&
+           smps_mode != IEEE80211_SMPS_AUTOMATIC)
+               return 0;
+
+       /*
+        * If not associated, or current association is not an HT
+        * association, there's no need to send an action frame.
+        */
+       if (!sdata->u.mgd.associated ||
+           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+               mutex_lock(&sdata->local->iflist_mtx);
+               ieee80211_recalc_smps(sdata->local, sdata);
+               mutex_unlock(&sdata->local->iflist_mtx);
+               return 0;
+       }
+
+       ap = sdata->u.mgd.associated->cbss.bssid;
+
+       if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
+               if (sdata->u.mgd.powersave)
+                       smps_mode = IEEE80211_SMPS_DYNAMIC;
+               else
+                       smps_mode = IEEE80211_SMPS_OFF;
+       }
+
+       /* send SM PS frame to AP */
+       err = ieee80211_send_smps_action(sdata, smps_mode,
+                                        ap, ap);
+       if (err)
+               sdata->u.mgd.req_smps = old_req;
+
+       return err;
+}
+
 static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                                    bool enabled, int timeout)
 {
@@ -1341,6 +1380,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        sdata->u.mgd.powersave = enabled;
        conf->dynamic_ps_timeout = timeout;
 
+       /* no change, but if automatic follow powersave */
+       mutex_lock(&sdata->u.mgd.mtx);
+       __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
+       mutex_unlock(&sdata->u.mgd.mtx);
+
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 
@@ -1356,15 +1400,25 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int i, err = -EINVAL;
+       int i;
        u32 target_rate;
        struct ieee80211_supported_band *sband;
 
+       /*
+        * This _could_ be supported by providing a hook for
+        * drivers for this function, but at this point it
+        * doesn't seem worth bothering.
+        */
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return -EOPNOTSUPP;
+
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+       /*
+        * target_rate = -1, rate->fixed = 0 means auto only, so use all rates
         * target_rate = X, rate->fixed = 1 means only rate X
-        * target_rate = X, rate->fixed = 0 means all rates <= X */
+        * target_rate = X, rate->fixed = 0 means all rates <= X
+        */
        sdata->max_ratectrl_rateidx = -1;
        sdata->force_unicast_rateidx = -1;
 
@@ -1375,20 +1429,18 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
        else
                return 0;
 
-       for (i=0; i< sband->n_bitrates; i++) {
-               struct ieee80211_rate *brate = &sband->bitrates[i];
-               int this_rate = brate->bitrate;
+       for (i = 0; i< sband->n_bitrates; i++) {
+               if (target_rate != sband->bitrates[i].bitrate)
+                       continue;
 
-               if (target_rate == this_rate) {
-                       sdata->max_ratectrl_rateidx = i;
-                       if (mask->fixed)
-                               sdata->force_unicast_rateidx = i;
-                       err = 0;
-                       break;
-               }
+               /* requested bitrate found */
+               sdata->max_ratectrl_rateidx = i;
+               if (mask->fixed)
+                       sdata->force_unicast_rateidx = i;
+               return 0;
        }
 
-       return err;
+       return -EINVAL;
 }
 
 struct cfg80211_ops mac80211_config_ops = {
index e0f5224..d12e743 100644 (file)
@@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D);
 KEY_CONF_FILE(hw_key_idx, D);
 KEY_FILE(flags, X);
 KEY_FILE(tx_rx_count, D);
-KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n");
+KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n");
 KEY_OPS(ifindex);
 
 static ssize_t key_algorithm_read(struct file *file,
index 472b203..3559835 100644 (file)
@@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read(
        return ret;
 }
 
+static ssize_t ieee80211_if_write(
+       struct ieee80211_sub_if_data *sdata,
+       const char __user *userbuf,
+       size_t count, loff_t *ppos,
+       ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
+{
+       u8 *buf;
+       ssize_t ret = -ENODEV;
+
+       buf = kzalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, userbuf, count))
+               return -EFAULT;
+
+       rtnl_lock();
+       if (sdata->dev->reg_state == NETREG_REGISTERED)
+               ret = (*write)(sdata, buf, count);
+       rtnl_unlock();
+
+       return ret;
+}
+
 #define IEEE80211_IF_FMT(name, field, format_string)                   \
 static ssize_t ieee80211_if_fmt_##name(                                        \
        const struct ieee80211_sub_if_data *sdata, char *buf,           \
@@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name(                                       \
        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 }
 
-#define __IEEE80211_IF_FILE(name)                                      \
+#define __IEEE80211_IF_FILE(name, _write)                              \
 static ssize_t ieee80211_if_read_##name(struct file *file,             \
                                        char __user *userbuf,           \
                                        size_t count, loff_t *ppos)     \
@@ -82,12 +106,24 @@ static ssize_t ieee80211_if_read_##name(struct file *file,         \
 }                                                                      \
 static const struct file_operations name##_ops = {                     \
        .read = ieee80211_if_read_##name,                               \
+       .write = (_write),                                              \
        .open = mac80211_open_file_generic,                             \
 }
 
+#define __IEEE80211_IF_FILE_W(name)                                    \
+static ssize_t ieee80211_if_write_##name(struct file *file,            \
+                                        const char __user *userbuf,    \
+                                        size_t count, loff_t *ppos)    \
+{                                                                      \
+       return ieee80211_if_write(file->private_data, userbuf, count,   \
+                                 ppos, ieee80211_if_parse_##name);     \
+}                                                                      \
+__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
+
+
 #define IEEE80211_IF_FILE(name, field, format)                         \
                IEEE80211_IF_FMT_##format(name, field)                  \
-               __IEEE80211_IF_FILE(name)
+               __IEEE80211_IF_FILE(name, NULL)
 
 /* common attributes */
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
@@ -99,6 +135,70 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
 IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
 
+static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
+                             enum ieee80211_smps_mode smps_mode)
+{
+       struct ieee80211_local *local = sdata->local;
+       int err;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
+           smps_mode == IEEE80211_SMPS_STATIC)
+               return -EINVAL;
+
+       /* auto should be dynamic if in PS mode */
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
+           (smps_mode == IEEE80211_SMPS_DYNAMIC ||
+            smps_mode == IEEE80211_SMPS_AUTOMATIC))
+               return -EINVAL;
+
+       /* supported only on managed interfaces for now */
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&local->iflist_mtx);
+       err = __ieee80211_request_smps(sdata, smps_mode);
+       mutex_unlock(&local->iflist_mtx);
+
+       return err;
+}
+
+static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
+       [IEEE80211_SMPS_AUTOMATIC] = "auto",
+       [IEEE80211_SMPS_OFF] = "off",
+       [IEEE80211_SMPS_STATIC] = "static",
+       [IEEE80211_SMPS_DYNAMIC] = "dynamic",
+};
+
+static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
+                                    char *buf, int buflen)
+{
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       return snprintf(buf, buflen, "request: %s\nused: %s\n",
+                       smps_modes[sdata->u.mgd.req_smps],
+                       smps_modes[sdata->u.mgd.ap_smps]);
+}
+
+static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
+                                      const char *buf, int buflen)
+{
+       enum ieee80211_smps_mode mode;
+
+       for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
+               if (strncmp(buf, smps_modes[mode], buflen) == 0) {
+                       int err = ieee80211_set_smps(sdata, mode);
+                       if (!err)
+                               return buflen;
+                       return err;
+               }
+       }
+
+       return -EINVAL;
+}
+
+__IEEE80211_IF_FILE_W(smps);
+
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
@@ -109,7 +209,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
        return scnprintf(buf, buflen, "%u\n",
                         skb_queue_len(&sdata->u.ap.ps_bc_buf));
 }
-__IEEE80211_IF_FILE(num_buffered_multicast);
+__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@@ -158,6 +258,10 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
        debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
                            sdata, &name##_ops);
 
+#define DEBUGFS_ADD_MODE(name, mode) \
+       debugfs_create_file(#name, mode, sdata->debugfs.dir, \
+                           sdata, &name##_ops);
+
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(drop_unencrypted, sta);
@@ -167,6 +271,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(bssid, sta);
        DEBUGFS_ADD(aid, sta);
        DEBUGFS_ADD(capab, sta);
+       DEBUGFS_ADD_MODE(smps, 0600);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -280,16 +385,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
        }
 }
 
-static int notif_registered;
-
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 {
        char buf[10+IFNAMSIZ];
 
-       if (!notif_registered)
-               return;
-
-       sprintf(buf, "netdev:%s", sdata->dev->name);
+       sprintf(buf, "netdev:%s", sdata->name);
        sdata->debugfs.dir = debugfs_create_dir(buf,
                sdata->local->hw.wiphy->debugfsdir);
        add_files(sdata);
@@ -304,58 +404,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
        sdata->debugfs.dir = NULL;
 }
 
-static int netdev_notify(struct notifier_block *nb,
-                        unsigned long state,
-                        void *ndev)
+void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 {
-       struct net_device *dev = ndev;
        struct dentry *dir;
-       struct ieee80211_sub_if_data *sdata;
-       char buf[10+IFNAMSIZ];
-
-       if (state != NETDEV_CHANGENAME)
-               return 0;
-
-       if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
-               return 0;
-
-       if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
-               return 0;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       char buf[10 + IFNAMSIZ];
 
        dir = sdata->debugfs.dir;
 
        if (!dir)
-               return 0;
+               return;
 
-       sprintf(buf, "netdev:%s", dev->name);
+       sprintf(buf, "netdev:%s", sdata->name);
        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
                printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
                       "dir to %s\n", buf);
-
-       return 0;
-}
-
-static struct notifier_block mac80211_debugfs_netdev_notifier = {
-       .notifier_call = netdev_notify,
-};
-
-void ieee80211_debugfs_netdev_init(void)
-{
-       int err;
-
-       err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
-       if (err) {
-               printk(KERN_ERR
-                      "mac80211: failed to install netdev notifier,"
-                      " disabling per-netdev debugfs!\n");
-       } else
-               notif_registered = 1;
-}
-
-void ieee80211_debugfs_netdev_exit(void)
-{
-       unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
-       notif_registered = 0;
 }
index 7af731f..79025e7 100644 (file)
@@ -6,8 +6,7 @@
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
-void ieee80211_debugfs_netdev_init(void);
-void ieee80211_debugfs_netdev_exit(void);
+void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata);
 #else
 static inline void ieee80211_debugfs_add_netdev(
        struct ieee80211_sub_if_data *sdata)
@@ -15,10 +14,8 @@ static inline void ieee80211_debugfs_add_netdev(
 static inline void ieee80211_debugfs_remove_netdev(
        struct ieee80211_sub_if_data *sdata)
 {}
-static inline void ieee80211_debugfs_netdev_init(void)
-{}
-
-static inline void ieee80211_debugfs_netdev_exit(void)
+static inline void ieee80211_debugfs_rename_netdev(
+       struct ieee80211_sub_if_data *sdata)
 {}
 #endif
 
index 3f41608..0d4a759 100644 (file)
@@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = {            \
                STA_OPS(name)
 
 STA_FILE(aid, sta.aid, D);
-STA_FILE(dev, sdata->dev->name, S);
+STA_FILE(dev, sdata->name, S);
 STA_FILE(rx_packets, rx_packets, LU);
 STA_FILE(tx_packets, tx_packets, LU);
 STA_FILE(rx_bytes, rx_bytes, LU);
@@ -160,7 +160,12 @@ STA_OPS(agg_status);
 static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
 {
-       char buf[200], *p = buf;
+#define PRINT_HT_CAP(_cond, _str) \
+       do { \
+       if (_cond) \
+                       p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \
+       } while (0)
+       char buf[1024], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
        struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
@@ -168,15 +173,64 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
                        htc->ht_supported ? "" : "not ");
        if (htc->ht_supported) {
-               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
+               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap);
+
+               PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP");
+               PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
+               PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20");
+
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save");
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save");
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled");
+
+               PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield");
+               PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI");
+               PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI");
+               PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC");
+
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams");
+
+               PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack");
+
+               PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "
+                            "3839 bytes");
+               PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: "
+                            "7935 bytes");
+
+               /*
+                * For beacons and probe response this would mean the BSS
+                * does or does not allow the usage of DSSS/CCK HT40.
+                * Otherwise it means the STA does or does not use
+                * DSSS/CCK HT40.
+                */
+               PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40");
+               PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40");
+
+               /* BIT(13) is reserved */
+
+               PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant");
+
+               PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection");
+
                p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
                                htc->ampdu_factor, htc->ampdu_density);
                p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
+
                for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
                                        htc->mcs.rx_mask[i]);
-               p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
-                               le16_to_cpu(htc->mcs.rx_highest));
+               p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+               /* If not set this is meaningless */
+               if (le16_to_cpu(htc->mcs.rx_highest)) {
+                       p += scnprintf(p, sizeof(buf)+buf-p,
+                                      "MCS rx highest: %d Mbps\n",
+                                      le16_to_cpu(htc->mcs.rx_highest));
+               }
+
                p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
                                htc->mcs.tx_params);
        }
index 921dd9c..727e4cf 100644 (file)
@@ -39,7 +39,7 @@ static inline int drv_add_interface(struct ieee80211_local *local,
                                    struct ieee80211_if_init_conf *conf)
 {
        int ret = local->ops->add_interface(&local->hw, conf);
-       trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
+       trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret);
        return ret;
 }
 
@@ -47,7 +47,7 @@ static inline void drv_remove_interface(struct ieee80211_local *local,
                                        struct ieee80211_if_init_conf *conf)
 {
        local->ops->remove_interface(&local->hw, conf);
-       trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
+       trace_drv_remove_interface(local, vif_to_sdata(conf->vif));
 }
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
@@ -58,13 +58,13 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed)
 }
 
 static inline void drv_bss_info_changed(struct ieee80211_local *local,
-                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_sub_if_data *sdata,
                                        struct ieee80211_bss_conf *info,
                                        u32 changed)
 {
        if (local->ops->bss_info_changed)
-               local->ops->bss_info_changed(&local->hw, vif, info, changed);
-       trace_drv_bss_info_changed(local, vif, info, changed);
+               local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
+       trace_drv_bss_info_changed(local, sdata, info, changed);
 }
 
 static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
@@ -106,12 +106,13 @@ static inline int drv_set_tim(struct ieee80211_local *local,
 }
 
 static inline int drv_set_key(struct ieee80211_local *local,
-                             enum set_key_cmd cmd, struct ieee80211_vif *vif,
+                             enum set_key_cmd cmd,
+                             struct ieee80211_sub_if_data *sdata,
                              struct ieee80211_sta *sta,
                              struct ieee80211_key_conf *key)
 {
-       int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
-       trace_drv_set_key(local, cmd, vif, sta, key, ret);
+       int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
+       trace_drv_set_key(local, cmd, sdata, sta, key, ret);
        return ret;
 }
 
@@ -179,13 +180,13 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
 }
 
 static inline void drv_sta_notify(struct ieee80211_local *local,
-                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_sub_if_data *sdata,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
        if (local->ops->sta_notify)
-               local->ops->sta_notify(&local->hw, vif, cmd, sta);
-       trace_drv_sta_notify(local, vif, cmd, sta);
+               local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
+       trace_drv_sta_notify(local, sdata, cmd, sta);
 }
 
 static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
@@ -239,16 +240,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 }
 
 static inline int drv_ampdu_action(struct ieee80211_local *local,
-                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sub_if_data *sdata,
                                   enum ieee80211_ampdu_mlme_action action,
                                   struct ieee80211_sta *sta, u16 tid,
                                   u16 *ssn)
 {
        int ret = -EOPNOTSUPP;
        if (local->ops->ampdu_action)
-               ret = local->ops->ampdu_action(&local->hw, vif, action,
+               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
                                               sta, tid, ssn);
-       trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
+       trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
        return ret;
 }
 
index ee94ea0..7a849b9 100644 (file)
@@ -25,10 +25,12 @@ static inline void trace_ ## name(proto) {}
 #define STA_PR_FMT     " sta:%pM"
 #define STA_PR_ARG     __entry->sta_addr
 
-#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, vif)
-#define VIF_ASSIGN     __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
-#define VIF_PR_FMT     " vif:%p(%d)"
-#define VIF_PR_ARG     __entry->vif, __entry->vif_type
+#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
+                       __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
+                       __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_PR_FMT     " vif:%s(%d)"
+#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type
 
 TRACE_EVENT(drv_start,
        TP_PROTO(struct ieee80211_local *local, int ret),
@@ -70,11 +72,10 @@ TRACE_EVENT(drv_stop,
 
 TRACE_EVENT(drv_add_interface,
        TP_PROTO(struct ieee80211_local *local,
-                const u8 *addr,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 int ret),
 
-       TP_ARGS(local, addr, vif, ret),
+       TP_ARGS(local, sdata, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -86,7 +87,7 @@ TRACE_EVENT(drv_add_interface,
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               memcpy(__entry->addr, addr, 6);
+               memcpy(__entry->addr, sdata->vif.addr, 6);
                __entry->ret = ret;
        ),
 
@@ -97,10 +98,9 @@ TRACE_EVENT(drv_add_interface,
 );
 
 TRACE_EVENT(drv_remove_interface,
-       TP_PROTO(struct ieee80211_local *local,
-                const u8 *addr, struct ieee80211_vif *vif),
+       TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
 
-       TP_ARGS(local, addr, vif),
+       TP_ARGS(local, sdata),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -111,7 +111,7 @@ TRACE_EVENT(drv_remove_interface,
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               memcpy(__entry->addr, addr, 6);
+               memcpy(__entry->addr, sdata->vif.addr, 6);
        ),
 
        TP_printk(
@@ -140,6 +140,7 @@ TRACE_EVENT(drv_config,
                __field(u8, short_frame_max_tx_count)
                __field(int, center_freq)
                __field(int, channel_type)
+               __field(int, smps)
        ),
 
        TP_fast_assign(
@@ -155,6 +156,7 @@ TRACE_EVENT(drv_config,
                __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
                __entry->center_freq = local->hw.conf.channel->center_freq;
                __entry->channel_type = local->hw.conf.channel_type;
+               __entry->smps = local->hw.conf.smps_mode;
        ),
 
        TP_printk(
@@ -165,11 +167,11 @@ TRACE_EVENT(drv_config,
 
 TRACE_EVENT(drv_bss_info_changed,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_bss_conf *info,
                 u32 changed),
 
-       TP_ARGS(local, vif, info, changed),
+       TP_ARGS(local, sdata, info, changed),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -293,11 +295,11 @@ TRACE_EVENT(drv_set_tim,
 
 TRACE_EVENT(drv_set_key,
        TP_PROTO(struct ieee80211_local *local,
-                enum set_key_cmd cmd, struct ieee80211_vif *vif,
+                enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_sta *sta,
                 struct ieee80211_key_conf *key, int ret),
 
-       TP_ARGS(local, cmd, vif, sta, key, ret),
+       TP_ARGS(local, cmd, sdata, sta, key, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -491,11 +493,11 @@ TRACE_EVENT(drv_set_rts_threshold,
 
 TRACE_EVENT(drv_sta_notify,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 enum sta_notify_cmd cmd,
                 struct ieee80211_sta *sta),
 
-       TP_ARGS(local, vif, cmd, sta),
+       TP_ARGS(local, sdata, cmd, sta),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -656,12 +658,12 @@ TRACE_EVENT(drv_tx_last_beacon,
 
 TRACE_EVENT(drv_ampdu_action,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 enum ieee80211_ampdu_mlme_action action,
                 struct ieee80211_sta *sta, u16 tid,
                 u16 *ssn, int ret),
 
-       TP_ARGS(local, vif, action, sta, tid, ssn, ret),
+       TP_ARGS(local, sdata, action, sta, tid, ssn, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
index d7dcee6..bb677a7 100644 (file)
@@ -125,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
-                                       "for delba frame\n", sdata->dev->name);
+                                       "for delba frame\n", sdata->name);
                return;
        }
 
@@ -133,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -185,3 +185,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                spin_unlock_bh(&sta->lock);
        }
 }
+
+int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
+                              enum ieee80211_smps_mode smps, const u8 *da,
+                              const u8 *bssid)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *action_frame;
+
+       /* 27 = header + category + action + smps mode */
+       skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       action_frame = (void *)skb_put(skb, 27);
+       memcpy(action_frame->da, da, ETH_ALEN);
+       memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(action_frame->bssid, bssid, ETH_ALEN);
+       action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_ACTION);
+       action_frame->u.action.category = WLAN_CATEGORY_HT;
+       action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
+       switch (smps) {
+       case IEEE80211_SMPS_AUTOMATIC:
+       case IEEE80211_SMPS_NUM_MODES:
+               WARN_ON(1);
+       case IEEE80211_SMPS_OFF:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DISABLED;
+               break;
+       case IEEE80211_SMPS_STATIC:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_STATIC;
+               break;
+       case IEEE80211_SMPS_DYNAMIC:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DYNAMIC;
+               break;
+       }
+
+       /* we'll do more on status of this frame */
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       ieee80211_tx_skb(sdata, skb);
+
+       return 0;
+}
index 10d1385..ef6c6b2 100644 (file)
@@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_PROBE_RESP);
        memset(mgmt->da, 0xff, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
        mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
        mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
@@ -252,7 +252,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, mgmt->sa);
+               sta = sta_info_get(sdata, mgmt->sa);
                if (sta) {
                        u32 prev_rates;
 
@@ -266,7 +266,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                printk(KERN_DEBUG "%s: updated supp_rates set "
                                    "for %pM based on beacon info (0x%llx | "
                                    "0x%llx -> 0x%llx)\n",
-                                   sdata->dev->name,
+                                   sdata->name,
                                    sta->sta.addr,
                                    (unsigned long long) prev_rates,
                                    (unsigned long long) supp_rates,
@@ -364,7 +364,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                printk(KERN_DEBUG "%s: beacon TSF higher than "
                       "local TSF - IBSS merge with BSSID %pM\n",
-                      sdata->dev->name, mgmt->bssid);
+                      sdata->name, mgmt->bssid);
 #endif
                ieee80211_sta_join_ibss(sdata, bss);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
@@ -393,7 +393,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
        if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
-                              sdata->dev->name, addr);
+                              sdata->name, addr);
                return NULL;
        }
 
@@ -402,7 +402,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
+              wiphy_name(local->hw.wiphy), addr, sdata->name);
 #endif
 
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -466,7 +466,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
                return;
 
        printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-              "IBSS networks with same SSID (merge)\n", sdata->dev->name);
+              "IBSS networks with same SSID (merge)\n", sdata->name);
 
        ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
 }
@@ -488,13 +488,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
                 * random number generator get different BSSID. */
                get_random_bytes(bssid, ETH_ALEN);
                for (i = 0; i < ETH_ALEN; i++)
-                       bssid[i] ^= sdata->dev->dev_addr[i];
+                       bssid[i] ^= sdata->vif.addr[i];
                bssid[0] &= ~0x01;
                bssid[0] |= 0x02;
        }
 
        printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
-              sdata->dev->name, bssid);
+              sdata->name, bssid);
 
        sband = local->hw.wiphy->bands[ifibss->channel->band];
 
@@ -523,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        active_ibss = ieee80211_sta_active_ibss(sdata);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
-              sdata->dev->name, active_ibss);
+              sdata->name, active_ibss);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
        if (active_ibss)
@@ -552,7 +552,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 
                printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
                       " based on configured SSID\n",
-                      sdata->dev->name, bss->cbss.bssid);
+                      sdata->name, bss->cbss.bssid);
 
                ieee80211_sta_join_ibss(sdata, bss);
                ieee80211_rx_bss_put(local, bss);
@@ -571,7 +571,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        } else if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-                      "join\n", sdata->dev->name);
+                      "join\n", sdata->name);
 
                ieee80211_request_internal_scan(sdata, ifibss->ssid,
                                                ifibss->ssid_len);
@@ -585,7 +585,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                                return;
                        }
                        printk(KERN_DEBUG "%s: IBSS not allowed on"
-                              " %d MHz\n", sdata->dev->name,
+                              " %d MHz\n", sdata->name,
                               local->hw.conf.channel->center_freq);
 
                        /* No IBSS found - decrease scan interval and continue
@@ -619,7 +619,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
               " (tx_last_beacon=%d)\n",
-              sdata->dev->name, mgmt->sa, mgmt->da,
+              sdata->name, mgmt->sa, mgmt->da,
               mgmt->bssid, tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
@@ -637,7 +637,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
                       "from %pM\n",
-                      sdata->dev->name, mgmt->sa);
+                      sdata->name, mgmt->sa);
 #endif
                return;
        }
@@ -657,7 +657,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
-              sdata->dev->name, resp->da);
+              sdata->name, resp->da);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
@@ -671,7 +671,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        size_t baselen;
        struct ieee802_11_elems elems;
 
-       if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
index 91dc863..88b0ba6 100644 (file)
@@ -140,7 +140,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
 
 struct ieee80211_tx_data {
        struct sk_buff *skb;
-       struct net_device *dev;
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
@@ -298,6 +297,8 @@ struct ieee80211_if_managed {
 
        unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
+       enum ieee80211_smps_mode req_smps, /* requested smps mode */
+                                ap_smps; /* smps mode AP thinks we're in */
 
        unsigned long request;
 
@@ -433,6 +434,8 @@ struct ieee80211_sub_if_data {
 
        int drop_unencrypted;
 
+       char name[IFNAMSIZ];
+
        /*
         * keep track of whether the HT opmode (stored in
         * vif.bss_info.ht_operation_mode) is valid.
@@ -586,6 +589,9 @@ struct ieee80211_local {
        /* used for uploading changed mc list */
        struct work_struct reconfig_filter;
 
+       /* used to reconfigure hardware SM PS */
+       struct work_struct recalc_smps;
+
        /* aggregated multicast list */
        struct dev_addr_list *mc_list;
        int mc_count;
@@ -760,6 +766,8 @@ struct ieee80211_local {
        int user_power_level; /* in dBm */
        int power_constr_level; /* in dBm */
 
+       enum ieee80211_smps_mode smps_mode;
+
        struct work_struct restart_work;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -874,6 +882,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 void ieee80211_configure_filter(struct ieee80211_local *local);
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 
+extern bool ieee80211_disable_40mhz_24ghz;
+
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
@@ -938,6 +948,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
 
 /* interface handling */
+int ieee80211_iface_init(void);
+void ieee80211_iface_exit(void);
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                     struct net_device **new_dev, enum nl80211_iftype type,
                     struct vif_params *params);
@@ -976,6 +988,9 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
                          const u8 *da, u16 tid,
                          u16 initiator, u16 reason_code);
+int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
+                              enum ieee80211_smps_mode smps, const u8 *da,
+                              const u8 *bssid);
 
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
                                u16 tid, u16 initiator, u16 reason);
@@ -1086,6 +1101,10 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                            struct ieee802_11_elems *elems,
                            enum ieee80211_band band);
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+                            enum ieee80211_smps_mode smps_mode);
+void ieee80211_recalc_smps(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *forsdata);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index 80c16f6..a6e6da3 100644 (file)
@@ -60,6 +60,22 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static int ieee80211_change_mac(struct net_device *dev, void *addr)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int ret;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       ret = eth_mac_addr(dev, addr);
+
+       if (ret == 0)
+               memcpy(sdata->vif.addr, addr, ETH_ALEN);
+
+       return ret;
+}
+
 static inline int identical_mac_addr_allowed(int type1, int type2)
 {
        return type1 == NL80211_IFTYPE_MONITOR ||
@@ -234,7 +250,7 @@ static int ieee80211_open(struct net_device *dev)
        default:
                conf.vif = &sdata->vif;
                conf.type = sdata->vif.type;
-               conf.mac_addr = dev->dev_addr;
+               conf.mac_addr = sdata->vif.addr;
                res = drv_add_interface(local, &conf);
                if (res)
                        goto err_stop;
@@ -514,7 +530,7 @@ static int ieee80211_stop(struct net_device *dev)
 
                conf.vif = &sdata->vif;
                conf.type = sdata->vif.type;
-               conf.mac_addr = dev->dev_addr;
+               conf.mac_addr = sdata->vif.addr;
                /* disable all keys for as long as this netdev is down */
                ieee80211_disable_keys(sdata);
                drv_remove_interface(local, &conf);
@@ -651,7 +667,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_start_xmit         = ieee80211_subif_start_xmit,
        .ndo_set_multicast_list = ieee80211_set_multicast_list,
        .ndo_change_mtu         = ieee80211_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ieee80211_change_mac,
 };
 
 static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -794,6 +810,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
        sdata = netdev_priv(ndev);
        ndev->ieee80211_ptr = &sdata->wdev;
+       memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
+       memcpy(sdata->name, ndev->name, IFNAMSIZ);
 
        /* initialise type-independent data */
        sdata->wdev.wiphy = local->hw.wiphy;
@@ -945,3 +963,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
        if (chg)
                ieee80211_hw_config(local, chg);
 }
+
+static int netdev_notify(struct notifier_block *nb,
+                        unsigned long state,
+                        void *ndev)
+{
+       struct net_device *dev = ndev;
+       struct ieee80211_sub_if_data *sdata;
+
+       if (state != NETDEV_CHANGENAME)
+               return 0;
+
+       if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
+               return 0;
+
+       if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       memcpy(sdata->name, sdata->name, IFNAMSIZ);
+
+       ieee80211_debugfs_rename_netdev(sdata);
+       return 0;
+}
+
+static struct notifier_block mac80211_netdev_notifier = {
+       .notifier_call = netdev_notify,
+};
+
+int ieee80211_iface_init(void)
+{
+       return register_netdevice_notifier(&mac80211_netdev_notifier);
+}
+
+void ieee80211_iface_exit(void)
+{
+       unregister_netdevice_notifier(&mac80211_netdev_notifier);
+}
index 659a42d..32ee6d0 100644 (file)
@@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
-       ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
+       ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
        if (!ret) {
                spin_lock_bh(&todo_lock);
@@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
-       ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif,
+       ret = drv_set_key(key->local, DISABLE_KEY, sdata,
                          sta, &key->conf);
 
        if (ret)
@@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
                         */
 
                        /* same here, the AP could be using QoS */
-                       ap = sta_info_get(key->local, key->sdata->u.mgd.bssid);
+                       ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
                        if (ap) {
                                if (test_sta_flags(ap, WLAN_STA_WME))
                                        key->conf.flags |=
index a49f93b..bdc2968 100644 (file)
@@ -59,11 +59,17 @@ enum ieee80211_internal_key_flags {
        KEY_FLAG_TODO_DEFMGMTKEY        = BIT(6),
 };
 
+enum ieee80211_internal_tkip_state {
+       TKIP_STATE_NOT_INIT,
+       TKIP_STATE_PHASE1_DONE,
+       TKIP_STATE_PHASE1_HW_UPLOADED,
+};
+
 struct tkip_ctx {
        u32 iv32;
        u16 iv16;
        u16 p1k[5];
-       int initialized;
+       enum ieee80211_internal_tkip_state state;
 };
 
 struct ieee80211_key {
index 0d2d948..d442674 100644 (file)
 #include "led.h"
 #include "cfg.h"
 #include "debugfs.h"
-#include "debugfs_netdev.h"
+
+
+bool ieee80211_disable_40mhz_24ghz;
+module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
+MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
+                "Disable 40MHz support in the 2.4GHz band");
 
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
@@ -114,6 +119,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                changed |= IEEE80211_CONF_CHANGE_CHANNEL;
        }
 
+       if (!conf_is_ht(&local->hw.conf)) {
+               /*
+                * mac80211.h documents that this is only valid
+                * when the channel is set to an HT type, and
+                * that otherwise STATIC is used.
+                */
+               local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC;
+       } else if (local->hw.conf.smps_mode != local->smps_mode) {
+               local->hw.conf.smps_mode = local->smps_mode;
+               changed |= IEEE80211_CONF_CHANGE_SMPS;
+       }
+
        if (scan_chan)
                power = chan->max_power;
        else
@@ -173,7 +190,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
-               sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
+               sdata->vif.bss_conf.bssid = sdata->vif.addr;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                sdata->vif.bss_conf.bssid = zero;
        } else {
@@ -223,8 +240,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       drv_bss_info_changed(local, &sdata->vif,
-                            &sdata->vif.bss_conf, changed);
+       drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed);
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -299,6 +315,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_restart_hw);
 
+static void ieee80211_recalc_smps_work(struct work_struct *work)
+{
+       struct ieee80211_local *local =
+               container_of(work, struct ieee80211_local, recalc_smps);
+
+       mutex_lock(&local->iflist_mtx);
+       ieee80211_recalc_smps(local, NULL);
+       mutex_unlock(&local->iflist_mtx);
+}
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -372,6 +398,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
+       INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
+       local->smps_mode = IEEE80211_SMPS_OFF;
 
        INIT_WORK(&local->dynamic_ps_enable_work,
                  ieee80211_dynamic_ps_enable_work);
@@ -674,11 +702,19 @@ static int __init ieee80211_init(void)
 
        ret = rc80211_pid_init();
        if (ret)
-               return ret;
+               goto err_pid;
 
-       ieee80211_debugfs_netdev_init();
+       ret = ieee80211_iface_init();
+       if (ret)
+               goto err_netdev;
 
        return 0;
+ err_netdev:
+       rc80211_pid_exit();
+ err_pid:
+       rc80211_minstrel_exit();
+
+       return ret;
 }
 
 static void __exit ieee80211_exit(void)
@@ -695,7 +731,7 @@ static void __exit ieee80211_exit(void)
        if (mesh_allocated)
                ieee80211s_stop();
 
-       ieee80211_debugfs_netdev_exit();
+       ieee80211_iface_exit();
 }
 
 
index 6a43314..e0bd85e 100644 (file)
@@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: running mesh housekeeping\n",
-              sdata->dev->name);
+              sdata->name);
 #endif
 
        ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
@@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
        /* ignore ProbeResp to foreign address */
        if (stype == IEEE80211_STYPE_PROBE_RESP &&
-           compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
+           compare_ether_addr(mgmt->da, sdata->vif.addr))
                return;
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
index d28acb6..ce84237 100644 (file)
@@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                                          IEEE80211_STYPE_ACTION);
 
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID == SA */
-       memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
 
@@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                                          IEEE80211_STYPE_ACTION);
 
        memcpy(mgmt->da, ra, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
        mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
@@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
        bool process = true;
 
        rcu_read_lock();
-       sta = sta_info_get(local, mgmt->sa);
+       sta = sta_info_get(sdata, mgmt->sa);
        if (!sta) {
                rcu_read_unlock();
                return 0;
@@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
                new_metric = MAX_METRIC;
        exp_time = TU_TO_EXP_TIME(orig_lifetime);
 
-       if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
+       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
                /* This MP is the originator, we are not interested in this
                 * frame, except for updating transmitter's path info.
                 */
@@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 
        mhwmp_dbg("received PREQ from %pM\n", orig_addr);
 
-       if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
+       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
                mhwmp_dbg("PREQ is for us\n");
                forward = false;
                reply = true;
@@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
         * replies
         */
        target_addr = PREP_IE_TARGET_ADDR(prep_elem);
-       if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0)
                /* destination, no forwarding required */
                return;
 
@@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                target_flags = MP_F_RF;
 
        spin_unlock_bh(&mpath->state_lock);
-       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
+       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
                        cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
                        cpu_to_le32(mpath->sn), broadcast_addr, 0,
                        ttl, cpu_to_le32(lifetime), 0,
@@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                if (time_after(jiffies,
                               mpath->exp_time -
                               msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
-                   !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) &&
+                   !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
                    !(mpath->flags & MESH_PATH_RESOLVING) &&
                    !(mpath->flags & MESH_PATH_FIXED)) {
                        mesh_queue_preq(mpath,
@@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-       mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
+       mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
                               cpu_to_le32(++ifmsh->sn),
                               0, NULL, 0, broadcast_addr,
                               0, MESH_TTL, 0, 0, 0, sdata);
index 0192cfd..2312efe 100644 (file)
@@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
        struct mesh_path *mpath;
        u32 sn = 0;
 
-       if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) {
+       if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
                u8 *ra, *da;
 
                da = hdr->addr3;
index 0f7c6e6..7985e51 100644 (file)
@@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
        mgmt->u.action.category = MESH_PLINK_CATEGORY;
        mgmt->u.action.u.plink_action.action_code = action;
@@ -234,7 +234,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, hw_addr);
+       sta = sta_info_get(sdata, hw_addr);
        if (!sta) {
                sta = mesh_plink_alloc(sdata, hw_addr, rates);
                if (!sta) {
@@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, mgmt->sa);
+       sta = sta_info_get(sdata, mgmt->sa);
        if (!sta && ftype != PLINK_OPEN) {
                mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
                rcu_read_unlock();
index c79e59f..2f9ed8b 100644 (file)
@@ -75,6 +75,9 @@ enum rx_mgmt_action {
        /* caller must call cfg80211_send_disassoc() */
        RX_MGMT_CFG80211_DISASSOC,
 
+       /* caller must tell cfg80211 about internal error */
+       RX_MGMT_CFG80211_ASSOC_ERROR,
+
        /* caller must call cfg80211_auth_timeout() & free work */
        RX_MGMT_CFG80211_AUTH_TO,
 
@@ -202,7 +205,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                ieee80211_hw_config(local, 0);
 
                rcu_read_lock();
-               sta = sta_info_get(local, bssid);
+               sta = sta_info_get(sdata, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED);
@@ -248,7 +251,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                            wk->ssid_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
-                      "frame\n", sdata->dev->name);
+                      "frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -282,7 +285,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
 
        if (!is_zero_ether_addr(wk->prev_bssid)) {
@@ -398,6 +401,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                __le16 tmp;
                u32 flags = local->hw.conf.channel->flags;
 
+               /* determine capability flags */
+
+               if (ieee80211_disable_40mhz_24ghz &&
+                   sband->band == IEEE80211_BAND_2GHZ) {
+                       cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       cap &= ~IEEE80211_HT_CAP_SGI_40;
+               }
+
                switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
                case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                        if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
@@ -413,17 +424,64 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                        break;
                }
 
-               tmp = cpu_to_le16(cap);
-               pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
+               /* set SM PS mode properly */
+               cap &= ~IEEE80211_HT_CAP_SM_PS;
+               /* new association always uses requested smps mode */
+               if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
+                       if (ifmgd->powersave)
+                               ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
+                       else
+                               ifmgd->ap_smps = IEEE80211_SMPS_OFF;
+               } else
+                       ifmgd->ap_smps = ifmgd->req_smps;
+
+               switch (ifmgd->ap_smps) {
+               case IEEE80211_SMPS_AUTOMATIC:
+               case IEEE80211_SMPS_NUM_MODES:
+                       WARN_ON(1);
+               case IEEE80211_SMPS_OFF:
+                       cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
+                               IEEE80211_HT_CAP_SM_PS_SHIFT;
+                       break;
+               case IEEE80211_SMPS_STATIC:
+                       cap |= WLAN_HT_CAP_SM_PS_STATIC <<
+                               IEEE80211_HT_CAP_SM_PS_SHIFT;
+                       break;
+               case IEEE80211_SMPS_DYNAMIC:
+                       cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
+                               IEEE80211_HT_CAP_SM_PS_SHIFT;
+                       break;
+               }
+
+               /* reserve and fill IE */
+
+               pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
                *pos++ = WLAN_EID_HT_CAPABILITY;
                *pos++ = sizeof(struct ieee80211_ht_cap);
                memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+               /* capability flags */
+               tmp = cpu_to_le16(cap);
                memcpy(pos, &tmp, sizeof(u16));
                pos += sizeof(u16);
-               /* TODO: needs a define here for << 2 */
+
+               /* AMPDU parameters */
                *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density << 2);
+                        (sband->ht_cap.ampdu_density <<
+                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+               /* MCS set */
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+               pos += sizeof(sband->ht_cap.mcs);
+
+               /* extended capabilities */
+               pos += sizeof(__le16);
+
+               /* BF capabilities */
+               pos += sizeof(__le32);
+
+               /* antenna selection */
+               pos += sizeof(u8);
        }
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -443,7 +501,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for "
-                      "deauth/disassoc frame\n", sdata->dev->name);
+                      "deauth/disassoc frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -451,7 +509,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
        skb_put(skb, 2);
@@ -484,7 +542,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for "
-                      "pspoll frame\n", sdata->dev->name);
+                      "pspoll frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -499,7 +557,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
        pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
 
        memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
-       memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN);
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
@@ -519,7 +577,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
-                      "frame\n", sdata->dev->name);
+                      "frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -532,7 +590,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
                fc |= cpu_to_le16(IEEE80211_FCTL_PM);
        nullfunc->frame_control = fc;
        memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
-       memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -940,6 +998,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        mutex_lock(&local->iflist_mtx);
        ieee80211_recalc_ps(local, -1);
+       ieee80211_recalc_smps(local, sdata);
        mutex_unlock(&local->iflist_mtx);
 
        netif_start_queue(sdata->dev);
@@ -956,7 +1015,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
        wk->tries++;
        if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
+                      sdata->name, wk->bss->cbss.bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
@@ -974,7 +1033,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
        }
 
        printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
-                       sdata->dev->name, wk->bss->cbss.bssid,
+                       sdata->name, wk->bss->cbss.bssid,
                        wk->tries);
 
        /*
@@ -1001,7 +1060,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
        if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: authentication with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
+                      sdata->name, wk->bss->cbss.bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
@@ -1019,7 +1078,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
        }
 
        printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
-              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
+              sdata->name, wk->bss->cbss.bssid, wk->tries);
 
        ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
                            wk->bss->cbss.bssid, NULL, 0, 0);
@@ -1078,7 +1137,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        netif_carrier_off(sdata->dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, bssid);
+       sta = sta_info_get(sdata, bssid);
        if (sta)
                ieee80211_sta_tear_down_BA_sessions(sta);
        rcu_read_unlock();
@@ -1115,7 +1174,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, bssid);
+       sta = sta_info_get(sdata, bssid);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -1139,7 +1198,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
        if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
                printk(KERN_DEBUG "%s: association with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
+                      sdata->name, wk->bss->cbss.bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
@@ -1157,7 +1216,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
        }
 
        printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
-              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
+              sdata->name, wk->bss->cbss.bssid, wk->tries);
        ieee80211_send_assoc(sdata, wk);
 
        wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@ -1218,7 +1277,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (beacon && net_ratelimit())
                printk(KERN_DEBUG "%s: detected beacon loss from AP "
-                      "- sending probe request\n", sdata->dev->name);
+                      "- sending probe request\n", sdata->name);
 #endif
 
        /*
@@ -1275,7 +1334,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgd_work *wk)
 {
        wk->state = IEEE80211_MGD_STATE_IDLE;
-       printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
+       printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
 }
 
 
@@ -1372,7 +1431,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
-                       sdata->dev->name, bssid, reason_code);
+                       sdata->name, bssid, reason_code);
 
        if (!wk) {
                ieee80211_set_disassoc(sdata, true);
@@ -1407,7 +1466,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
-                       sdata->dev->name, mgmt->sa, reason_code);
+                       sdata->name, mgmt->sa, reason_code);
 
        ieee80211_set_disassoc(sdata, false);
        ieee80211_recalc_idle(sdata->local);
@@ -1431,8 +1490,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u8 *pos;
        u32 changed = 0;
-       int i, j;
-       bool have_higher_than_11mbit = false, newsta = false;
+       int i, j, err;
+       bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
 
        /*
@@ -1452,7 +1511,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
               "status=%d aid=%d)\n",
-              sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa,
+              sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
               capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
        pos = mgmt->u.assoc_resp.variable;
@@ -1466,7 +1525,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                ms = tu * 1024 / 1000;
                printk(KERN_DEBUG "%s: AP rejected association temporarily; "
                       "comeback duration %u TU (%u ms)\n",
-                      sdata->dev->name, tu, ms);
+                      sdata->name, tu, ms);
                wk->timeout = jiffies + msecs_to_jiffies(ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
                        run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
@@ -1475,49 +1534,37 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
-                      sdata->dev->name, status_code);
+                      sdata->name, status_code);
                wk->state = IEEE80211_MGD_STATE_IDLE;
                return RX_MGMT_CFG80211_ASSOC;
        }
 
        if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
                printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-                      "set\n", sdata->dev->name, aid);
+                      "set\n", sdata->name, aid);
        aid &= ~(BIT(15) | BIT(14));
 
        if (!elems.supp_rates) {
                printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-                      sdata->dev->name);
+                      sdata->name);
                return RX_MGMT_NONE;
        }
 
-       printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
+       printk(KERN_DEBUG "%s: associated\n", sdata->name);
        ifmgd->aid = aid;
 
-       rcu_read_lock();
-
-       /* Add STA entry for the AP */
-       sta = sta_info_get(local, wk->bss->cbss.bssid);
+       sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
        if (!sta) {
-               newsta = true;
-
-               rcu_read_unlock();
-
-               sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
-               if (!sta) {
-                       printk(KERN_DEBUG "%s: failed to alloc STA entry for"
-                              " the AP\n", sdata->dev->name);
-                       return RX_MGMT_NONE;
-               }
-
-               set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
-                                  WLAN_STA_ASSOC_AP);
-               if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-                       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
-
-               rcu_read_lock();
+               printk(KERN_DEBUG "%s: failed to alloc STA entry for"
+                      " the AP\n", sdata->name);
+               return RX_MGMT_CFG80211_ASSOC_ERROR;
        }
 
+       set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
+                          WLAN_STA_ASSOC_AP);
+       if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+               set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+
        rates = 0;
        basic_rates = 0;
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -1580,18 +1627,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        if (elems.wmm_param)
                set_sta_flags(sta, WLAN_STA_WME);
 
-       if (newsta) {
-               int err = sta_info_insert(sta);
-               if (err) {
-                       printk(KERN_DEBUG "%s: failed to insert STA entry for"
-                              " the AP (error %d)\n", sdata->dev->name, err);
-                       rcu_read_unlock();
-                       return RX_MGMT_NONE;
-               }
+       err = sta_info_insert(sta);
+       sta = NULL;
+       if (err) {
+               printk(KERN_DEBUG "%s: failed to insert STA entry for"
+                      " the AP (error %d)\n", sdata->name, err);
+               return RX_MGMT_CFG80211_ASSOC_ERROR;
        }
 
-       rcu_read_unlock();
-
        if (elems.wmm_param)
                ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
                                         elems.wmm_param_len);
@@ -1679,7 +1722,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        ASSERT_MGD_MTX(ifmgd);
 
-       if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -1694,7 +1737,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        /* direct probe may be part of the association flow */
        if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
                printk(KERN_DEBUG "%s: direct probe responded\n",
-                      sdata->dev->name);
+                      sdata->name);
                wk->tries = 0;
                wk->state = IEEE80211_MGD_STATE_AUTH;
                WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
@@ -1787,7 +1830,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: cancelling probereq poll due "
-                              "to a received beacon\n", sdata->dev->name);
+                              "to a received beacon\n", sdata->name);
                }
 #endif
                ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
@@ -1865,7 +1908,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, bssid);
+               sta = sta_info_get(sdata, bssid);
                if (WARN_ON(!sta)) {
                        rcu_read_unlock();
                        return;
@@ -2036,6 +2079,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        case RX_MGMT_CFG80211_DEAUTH:
                cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
                break;
+       case RX_MGMT_CFG80211_ASSOC_ERROR:
+               /* an internal error -- pretend timeout for now */
+               cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
+               break;
        default:
                WARN(1, "unexpected: %d", rma);
        }
@@ -2336,6 +2383,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
                ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 
        mutex_init(&ifmgd->mtx);
+
+       if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
+               ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
+       else
+               ifmgd->req_smps = IEEE80211_SMPS_OFF;
 }
 
 /* scan finished notification */
@@ -2563,7 +2615,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        mutex_unlock(&ifmgd->mtx);
 
        printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
-              sdata->dev->name, bssid, req->reason_code);
+              sdata->name, bssid, req->reason_code);
 
        ieee80211_send_deauth_disassoc(sdata, bssid,
                        IEEE80211_STYPE_DEAUTH, req->reason_code,
@@ -2594,7 +2646,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        }
 
        printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
-              sdata->dev->name, req->bss->bssid, req->reason_code);
+              sdata->name, req->bss->bssid, req->reason_code);
 
        ieee80211_set_disassoc(sdata, false);
 
index e535f1c..05e161c 100644 (file)
@@ -65,7 +65,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-                       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
+                       drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
                                       &sta->sta);
                }
 
@@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 
                conf.vif = &sdata->vif;
                conf.type = sdata->vif.type;
-               conf.mac_addr = sdata->dev->dev_addr;
+               conf.mac_addr = sdata->vif.addr;
                drv_remove_interface(local, &conf);
        }
 
index 9f2807a..6cbf1a7 100644 (file)
@@ -283,15 +283,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        skb->protocol = htons(ETH_P_802_2);
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
                        continue;
 
                if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
                        continue;
 
+               if (!netif_running(sdata->dev))
+                       continue;
+
                if (prev_dev) {
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2) {
@@ -361,7 +361,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
  * boundary. In the case of regular frames, this simply means aligning the
  * payload to a four-byte boundary (because either the IP header is directly
  * contained, or IV/RFC1042 headers that have a length divisible by four are
- * in front of it).
+ * in front of it).  If the payload data is not properly aligned and the
+ * architecture doesn't support efficient unaligned operations, mac80211
+ * will align the data.
  *
  * With A-MSDU frames, however, the payload data address must yield two modulo
  * four because there are 14-byte 802.3 headers within the A-MSDU frames that
@@ -375,25 +377,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
  */
 static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       int hdrlen;
-
-#ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
-       return;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       WARN_ONCE((unsigned long)rx->skb->data & 1,
+                 "unaligned packet at 0x%p\n", rx->skb->data);
 #endif
-
-       if (WARN_ONCE((unsigned long)rx->skb->data & 1,
-                     "unaligned packet at 0x%p\n", rx->skb->data))
-               return;
-
-       if (!ieee80211_is_data_present(hdr->frame_control))
-               return;
-
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       if (rx->flags & IEEE80211_RX_AMSDU)
-               hdrlen += ETH_HLEN;
-       WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3,
-                 "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen);
 }
 
 
@@ -476,7 +463,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       char *dev_addr = rx->sdata->dev->dev_addr;
+       char *dev_addr = rx->sdata->vif.addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1021,10 +1008,10 @@ static void ap_sta_ps_start(struct sta_info *sta)
 
        atomic_inc(&sdata->bss->num_sta_ps);
        set_sta_flags(sta, WLAN_STA_PS_STA);
-       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
+       drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
-              sdata->dev->name, sta->sta.addr, sta->sta.aid);
+              sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -1038,13 +1025,13 @@ static void ap_sta_ps_end(struct sta_info *sta)
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
-              sdata->dev->name, sta->sta.addr, sta->sta.aid);
+              sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
-                      sdata->dev->name, sta->sta.addr, sta->sta.aid);
+                      sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                return;
        }
@@ -1156,7 +1143,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
                printk(KERN_DEBUG "%s: RX reassembly removed oldest "
                       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
                       "addr1=%pM addr2=%pM\n",
-                      sdata->dev->name, idx,
+                      sdata->name, idx,
                       jiffies - entry->first_frag_time, entry->seq,
                       entry->last_frag, hdr->addr1, hdr->addr2);
 #endif
@@ -1424,7 +1411,6 @@ static int
 __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
-       struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
        if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1436,7 +1422,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
             (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
                return -1;
 
-       return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
+       return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
 }
 
 /*
@@ -1453,7 +1439,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * of whether the frame was encrypted or not.
         */
        if (ehdr->h_proto == htons(ETH_P_PAE) &&
-           (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
+           (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
 
@@ -1472,7 +1458,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct net_device *dev = sdata->dev;
-       struct ieee80211_local *local = rx->local;
        struct sk_buff *skb, *xmit_skb;
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
@@ -1495,8 +1480,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                                printk(KERN_DEBUG "%s: failed to clone "
                                       "multicast frame\n", dev->name);
                } else {
-                       dsta = sta_info_get(local, skb->data);
-                       if (dsta && dsta->sdata->dev == dev) {
+                       dsta = sta_info_get(sdata, skb->data);
+                       if (dsta) {
                                /*
                                 * The destination station is associated to
                                 * this AP (in this VLAN), so send the frame
@@ -1512,7 +1497,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        if (skb) {
                int align __maybe_unused;
 
-#if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                /*
                 * 'align' will only take the values 0 or 2 here
                 * since all frames are required to be aligned
@@ -1556,16 +1541,10 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
        struct net_device *dev = rx->sdata->dev;
-       struct ieee80211_local *local = rx->local;
-       u16 ethertype;
-       u8 *payload;
-       struct sk_buff *skb = rx->skb, *frame = NULL;
+       struct sk_buff *skb = rx->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
-       const struct ethhdr *eth;
-       int remaining, err;
-       u8 dst[ETH_ALEN];
-       u8 src[ETH_ALEN];
+       struct sk_buff_head frame_list;
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -1576,94 +1555,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(rx->flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       err = __ieee80211_data_to_8023(rx);
-       if (unlikely(err))
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+           !rx->sdata->u.vlan.sta)
                return RX_DROP_UNUSABLE;
 
-       skb->dev = dev;
-
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
-
-       /* skip the wrapping header */
-       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-       if (!eth)
+       if (is_multicast_ether_addr(hdr->addr1) &&
+           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+             rx->sdata->u.vlan.sta) ||
+            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+             rx->sdata->u.mgd.use_4addr)))
                return RX_DROP_UNUSABLE;
 
-       while (skb != frame) {
-               u8 padding;
-               __be16 len = eth->h_proto;
-               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
-
-               remaining = skb->len;
-               memcpy(dst, eth->h_dest, ETH_ALEN);
-               memcpy(src, eth->h_source, ETH_ALEN);
-
-               padding = ((4 - subframe_len) & 0x3);
-               /* the last MSDU has no padding */
-               if (subframe_len > remaining)
-                       return RX_DROP_UNUSABLE;
+       skb->dev = dev;
+       __skb_queue_head_init(&frame_list);
 
-               skb_pull(skb, sizeof(struct ethhdr));
-               /* if last subframe reuse skb */
-               if (remaining <= subframe_len + padding)
-                       frame = skb;
-               else {
-                       /*
-                        * Allocate and reserve two bytes more for payload
-                        * alignment since sizeof(struct ethhdr) is 14.
-                        */
-                       frame = dev_alloc_skb(
-                               ALIGN(local->hw.extra_tx_headroom, 4) +
-                               subframe_len + 2);
-
-                       if (frame == NULL)
-                               return RX_DROP_UNUSABLE;
-
-                       skb_reserve(frame,
-                                   ALIGN(local->hw.extra_tx_headroom, 4) +
-                                   sizeof(struct ethhdr) + 2);
-                       memcpy(skb_put(frame, ntohs(len)), skb->data,
-                               ntohs(len));
-
-                       eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
-                                                       padding);
-                       if (!eth) {
-                               dev_kfree_skb(frame);
-                               return RX_DROP_UNUSABLE;
-                       }
-               }
+       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+                                rx->sdata->vif.type,
+                                rx->local->hw.extra_tx_headroom);
 
-               skb_reset_network_header(frame);
-               frame->dev = dev;
-               frame->priority = skb->priority;
-               rx->skb = frame;
-
-               payload = frame->data;
-               ethertype = (payload[6] << 8) | payload[7];
-
-               if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-                           ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                          compare_ether_addr(payload,
-                                             bridge_tunnel_header) == 0)) {
-                       /* remove RFC1042 or Bridge-Tunnel
-                        * encapsulation and replace EtherType */
-                       skb_pull(frame, 6);
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               } else {
-                       memcpy(skb_push(frame, sizeof(__be16)),
-                              &len, sizeof(__be16));
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               }
+       while (!skb_queue_empty(&frame_list)) {
+               rx->skb = __skb_dequeue(&frame_list);
 
                if (!ieee80211_frame_allowed(rx, fc)) {
-                       if (skb == frame) /* last frame */
-                               return RX_DROP_UNUSABLE;
-                       dev_kfree_skb(frame);
+                       dev_kfree_skb(rx->skb);
                        continue;
                }
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += rx->skb->len;
 
                ieee80211_deliver_skb(rx);
        }
@@ -1721,7 +1640,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        /* Frame has reached destination.  Don't forward */
        if (!is_multicast_ether_addr(hdr->addr1) &&
-           compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
+           compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
        mesh_hdr->ttl--;
@@ -1738,10 +1657,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-                                                  sdata->dev->name);
+                                                  sdata->name);
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
+                       memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
                        info = IEEE80211_SKB_CB(fwd_skb);
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -1870,7 +1789,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        struct sk_buff *skb;
        struct ieee80211_mgmt *resp;
 
-       if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) {
+       if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) {
                /* Not to own unicast address */
                return;
        }
@@ -1894,7 +1813,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        resp = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(resp, 0, 24);
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
-       memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
        resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
@@ -2274,7 +2193,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (!bssid && !sdata->u.mgd.use_4addr)
                        return 0;
                if (!multicast &&
-                   compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
+                   compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2291,7 +2210,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!multicast &&
-                          compare_ether_addr(sdata->dev->dev_addr,
+                          compare_ether_addr(sdata->vif.addr,
                                              hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
@@ -2308,7 +2227,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                break;
        case NL80211_IFTYPE_MESH_POINT:
                if (!multicast &&
-                   compare_ether_addr(sdata->dev->dev_addr,
+                   compare_ether_addr(sdata->vif.addr,
                                       hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
@@ -2319,11 +2238,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_AP:
                if (!bssid) {
-                       if (compare_ether_addr(sdata->dev->dev_addr,
+                       if (compare_ether_addr(sdata->vif.addr,
                                               hdr->addr1))
                                return 0;
                } else if (!ieee80211_bssid_match(bssid,
-                                       sdata->dev->dev_addr)) {
+                                       sdata->vif.addr)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2362,6 +2281,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
+       struct sta_info *sta, *tmp;
+       bool found_sta = false;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        memset(&rx, 0, sizeof(rx));
@@ -2378,68 +2299,76 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       rx.sta = sta_info_get(local, hdr->addr2);
-       if (rx.sta)
-               rx.sdata = rx.sta->sdata;
-
-       if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
-               rx.flags |= IEEE80211_RX_RA_MATCH;
-               prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
-               if (prepares) {
-                       if (status->flag & RX_FLAG_MMIC_ERROR) {
-                               if (rx.flags & IEEE80211_RX_RA_MATCH)
-                                       ieee80211_rx_michael_mic_report(hdr, &rx);
-                       } else
-                               prev = rx.sdata;
+       if (ieee80211_is_data(hdr->frame_control)) {
+               for_each_sta_info(local, hdr->addr2, sta, tmp) {
+                       rx.sta = sta;
+                       found_sta = true;
+                       rx.sdata = sta->sdata;
+
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
+                       if (prepares) {
+                               if (status->flag & RX_FLAG_MMIC_ERROR) {
+                                       if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                               ieee80211_rx_michael_mic_report(hdr, &rx);
+                               } else
+                                       prev = rx.sdata;
+                       }
                }
-       } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
+       }
+       if (!found_sta) {
+               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (!netif_running(sdata->dev))
+                               continue;
 
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
-                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       continue;
+                       if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                               continue;
 
-               rx.flags |= IEEE80211_RX_RA_MATCH;
-               prepares = prepare_for_handlers(sdata, &rx, hdr);
+                       rx.sta = sta_info_get(sdata, hdr->addr2);
 
-               if (!prepares)
-                       continue;
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(sdata, &rx, hdr);
 
-               if (status->flag & RX_FLAG_MMIC_ERROR) {
-                       rx.sdata = sdata;
-                       if (rx.flags & IEEE80211_RX_RA_MATCH)
-                               ieee80211_rx_michael_mic_report(hdr, &rx);
-                       continue;
-               }
+                       if (!prepares)
+                               continue;
 
-               /*
-                * frame is destined for this interface, but if it's not
-                * also for the previous one we handle that after the
-                * loop to avoid copying the SKB once too much
-                */
+                       if (status->flag & RX_FLAG_MMIC_ERROR) {
+                               rx.sdata = sdata;
+                               if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                       ieee80211_rx_michael_mic_report(hdr,
+                                                                       &rx);
+                               continue;
+                       }
 
-               if (!prev) {
-                       prev = sdata;
-                       continue;
-               }
+                       /*
+                        * frame is destined for this interface, but if it's
+                        * not also for the previous one we handle that after
+                        * the loop to avoid copying the SKB once too much
+                        */
 
-               /*
-                * frame was destined for the previous interface
-                * so invoke RX handlers for it
-                */
+                       if (!prev) {
+                               prev = sdata;
+                               continue;
+                       }
 
-               skb_new = skb_copy(skb, GFP_ATOMIC);
-               if (!skb_new) {
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "%s: failed to copy "
-                                      "multicast frame for %s\n",
-                                      wiphy_name(local->hw.wiphy),
-                                      prev->dev->name);
-                       continue;
+                       /*
+                        * frame was destined for the previous interface
+                        * so invoke RX handlers for it
+                        */
+
+                       skb_new = skb_copy(skb, GFP_ATOMIC);
+                       if (!skb_new) {
+                               if (net_ratelimit())
+                                       printk(KERN_DEBUG "%s: failed to copy "
+                                              "multicast frame for %s\n",
+                                              wiphy_name(local->hw.wiphy),
+                                              prev->name);
+                               continue;
+                       }
+                       ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
+                       prev = sdata;
                }
-               ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
-               prev = sdata;
        }
        if (prev)
                ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
index f1a4c71..66da0ab 100644 (file)
@@ -147,7 +147,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        presp = ieee80211_is_probe_resp(fc);
        if (presp) {
                /* ignore ProbeResp to foreign address */
-               if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+               if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                        return RX_DROP_MONITOR;
 
                presp = true;
index aa743a8..7733f66 100644 (file)
@@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer for "
-                               "measurement report frame\n", sdata->dev->name);
+                               "measurement report frame\n", sdata->name);
                return;
        }
 
@@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
        msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
        memset(msr_report, 0, 24);
        memcpy(msr_report->da, da, ETH_ALEN);
-       memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(msr_report->bssid, bssid, ETH_ALEN);
        msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                IEEE80211_STYPE_ACTION);
index 71f370d..d1a77e7 100644 (file)
@@ -103,13 +103,16 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 }
 
 /* protected by RCU */
-struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
+struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+                             const u8 *addr)
 {
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
 
        sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
        while (sta) {
-               if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+               if (sta->sdata == sdata &&
+                   memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
                        break;
                sta = rcu_dereference(sta->hnext);
        }
@@ -369,7 +372,7 @@ int sta_info_insert(struct sta_info *sta)
                goto out_free;
        }
 
-       if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
+       if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
                    is_multicast_ether_addr(sta->sta.addr))) {
                err = -EINVAL;
                goto out_free;
@@ -377,7 +380,7 @@ int sta_info_insert(struct sta_info *sta)
 
        spin_lock_irqsave(&local->sta_lock, flags);
        /* check if STA exists already */
-       if (sta_info_get(local, sta->sta.addr)) {
+       if (sta_info_get(sdata, sta->sta.addr)) {
                spin_unlock_irqrestore(&local->sta_lock, flags);
                err = -EEXIST;
                goto out_free;
@@ -394,7 +397,7 @@ int sta_info_insert(struct sta_info *sta)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-               drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta);
+               drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta);
                sdata = sta->sdata;
        }
 
@@ -534,7 +537,7 @@ static void __sta_info_unlink(struct sta_info **sta)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-               drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
+               drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
                               &(*sta)->sta);
                sdata = (*sta)->sdata;
        }
@@ -828,7 +831,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                if (time_after(jiffies, sta->last_rx + exp_time)) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                        printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
-                              sdata->dev->name, sta->sta.addr);
+                              sdata->name, sta->sta.addr);
 #endif
                        __sta_info_unlink(&sta);
                        if (sta)
@@ -843,11 +846,12 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
 struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
                                               const u8 *addr)
 {
-       struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
+       struct sta_info *sta, *nxt;
 
-       if (!sta)
-               return NULL;
-       return &sta->sta;
+       /* Just return a random station ... first in list ... */
+       for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
+               return &sta->sta;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
 
@@ -872,7 +876,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        int sent, buffered;
 
-       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
+       drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
        if (!skb_queue_empty(&sta->ps_tx_buf))
                sta_info_clear_tim_bit(sta);
@@ -885,7 +889,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
-              "since STA not sleeping anymore\n", sdata->dev->name,
+              "since STA not sleeping anymore\n", sdata->name,
               sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
@@ -944,7 +948,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
                 */
                printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
                       "though there are no buffered frames for it\n",
-                      sdata->dev->name, sta->sta.addr);
+                      sdata->name, sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
        }
 }
index b4810f6..c820823 100644 (file)
@@ -403,9 +403,34 @@ static inline u32 get_sta_flags(struct sta_info *sta)
 #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
 
 /*
- * Get a STA info, must have be under RCU read lock.
+ * Get a STA info, must be under RCU read lock.
  */
-struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
+struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+                             const u8 *addr);
+
+static inline
+void for_each_sta_info_type_check(struct ieee80211_local *local,
+                                 const u8 *addr,
+                                 struct sta_info *sta,
+                                 struct sta_info *nxt)
+{
+}
+
+#define for_each_sta_info(local, _addr, sta, nxt)                      \
+       for (   /* initialise loop */                                   \
+               sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+               nxt = sta ? rcu_dereference(sta->hnext) : NULL;         \
+               /* typecheck */                                         \
+               for_each_sta_info_type_check(local, (_addr), sta, nxt), \
+               /* continue condition */                                \
+               sta;                                                    \
+               /* advance loop */                                      \
+               sta = nxt,                                              \
+               nxt = sta ? rcu_dereference(sta->hnext) : NULL          \
+            )                                                          \
+       /* compare address and run code only if it matches */           \
+       if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0)
+
 /*
  * Get STA info by index, BROKEN!
  */
index d78f36c..0c0850d 100644 (file)
@@ -134,6 +134,40 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
        dev_kfree_skb(skb);
 }
 
+static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
+{
+       struct ieee80211_mgmt *mgmt = (void *) skb->data;
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+       if (ieee80211_is_action(mgmt->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_STATION &&
+           mgmt->u.action.category == WLAN_CATEGORY_HT &&
+           mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
+               /*
+                * This update looks racy, but isn't -- if we come
+                * here we've definitely got a station that we're
+                * talking to, and on a managed interface that can
+                * only be the AP. And the only other place updating
+                * this variable is before we're associated.
+                */
+               switch (mgmt->u.action.u.ht_smps.smps_control) {
+               case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
+                       break;
+               case WLAN_HT_SMPS_CONTROL_STATIC:
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
+                       break;
+               case WLAN_HT_SMPS_CONTROL_DISABLED:
+               default: /* shouldn't happen since we don't send that */
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
+                       break;
+               }
+
+               ieee80211_queue_work(&local->hw, &local->recalc_smps);
+       }
+}
+
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct sk_buff *skb2;
@@ -146,7 +180,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_tx_status_rtap_hdr *rthdr;
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
-       struct sta_info *sta;
+       struct sta_info *sta, *tmp;
        int retry_count = -1, i;
        bool injected;
 
@@ -166,9 +200,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        sband = local->hw.wiphy->bands[info->band];
 
-       sta = sta_info_get(local, hdr->addr1);
+       for_each_sta_info(local, hdr->addr1, sta, tmp) {
+               /* skip wrong virtual interface */
+               if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
+                       continue;
 
-       if (sta) {
                if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
                    test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
@@ -208,6 +244,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                rate_control_tx_status(local, sband, sta, skb);
                if (ieee80211_vif_is_mesh(&sta->sdata->vif))
                        ieee80211s_update_metric(local, sta, skb);
+
+               if (!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+                   (info->flags & IEEE80211_TX_STAT_ACK))
+                       ieee80211_frame_acked(sta, skb);
        }
 
        rcu_read_unlock();
index 4921d72..b73454a 100644 (file)
@@ -100,7 +100,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx,
                p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
                p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
        }
-       ctx->initialized = 1;
+       ctx->state = TKIP_STATE_PHASE1_DONE;
 }
 
 static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
@@ -183,7 +183,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
        /* Update the p1k only when the iv16 in the packet wraps around, this
         * might occur after the wrap around of iv16 in the key in case of
         * fragmented packets. */
-       if (iv16 == 0 || !ctx->initialized)
+       if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
                tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32);
 
        if (type == IEEE80211_TKIP_P1_KEY) {
@@ -209,7 +209,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
        const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
 
        /* Calculate per-packet key */
-       if (ctx->iv16 == 0 || !ctx->initialized)
+       if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
                tkip_mixing_phase1(tk, ctx, ta, ctx->iv32);
 
        tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
@@ -259,7 +259,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
-       if (key->u.tkip.rx[queue].initialized &&
+       if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
            (iv32 < key->u.tkip.rx[queue].iv32 ||
             (iv32 == key->u.tkip.rx[queue].iv32 &&
              iv16 <= key->u.tkip.rx[queue].iv16))) {
@@ -275,11 +275,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
-               key->u.tkip.rx[queue].initialized = 1;
+               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
                goto done;
        }
 
-       if (!key->u.tkip.rx[queue].initialized ||
+       if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
            key->u.tkip.rx[queue].iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
                tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
@@ -299,18 +299,20 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                        printk("\n");
                }
 #endif
-               if (key->local->ops->update_tkip_key &&
-                       key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-                       static const u8 bcast[ETH_ALEN] =
-                               {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-                       const u8 *sta_addr = key->sta->sta.addr;
-
-                       if (is_multicast_ether_addr(ra))
-                               sta_addr = bcast;
-
-                       drv_update_tkip_key(key->local, &key->conf, sta_addr,
-                                           iv32, key->u.tkip.rx[queue].p1k);
-               }
+       }
+       if (key->local->ops->update_tkip_key &&
+           key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+           key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
+               static const u8 bcast[ETH_ALEN] =
+               {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+               const u8 *sta_addr = key->sta->sta.addr;
+
+               if (is_multicast_ether_addr(ra))
+                       sta_addr = bcast;
+
+               drv_update_tkip_key(key->local, &key->conf, sta_addr,
+                               iv32, key->u.tkip.rx[queue].p1k);
+               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
        }
 
        tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
index 8834cc9..ac48c86 100644 (file)
@@ -223,7 +223,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        printk(KERN_DEBUG "%s: dropped data frame to not "
                               "associated station %pM\n",
-                              tx->dev->name, hdr->addr1);
+                              tx->sdata->name, hdr->addr1);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
                        I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
                        return TX_DROP;
@@ -331,7 +331,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n",
-                              tx->dev->name);
+                              tx->sdata->name);
 #endif
                dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
        } else
@@ -391,7 +391,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: STA %pM TX "
                                       "buffer full - dropping oldest frame\n",
-                                      tx->dev->name, sta->sta.addr);
+                                      tx->sdata->name, sta->sta.addr);
                        }
 #endif
                        dev_kfree_skb(old);
@@ -416,7 +416,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        else if (unlikely(staflags & WLAN_STA_PS_STA)) {
                printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
-                      "set -> send frame\n", tx->dev->name,
+                      "set -> send frame\n", tx->sdata->name,
                       sta->sta.addr);
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -549,7 +549,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
                 "%s: Dropped data frame as no usable bitrate found while "
                 "scanning and associated. Target station: "
                 "%pM on %d GHz band\n",
-                tx->dev->name, hdr->addr1,
+                tx->sdata->name, hdr->addr1,
                 tx->channel->band ? 5 : 2))
                return TX_DROP;
 
@@ -1021,7 +1021,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
-       tx->dev = sdata->dev; /* use original interface */
        tx->local = local;
        tx->sdata = sdata;
        tx->channel = local->hw.conf.channel;
@@ -1055,7 +1054,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                tx->sta = rcu_dereference(sdata->u.vlan.sta);
        if (!tx->sta)
-               tx->sta = sta_info_get(local, hdr->addr1);
+               tx->sta = sta_info_get(sdata, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
@@ -1474,7 +1473,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                                        continue;
                                if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
-                               if (compare_ether_addr(tmp_sdata->dev->dev_addr,
+                               if (compare_ether_addr(tmp_sdata->vif.addr,
                                                       hdr->addr2) == 0) {
                                        sdata = tmp_sdata;
                                        break;
@@ -1638,7 +1637,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
-                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
@@ -1652,7 +1651,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
                /* DA BSSID SA */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 24;
                break;
@@ -1660,7 +1659,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
                memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 30;
@@ -1674,8 +1673,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        goto fail;
                }
 
-               if (compare_ether_addr(dev->dev_addr,
-                                         skb->data + ETH_ALEN) == 0) {
+               if (compare_ether_addr(sdata->vif.addr,
+                                      skb->data + ETH_ALEN) == 0) {
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        skb->data, skb->data + ETH_ALEN);
                        meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
@@ -1705,7 +1704,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                }
                        }
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
-                                       mesh_da, dev->dev_addr);
+                                       mesh_da, sdata->vif.addr);
                        rcu_read_unlock();
                        if (is_mesh_mcast)
                                meshhdrlen =
@@ -1730,7 +1729,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
-                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
@@ -1761,9 +1760,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
        if (!is_multicast_ether_addr(hdr.addr1)) {
                rcu_read_lock();
-               sta = sta_info_get(local, hdr.addr1);
-               /* XXX: in the future, use sdata to look up the sta */
-               if (sta && sta->sdata == sdata)
+               sta = sta_info_get(sdata, hdr.addr1);
+               if (sta)
                        sta_flags = get_sta_flags(sta);
                rcu_read_unlock();
        }
@@ -1782,7 +1780,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                unlikely(!is_multicast_ether_addr(hdr.addr1) &&
                      !(sta_flags & WLAN_STA_AUTHORIZED) &&
                      !(ethertype == ETH_P_PAE &&
-                      compare_ether_addr(dev->dev_addr,
+                      compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit())
@@ -1922,7 +1920,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
                ieee80211_tx(sdata, skb, true);
        } else {
                hdr = (struct ieee80211_hdr *)skb->data;
-               sta = sta_info_get(local, hdr->addr1);
+               sta = sta_info_get(sdata, hdr->addr1);
 
                ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
@@ -2146,8 +2144,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
-               memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
                mgmt->u.beacon.beacon_int =
                        cpu_to_le16(sdata->vif.bss_conf.beacon_int);
                mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
index 78a6e92..b019725 100644 (file)
@@ -469,7 +469,7 @@ void ieee80211_iterate_active_interfaces(
                        break;
                }
                if (netif_running(sdata->dev))
-                       iterator(data, sdata->dev->dev_addr,
+                       iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
 
@@ -503,7 +503,7 @@ void ieee80211_iterate_active_interfaces_atomic(
                        break;
                }
                if (netif_running(sdata->dev))
-                       iterator(data, sdata->dev->dev_addr,
+                       iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
 
@@ -848,7 +848,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                            sizeof(*mgmt) + 6 + extra_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
-                      "frame\n", sdata->dev->name);
+                      "frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -858,7 +858,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_AUTH);
        memcpy(mgmt->da, bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
        mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
        mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
@@ -908,16 +908,24 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
        }
 
        if (sband->ht_cap.ht_supported) {
-               __le16 tmp = cpu_to_le16(sband->ht_cap.cap);
+               u16 cap = sband->ht_cap.cap;
+               __le16 tmp;
+
+               if (ieee80211_disable_40mhz_24ghz &&
+                   sband->band == IEEE80211_BAND_2GHZ) {
+                       cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       cap &= ~IEEE80211_HT_CAP_SGI_40;
+               }
 
                *pos++ = WLAN_EID_HT_CAPABILITY;
                *pos++ = sizeof(struct ieee80211_ht_cap);
                memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+               tmp = cpu_to_le16(cap);
                memcpy(pos, &tmp, sizeof(u16));
                pos += sizeof(u16);
-               /* TODO: needs a define here for << 2 */
                *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density << 2);
+                        (sband->ht_cap.ampdu_density <<
+                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
                pos += sizeof(sband->ht_cap.mcs);
                pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
@@ -949,7 +957,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                            ie_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
-                      "request\n", sdata->dev->name);
+                      "request\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -958,7 +966,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        memset(mgmt, 0, 24);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_PROBE_REQ);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (dst) {
                memcpy(mgmt->da, dst, ETH_ALEN);
                memcpy(mgmt->bssid, dst, ETH_ALEN);
@@ -1051,7 +1059,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                    netif_running(sdata->dev)) {
                        conf.vif = &sdata->vif;
                        conf.type = sdata->vif.type;
-                       conf.mac_addr = sdata->dev->dev_addr;
+                       conf.mac_addr = sdata->vif.addr;
                        res = drv_add_interface(local, &conf);
                }
        }
@@ -1066,7 +1074,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-                       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
+                       drv_sta_notify(local, sdata, STA_NOTIFY_ADD,
                                       &sta->sta);
                }
                spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -1170,3 +1178,77 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        return 0;
 }
 
+static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
+                         enum ieee80211_smps_mode *smps_mode)
+{
+       if (ifmgd->associated) {
+               *smps_mode = ifmgd->ap_smps;
+
+               if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
+                       if (ifmgd->powersave)
+                               *smps_mode = IEEE80211_SMPS_DYNAMIC;
+                       else
+                               *smps_mode = IEEE80211_SMPS_OFF;
+               }
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/* must hold iflist_mtx */
+void ieee80211_recalc_smps(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *forsdata)
+{
+       struct ieee80211_sub_if_data *sdata;
+       enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
+       int count = 0;
+
+       if (forsdata)
+               WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx));
+
+       WARN_ON(!mutex_is_locked(&local->iflist_mtx));
+
+       /*
+        * This function could be improved to handle multiple
+        * interfaces better, but right now it makes any
+        * non-station interfaces force SM PS to be turned
+        * off. If there are multiple station interfaces it
+        * could also use the best possible mode, e.g. if
+        * one is in static and the other in dynamic then
+        * dynamic is ok.
+        */
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!netif_running(sdata->dev))
+                       continue;
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       goto set;
+               if (sdata != forsdata) {
+                       /*
+                        * This nested is ok -- we are holding the iflist_mtx
+                        * so can't get here twice or so. But it's required
+                        * since normally we acquire it first and then the
+                        * iflist_mtx.
+                        */
+                       mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
+                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+                       mutex_unlock(&sdata->u.mgd.mtx);
+               } else
+                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+
+               if (count > 1) {
+                       smps_mode = IEEE80211_SMPS_OFF;
+                       break;
+               }
+       }
+
+       if (smps_mode == local->smps_mode)
+               return;
+
+ set:
+       local->smps_mode = smps_mode;
+       /* changed flag is auto-detected for this */
+       ieee80211_hw_config(local, 0);
+}
diff --git a/net/wireless/.gitignore b/net/wireless/.gitignore
new file mode 100644 (file)
index 0000000..c33451b
--- /dev/null
@@ -0,0 +1 @@
+regdb.c
index 90e93a5..8419971 100644 (file)
@@ -109,6 +109,22 @@ config WIRELESS_OLD_REGULATORY
 
          Say N and if you say Y, please tell us why. The default is N.
 
+config CFG80211_INTERNAL_REGDB
+       bool "use statically compiled regulatory rules database" if EMBEDDED
+       default n
+       depends on CFG80211
+       ---help---
+         This option generates an internal data structure representing
+         the wireless regulatory rules described in net/wireless/db.txt
+         and includes code to query that database.  This is an alternative
+         to using CRDA for defining regulatory rules for the kernel.
+
+         For details see:
+
+         http://wireless.kernel.org/en/developers/Regulatory
+
+         Most distributions have a CRDA package.  So if unsure, say N.
+
 config CFG80211_WEXT
        bool "cfg80211 wireless extensions compatibility"
        depends on CFG80211
index f07c8dc..e77e508 100644 (file)
@@ -13,5 +13,11 @@ cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
 cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
+cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
 
 ccflags-y += -D__CHECK_ENDIAN__
+
+$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
+       @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@
+
+clean-files := regdb.c
index 4ef3efc..35b7121 100644 (file)
@@ -378,6 +378,8 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
                  struct wireless_dev *for_wdev,
                  int freq, enum nl80211_channel_type channel_type);
 
+u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)     WARN_ON(cond)
 #else
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
new file mode 100644 (file)
index 0000000..a2fc3a0
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# This file is a placeholder to prevent accidental build breakage if someone
+# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
+# enable that build option.
+#
+# You should be using CRDA instead.  It is even better if you use the CRDA
+# package provided by your distribution, since they will probably keep it
+# up-to-date on your behalf.
+#
+# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
+# need to replace this file with one containing appropriately formatted
+# regulatory rules that cover the regulatory domains you will be using.  Your
+# best option is to extract the db.txt file from the wireless-regdb git
+# repository:
+#
+#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
+#
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
new file mode 100644 (file)
index 0000000..8316cf0
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/bin/awk -f
+#
+# genregdb.awk -- generate regdb.c from db.txt
+#
+# Actually, it reads from stdin (presumed to be db.txt) and writes
+# to stdout (presumed to be regdb.c), but close enough...
+#
+# Copyright 2009 John W. Linville <linville@tuxdriver.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+
+BEGIN {
+       active = 0
+       rules = 0;
+       print "/*"
+       print " * DO NOT EDIT -- file generated from data in db.txt"
+       print " */"
+       print ""
+       print "#include <linux/nl80211.h>"
+       print "#include <net/cfg80211.h>"
+       print ""
+       regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
+}
+
+/^[ \t]*#/ {
+       /* Ignore */
+}
+
+!active && /^[ \t]*$/ {
+       /* Ignore */
+}
+
+!active && /country/ {
+       country=$2
+       sub(/:/, "", country)
+       printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
+       printf "\t.alpha2 = \"%s\",\n", country
+       printf "\t.reg_rules = {\n"
+       active = 1
+       regdb = regdb "\t&regdom_" country ",\n"
+}
+
+active && /^[ \t]*\(/ {
+       start = $1
+       sub(/\(/, "", start)
+       end = $3
+       bw = $5
+       sub(/\),/, "", bw)
+       gain = $6
+       sub(/\(/, "", gain)
+       sub(/,/, "", gain)
+       power = $7
+       sub(/\)/, "", power)
+       sub(/,/, "", power)
+       # power might be in mW...
+       units = $8
+       sub(/\)/, "", units)
+       sub(/,/, "", units)
+       if (units == "mW") {
+               if (power == 100) {
+                       power = 20
+               } else if (power == 200) {
+                       power = 23
+               } else if (power == 500) {
+                       power = 27
+               } else if (power == 1000) {
+                       power = 30
+               } else {
+                       print "Unknown power value in database!"
+               }
+       }
+       flagstr = ""
+       for (i=8; i<=NF; i++)
+               flagstr = flagstr $i
+       split(flagstr, flagarray, ",")
+       flags = ""
+       for (arg in flagarray) {
+               if (flagarray[arg] == "NO-OFDM") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | "
+               } else if (flagarray[arg] == "NO-CCK") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | "
+               } else if (flagarray[arg] == "NO-INDOOR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | "
+               } else if (flagarray[arg] == "NO-OUTDOOR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | "
+               } else if (flagarray[arg] == "DFS") {
+                       flags = flags "\n\t\t\tNL80211_RRF_DFS | "
+               } else if (flagarray[arg] == "PTP-ONLY") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | "
+               } else if (flagarray[arg] == "PTMP-ONLY") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
+               } else if (flagarray[arg] == "PASSIVE-SCAN") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | "
+               } else if (flagarray[arg] == "NO-IBSS") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | "
+               }
+       }
+       flags = flags "0"
+       printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags
+       rules++
+}
+
+active && /^[ \t]*$/ {
+       active = 0
+       printf "\t},\n"
+       printf "\t.n_reg_rules = %d\n", rules
+       printf "};\n\n"
+       rules = 0;
+}
+
+END {
+       print regdb "};"
+       print ""
+       print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
+}
index 1001db4..acaeaa7 100644 (file)
@@ -137,22 +137,23 @@ void __cfg80211_send_deauth(struct net_device *dev,
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        const u8 *bssid = mgmt->bssid;
        int i;
+       bool found = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
-
        if (wdev->current_bss &&
            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
                cfg80211_unhold_bss(wdev->current_bss);
                cfg80211_put_bss(&wdev->current_bss->pub);
                wdev->current_bss = NULL;
+               found = true;
        } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
                if (wdev->auth_bsses[i] &&
                    memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
                        cfg80211_unhold_bss(wdev->auth_bsses[i]);
                        cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
                        wdev->auth_bsses[i] = NULL;
+                       found = true;
                        break;
                }
                if (wdev->authtry_bsses[i] &&
@@ -160,10 +161,16 @@ void __cfg80211_send_deauth(struct net_device *dev,
                        cfg80211_unhold_bss(wdev->authtry_bsses[i]);
                        cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
                        wdev->authtry_bsses[i] = NULL;
+                       found = true;
                        break;
                }
        }
 
+       if (!found)
+               return;
+
+       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
+
        if (wdev->sme_state == CFG80211_SME_CONNECTED) {
                u16 reason_code;
                bool from_ap;
index a602843..7cb0d64 100644 (file)
@@ -1637,39 +1637,6 @@ static int parse_station_flags(struct genl_info *info,
        return 0;
 }
 
-static u16 nl80211_calculate_bitrate(struct rate_info *rate)
-{
-       int modulation, streams, bitrate;
-
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
-               return rate->legacy;
-
-       /* the formula below does only work for MCS values smaller than 32 */
-       if (rate->mcs >= 32)
-               return 0;
-
-       modulation = rate->mcs & 7;
-       streams = (rate->mcs >> 3) + 1;
-
-       bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
-                       13500000 : 6500000;
-
-       if (modulation < 4)
-               bitrate *= (modulation + 1);
-       else if (modulation == 4)
-               bitrate *= (modulation + 2);
-       else
-               bitrate *= (modulation + 3);
-
-       bitrate *= streams;
-
-       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
-               bitrate = (bitrate / 9) * 10;
-
-       /* do NOT round down here */
-       return (bitrate + 50000) / 100000;
-}
-
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
                                int flags, struct net_device *dev,
                                u8 *mac_addr, struct station_info *sinfo)
@@ -1716,8 +1683,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
                if (!txrate)
                        goto nla_put_failure;
 
-               /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
-               bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
+               /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
+               bitrate = cfg80211_calculate_bitrate(&sinfo->txrate);
                if (bitrate > 0)
                        NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
 
index baa898a..dc13c3f 100644 (file)
@@ -40,6 +40,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "regdb.h"
 #include "nl80211.h"
 
 /* Receipt of information from last regulatory request */
@@ -335,6 +336,98 @@ static bool country_ie_integrity_changes(u32 checksum)
        return false;
 }
 
+static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
+                        const struct ieee80211_regdomain *src_regd)
+{
+       struct ieee80211_regdomain *regd;
+       int size_of_regd = 0;
+       unsigned int i;
+
+       size_of_regd = sizeof(struct ieee80211_regdomain) +
+         ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+       regd = kzalloc(size_of_regd, GFP_KERNEL);
+       if (!regd)
+               return -ENOMEM;
+
+       memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
+
+       for (i = 0; i < src_regd->n_reg_rules; i++)
+               memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
+                       sizeof(struct ieee80211_reg_rule));
+
+       *dst_regd = regd;
+       return 0;
+}
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+struct reg_regdb_search_request {
+       char alpha2[2];
+       struct list_head list;
+};
+
+static LIST_HEAD(reg_regdb_search_list);
+static DEFINE_SPINLOCK(reg_regdb_search_lock);
+
+static void reg_regdb_search(struct work_struct *work)
+{
+       struct reg_regdb_search_request *request;
+       const struct ieee80211_regdomain *curdom, *regdom;
+       int i, r;
+
+       spin_lock(&reg_regdb_search_lock);
+       while (!list_empty(&reg_regdb_search_list)) {
+               request = list_first_entry(&reg_regdb_search_list,
+                                          struct reg_regdb_search_request,
+                                          list);
+               list_del(&request->list);
+
+               for (i=0; i<reg_regdb_size; i++) {
+                       curdom = reg_regdb[i];
+
+                       if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
+                               r = reg_copy_regd(&regdom, curdom);
+                               if (r)
+                                       break;
+                               spin_unlock(&reg_regdb_search_lock);
+                               mutex_lock(&cfg80211_mutex);
+                               set_regdom(regdom);
+                               mutex_unlock(&cfg80211_mutex);
+                               spin_lock(&reg_regdb_search_lock);
+                               break;
+                       }
+               }
+
+               kfree(request);
+       }
+       spin_unlock(&reg_regdb_search_lock);
+}
+
+static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+
+static void reg_regdb_query(const char *alpha2)
+{
+       struct reg_regdb_search_request *request;
+
+       if (!alpha2)
+               return;
+
+       request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
+       if (!request)
+               return;
+
+       memcpy(request->alpha2, alpha2, 2);
+
+       spin_lock(&reg_regdb_search_lock);
+       list_add_tail(&request->list, &reg_regdb_search_list);
+       spin_unlock(&reg_regdb_search_lock);
+
+       schedule_work(&reg_regdb_work);
+}
+#else
+static inline void reg_regdb_query(const char *alpha2) {}
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
 /*
  * This lets us keep regulatory code which is updated on a regulatory
  * basis in userspace.
@@ -354,6 +447,9 @@ static int call_crda(const char *alpha2)
                printk(KERN_INFO "cfg80211: Calling CRDA to update world "
                        "regulatory domain\n");
 
+       /* query internal regulatory database (if it exists) */
+       reg_regdb_query(alpha2);
+
        country_env[8] = alpha2[0];
        country_env[9] = alpha2[1];
 
@@ -1342,30 +1438,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
-static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
-                        const struct ieee80211_regdomain *src_regd)
-{
-       struct ieee80211_regdomain *regd;
-       int size_of_regd = 0;
-       unsigned int i;
-
-       size_of_regd = sizeof(struct ieee80211_regdomain) +
-         ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
-
-       regd = kzalloc(size_of_regd, GFP_KERNEL);
-       if (!regd)
-               return -ENOMEM;
-
-       memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
-
-       for (i = 0; i < src_regd->n_reg_rules; i++)
-               memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
-                       sizeof(struct ieee80211_reg_rule));
-
-       *dst_regd = regd;
-       return 0;
-}
-
 /*
  * Return value which can be used by ignore_request() to indicate
  * it has been determined we should intersect two regulatory domains
diff --git a/net/wireless/regdb.h b/net/wireless/regdb.h
new file mode 100644 (file)
index 0000000..818222c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __REGDB_H__
+#define __REGDB_H__
+
+extern const struct ieee80211_regdomain *reg_regdb[];
+extern int reg_regdb_size;
+
+#endif /* __REGDB_H__ */
index 59361fd..23557c1 100644 (file)
@@ -285,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
        }
 }
 
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -383,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_to_8023);
 
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype, u8 *bssid, bool qos)
 {
        struct ieee80211_hdr hdr;
@@ -497,6 +497,101 @@ int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_from_8023);
 
+
+void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom)
+{
+       struct sk_buff *frame = NULL;
+       u16 ethertype;
+       u8 *payload;
+       const struct ethhdr *eth;
+       int remaining, err;
+       u8 dst[ETH_ALEN], src[ETH_ALEN];
+
+       err = ieee80211_data_to_8023(skb, addr, iftype);
+       if (err)
+               goto out;
+
+       /* skip the wrapping header */
+       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+       if (!eth)
+               goto out;
+
+       while (skb != frame) {
+               u8 padding;
+               __be16 len = eth->h_proto;
+               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+               remaining = skb->len;
+               memcpy(dst, eth->h_dest, ETH_ALEN);
+               memcpy(src, eth->h_source, ETH_ALEN);
+
+               padding = (4 - subframe_len) & 0x3;
+               /* the last MSDU has no padding */
+               if (subframe_len > remaining)
+                       goto purge;
+
+               skb_pull(skb, sizeof(struct ethhdr));
+               /* reuse skb for the last subframe */
+               if (remaining <= subframe_len + padding)
+                       frame = skb;
+               else {
+                       unsigned int hlen = ALIGN(extra_headroom, 4);
+                       /*
+                        * Allocate and reserve two bytes more for payload
+                        * alignment since sizeof(struct ethhdr) is 14.
+                        */
+                       frame = dev_alloc_skb(hlen + subframe_len + 2);
+                       if (!frame)
+                               goto purge;
+
+                       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
+                       memcpy(skb_put(frame, ntohs(len)), skb->data,
+                               ntohs(len));
+
+                       eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
+                                                       padding);
+                       if (!eth) {
+                               dev_kfree_skb(frame);
+                               goto purge;
+                       }
+               }
+
+               skb_reset_network_header(frame);
+               frame->dev = skb->dev;
+               frame->priority = skb->priority;
+
+               payload = frame->data;
+               ethertype = (payload[6] << 8) | payload[7];
+
+               if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+                           ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+                          compare_ether_addr(payload,
+                                             bridge_tunnel_header) == 0)) {
+                       /* remove RFC1042 or Bridge-Tunnel
+                        * encapsulation and replace EtherType */
+                       skb_pull(frame, 6);
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               } else {
+                       memcpy(skb_push(frame, sizeof(__be16)), &len,
+                               sizeof(__be16));
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               }
+               __skb_queue_tail(list, frame);
+       }
+
+       return;
+
+ purge:
+       __skb_queue_purge(list);
+ out:
+       dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
+
 /* Given a data frame determine the 802.1p/1d tag to use. */
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 {
@@ -720,3 +815,36 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
        return err;
 }
+
+u16 cfg80211_calculate_bitrate(struct rate_info *rate)
+{
+       int modulation, streams, bitrate;
+
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+               return rate->legacy;
+
+       /* the formula below does only work for MCS values smaller than 32 */
+       if (rate->mcs >= 32)
+               return 0;
+
+       modulation = rate->mcs & 7;
+       streams = (rate->mcs >> 3) + 1;
+
+       bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
+                       13500000 : 6500000;
+
+       if (modulation < 4)
+               bitrate *= (modulation + 1);
+       else if (modulation == 4)
+               bitrate *= (modulation + 2);
+       else
+               bitrate *= (modulation + 3);
+
+       bitrate *= streams;
+
+       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+               bitrate = (bitrate / 9) * 10;
+
+       /* do NOT round down here */
+       return (bitrate + 50000) / 100000;
+}
index 54face3..4198243 100644 (file)
@@ -1257,10 +1257,7 @@ int cfg80211_wext_giwrate(struct net_device *dev,
        if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
                return -EOPNOTSUPP;
 
-       rate->value = 0;
-
-       if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
-               rate->value = 100000 * sinfo.txrate.legacy;
+       rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
 
        return 0;
 }