]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Tue, 8 Jul 2008 23:30:17 +0000 (16:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Jul 2008 23:30:17 +0000 (16:30 -0700)
Conflicts:

drivers/net/wireless/iwlwifi/iwl-3945.c
net/mac80211/mlme.c

1  2 
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/zd1211rw/zd_usb.c
net/ipv6/addrconf.c
net/mac80211/main.c
net/mac80211/mlme.c
net/sctp/sm_statefuns.c

index 38866ab0040faaa15ad71dca119c9371af3cd188,55ac850744b343024189ec0db16efc10e0d9aec9..94e177a9f51ca0d3e39b4dd44b3caf8440e525ef
@@@ -283,7 -283,8 +283,7 @@@ static void iwl3945_tx_queue_reclaim(st
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
  
                tx_info = &txq->txb[txq->q.read_ptr];
 -              ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0],
 -                                          &tx_info->status);
 +              ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
                tx_info->skb[0] = NULL;
                iwl3945_hw_txq_free_tfd(priv, txq);
        }
@@@ -305,7 -306,7 +305,7 @@@ static void iwl3945_rx_reply_tx(struct 
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
        struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
 -      struct ieee80211_tx_status *tx_status;
 +      struct ieee80211_tx_info *info;
        struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
        u32  status = le32_to_cpu(tx_resp->status);
        int rate_idx;
                return;
        }
  
 -      tx_status = &(txq->txb[txq->q.read_ptr].status);
 +      info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
 +      memset(&info->status, 0, sizeof(info->status));
  
 -      tx_status->retry_count = tx_resp->failure_frame;
 +      info->status.retry_count = tx_resp->failure_frame;
        /* tx_status->rts_retry_count = tx_resp->failure_rts; */
 -      tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
 -                              IEEE80211_TX_STATUS_ACK : 0;
 +      info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
 +                              IEEE80211_TX_STAT_ACK : 0;
  
        IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
                        txq_id, iwl3945_get_tx_fail_reason(status), status,
                        tx_resp->rate, tx_resp->failure_frame);
  
        rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
 -      tx_status->control.tx_rate = &priv->ieee_rates[rate_idx];
 +      if (info->band == IEEE80211_BAND_5GHZ)
 +              rate_idx -= IWL_FIRST_OFDM_RATE;
 +      info->tx_rate_idx = rate_idx;
        IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
        iwl3945_tx_queue_reclaim(priv, txq_id, index);
  
@@@ -388,7 -386,7 +388,7 @@@ static void iwl3945_dbg_report_frame(st
        u32 print_dump = 0;     /* set to 1 to dump all frames' contents */
        u32 hundred = 0;
        u32 dataframe = 0;
 -      u16 fc;
 +      __le16 fc;
        u16 seq_ctl;
        u16 channel;
        u16 phy_flags;
        u8 *data = IWL_RX_DATA(pkt);
  
        /* MAC header */
 -      fc = le16_to_cpu(header->frame_control);
 +      fc = header->frame_control;
        seq_ctl = le16_to_cpu(header->seq_ctrl);
  
        /* metadata */
  
        /* if data frame is to us and all is good,
         *   (optionally) print summary for only 1 out of every 100 */
 -      if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
 -          (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
 +      if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
 +          cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
                dataframe = 1;
                if (!group100)
                        print_summary = 1;      /* print each frame */
  
        if (print_summary) {
                char *title;
-               u32 rate;
+               int rate;
  
                if (hundred)
                        title = "100Frames";
 -              else if (fc & IEEE80211_FCTL_RETRY)
 +              else if (ieee80211_has_retry(fc))
                        title = "Retry";
 -              else if (ieee80211_is_assoc_response(fc))
 +              else if (ieee80211_is_assoc_resp(fc))
                        title = "AscRsp";
 -              else if (ieee80211_is_reassoc_response(fc))
 +              else if (ieee80211_is_reassoc_resp(fc))
                        title = "RasRsp";
 -              else if (ieee80211_is_probe_response(fc)) {
 +              else if (ieee80211_is_probe_resp(fc)) {
                        title = "PrbRsp";
                        print_dump = 1; /* dump frame contents */
                } else if (ieee80211_is_beacon(fc)) {
                 *    but you can hack it to show more, if you'd like to. */
                if (dataframe)
                        IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+                                    "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
 -                                   title, fc, header->addr1[5],
 +                                   title, le16_to_cpu(fc), header->addr1[5],
                                     length, rssi, channel, rate);
                else {
                        /* src/dst addresses assume managed mode */
                        IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
                                     "src=0x%02x, rssi=%u, tim=%lu usec, "
                                     "phy=0x%02x, chnl=%d\n",
 -                                   title, fc, header->addr1[5],
 +                                   title, le16_to_cpu(fc), header->addr1[5],
                                     header->addr3[5], rssi,
                                     tsf_low - priv->scan_start_tsf,
                                     phy_flags, channel);
@@@ -522,7 -520,7 +522,7 @@@ static void iwl3945_add_radiotap(struc
  {
        /* First cache any information we need before we overwrite
         * the information provided in the skb from the hardware */
 -      s8 signal = stats->ssi;
 +      s8 signal = stats->signal;
        s8 noise = 0;
        int rate = stats->rate_idx;
        u64 tsf = stats->mactime;
@@@ -699,7 -697,7 +699,7 @@@ static void iwl3945_rx_reply_rx(struct 
        }
  
        /* Convert 3945's rssi indicator to dBm */
 -      rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
 +      rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
  
        /* Set default noise value to -127 */
        if (priv->last_rx_noise == 0)
         * Calculate rx_status.signal (quality indicator in %) based on SNR. */
        if (rx_stats_noise_diff) {
                snr = rx_stats_sig_avg / rx_stats_noise_diff;
 -              rx_status.noise = rx_status.ssi -
 +              rx_status.noise = rx_status.signal -
                                        iwl3945_calc_db_from_ratio(snr);
 -              rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi,
 +              rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
                                                         rx_status.noise);
  
        /* If noise info not available, calculate signal quality indicator (%)
         *   using just the dBm signal level. */
        } else {
                rx_status.noise = priv->last_rx_noise;
 -              rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0);
 +              rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
        }
  
  
        IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
 -                      rx_status.ssi, rx_status.noise, rx_status.signal,
 +                      rx_status.signal, rx_status.noise, rx_status.qual,
                        rx_stats_sig_avg, rx_stats_noise_diff);
  
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
        IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
                              network_packet ? '*' : ' ',
                              le16_to_cpu(rx_hdr->channel),
 -                            rx_status.ssi, rx_status.ssi,
 -                            rx_status.ssi, rx_status.rate_idx);
 +                            rx_status.signal, rx_status.signal,
 +                            rx_status.noise, rx_status.rate_idx);
  
  #ifdef CONFIG_IWL3945_DEBUG
        if (iwl3945_debug_level & (IWL_DL_RX))
        if (network_packet) {
                priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
                priv->last_tsf = le64_to_cpu(rx_end->timestamp);
 -              priv->last_rx_rssi = rx_status.ssi;
 +              priv->last_rx_rssi = rx_status.signal;
                priv->last_rx_noise = rx_status.noise;
        }
  
@@@ -964,24 -962,23 +964,24 @@@ u8 iwl3945_hw_find_station(struct iwl39
  */
  void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
                              struct iwl3945_cmd *cmd,
 -                            struct ieee80211_tx_control *ctrl,
 +                            struct ieee80211_tx_info *info,
                              struct ieee80211_hdr *hdr, int sta_id, int tx_id)
  {
        unsigned long flags;
 -      u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
 +      u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
 +      u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
        u16 rate_mask;
        int rate;
        u8 rts_retry_limit;
        u8 data_retry_limit;
        __le32 tx_flags;
 -      u16 fc = le16_to_cpu(hdr->frame_control);
 +      __le16 fc = hdr->frame_control;
  
        rate = iwl3945_rates[rate_index].plcp;
        tx_flags = cmd->cmd.tx.tx_flags;
  
        /* We need to figure out how to get the sta->supp_rates while
 -       * in this running context; perhaps encoding into ctrl->tx_rate? */
 +       * in this running context */
        rate_mask = IWL_RATES_MASK;
  
        spin_lock_irqsave(&priv->sta_lock, flags);
        else
                rts_retry_limit = 7;
  
 -      if (ieee80211_is_probe_response(fc)) {
 +      if (ieee80211_is_probe_resp(fc)) {
                data_retry_limit = 3;
                if (data_retry_limit < rts_retry_limit)
                        rts_retry_limit = data_retry_limit;
        if (priv->data_retry_limit != -1)
                data_retry_limit = priv->data_retry_limit;
  
 -      if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 -              switch (fc & IEEE80211_FCTL_STYPE) {
 -              case IEEE80211_STYPE_AUTH:
 -              case IEEE80211_STYPE_DEAUTH:
 -              case IEEE80211_STYPE_ASSOC_REQ:
 -              case IEEE80211_STYPE_REASSOC_REQ:
 +      if (ieee80211_is_mgmt(fc)) {
 +              switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
 +              case cpu_to_le16(IEEE80211_STYPE_AUTH):
 +              case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
 +              case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
 +              case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
                        if (tx_flags & TX_CMD_FLG_RTS_MSK) {
                                tx_flags &= ~TX_CMD_FLG_RTS_MSK;
                                tx_flags |= TX_CMD_FLG_CTS_MSK;
@@@ -1236,7 -1233,7 +1236,7 @@@ int iwl3945_hw_nic_init(struct iwl3945_
        iwl3945_power_init_handle(priv);
  
        spin_lock_irqsave(&priv->lock, flags);
 -      iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
 +      iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL);
        iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
                    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
  
index 1ccff240bf973c917c5c3e8a2cbb6aae8a8bd8f5,6cdad97646049bd89d49ce5128751b8c8d59e746..da8b7433e3a69b731c5d534bb86d1f9a46bb301f
@@@ -64,6 -64,7 +64,7 @@@ static struct usb_device_id usb_ids[] 
        { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
@@@ -169,11 -170,10 +170,11 @@@ static int upload_code(struct usb_devic
        if (flags & REBOOT) {
                u8 ret;
  
 +              /* Use "DMA-aware" buffer. */
                r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                        USB_REQ_FIRMWARE_CONFIRM,
                        USB_DIR_IN | USB_TYPE_VENDOR,
 -                      0, 0, &ret, sizeof(ret), 5000 /* ms */);
 +                      0, 0, p, sizeof(ret), 5000 /* ms */);
                if (r != sizeof(ret)) {
                        dev_err(&udev->dev,
                                "control request firmeware confirmation failed."
                                r = -ENODEV;
                        goto error;
                }
 +              ret = p[0];
                if (ret & 0x80) {
                        dev_err(&udev->dev,
                                "Internal error while downloading."
@@@ -314,31 -313,22 +315,31 @@@ int zd_usb_read_fw(struct zd_usb *usb, 
  {
        int r;
        struct usb_device *udev = zd_usb_to_usbdev(usb);
 +      u8 *buf;
  
 +      /* Use "DMA-aware" buffer. */
 +      buf = kmalloc(len, GFP_KERNEL);
 +      if (!buf)
 +              return -ENOMEM;
        r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
 -              data, len, 5000);
 +              buf, len, 5000);
        if (r < 0) {
                dev_err(&udev->dev,
                        "read over firmware interface failed: %d\n", r);
 -              return r;
 +              goto exit;
        } else if (r != len) {
                dev_err(&udev->dev,
                        "incomplete read over firmware interface: %d/%d\n",
                        r, len);
 -              return -EIO;
 +              r = -EIO;
 +              goto exit;
        }
 -
 -      return 0;
 +      r = 0;
 +      memcpy(data, buf, len);
 +exit:
 +      kfree(buf);
 +      return r;
  }
  
  #define urb_dev(urb) (&(urb)->dev->dev)
@@@ -880,7 -870,7 +881,7 @@@ static void tx_urb_complete(struct urb 
  {
        int r;
        struct sk_buff *skb;
 -      struct zd_tx_skb_control_block *cb;
 +      struct ieee80211_tx_info *info;
        struct zd_usb *usb;
  
        switch (urb->status) {
@@@ -904,8 -894,8 +905,8 @@@ free_urb
         * grab 'usb' pointer before handing off the skb (since
         * it might be freed by zd_mac_tx_to_dev or mac80211)
         */
 -      cb = (struct zd_tx_skb_control_block *)skb->cb;
 -      usb = &zd_hw_mac(cb->hw)->chip.usb;
 +      info = IEEE80211_SKB_CB(skb);
 +      usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
        zd_mac_tx_to_dev(skb, urb->status);
        free_tx_urb(usb, urb);
        tx_dec_submitted_urbs(usb);
diff --combined net/ipv6/addrconf.c
index 2ec73e62202c18b741adc862168c7e0da854be3a,ff61a5cdb0b3c9a927205f34ef355a0b8812ff72..8572cb05fc21205db6be341e7aceb8d13f84bae1
@@@ -6,6 -6,8 +6,6 @@@
   *    Pedro Roque             <roque@di.fc.ul.pt>
   *    Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
   *
 - *    $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
 - *
   *    This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
@@@ -119,7 -121,6 +119,7 @@@ static void ipv6_regen_rndid(unsigned l
  static int desync_factor = MAX_DESYNC_FACTOR * HZ;
  #endif
  
 +static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
  static int ipv6_count_addresses(struct inet6_dev *idev);
  
  /*
@@@ -184,8 -185,6 +184,8 @@@ struct ipv6_devconf ipv6_devconf __read
  #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
 +      .disable_ipv6           = 0,
 +      .accept_dad             = 1,
  };
  
  static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
  #endif
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
 +      .disable_ipv6           = 0,
 +      .accept_dad             = 1,
  };
  
  /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@@ -234,12 -231,6 +234,12 @@@ static inline int addrconf_qdisc_ok(str
        return (dev->qdisc != &noop_qdisc);
  }
  
 +/* Check if a route is valid prefix route */
 +static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
 +{
 +      return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0);
 +}
 +
  static void addrconf_del_timer(struct inet6_ifaddr *ifp)
  {
        if (del_timer(&ifp->timer))
@@@ -353,8 -344,6 +353,8 @@@ static struct inet6_dev * ipv6_add_dev(
                kfree(ndev);
                return NULL;
        }
 +      if (ndev->cnf.forwarding)
 +              dev_disable_lro(dev);
        /* We refer to the device */
        dev_hold(dev);
  
         */
        in6_dev_hold(ndev);
  
 +      if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
 +              ndev->cnf.accept_dad = -1;
 +
  #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
        if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
                printk(KERN_INFO
@@@ -452,8 -438,6 +452,8 @@@ static void dev_forward_change(struct i
        if (!idev)
                return;
        dev = idev->dev;
 +      if (idev->cnf.forwarding)
 +              dev_disable_lro(dev);
        if (dev && (dev->flags & IFF_MULTICAST)) {
                if (idev->cnf.forwarding)
                        ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
@@@ -499,14 -483,12 +499,14 @@@ static void addrconf_fixup_forwarding(s
        if (p == &net->ipv6.devconf_dflt->forwarding)
                return;
  
 +      rtnl_lock();
        if (p == &net->ipv6.devconf_all->forwarding) {
                __s32 newf = net->ipv6.devconf_all->forwarding;
                net->ipv6.devconf_dflt->forwarding = newf;
                addrconf_forward_change(net, newf);
        } else if ((!*p) ^ (!old))
                dev_forward_change((struct inet6_dev *)table->extra1);
 +      rtnl_unlock();
  
        if (*p)
                rt6_purge_dflt_routers(net);
@@@ -586,13 -568,6 +586,13 @@@ ipv6_add_addr(struct inet6_dev *idev, c
        struct rt6_info *rt;
        int hash;
        int err = 0;
 +      int addr_type = ipv6_addr_type(addr);
 +
 +      if (addr_type == IPV6_ADDR_ANY ||
 +          addr_type & IPV6_ADDR_MULTICAST ||
 +          (!(idev->dev->flags & IFF_LOOPBACK) &&
 +           addr_type & IPV6_ADDR_LOOPBACK))
 +              return ERR_PTR(-EADDRNOTAVAIL);
  
        rcu_read_lock_bh();
        if (idev->dead) {
@@@ -774,12 -749,12 +774,12 @@@ static void ipv6_del_addr(struct inet6_
        }
        write_unlock_bh(&idev->lock);
  
+       addrconf_del_timer(ifp);
        ipv6_ifa_notify(RTM_DELADDR, ifp);
  
        atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
  
-       addrconf_del_timer(ifp);
        /*
         * Purge or update corresponding prefix
         *
                ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
                rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
  
 -              if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 +              if (rt && addrconf_is_prefix_route(rt)) {
                        if (onlink == 0) {
                                ip6_del_rt(rt);
                                rt = NULL;
@@@ -983,8 -958,7 +983,8 @@@ static inline int ipv6_saddr_preferred(
        return 0;
  }
  
 -static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
 +static int ipv6_get_saddr_eval(struct net *net,
 +                             struct ipv6_saddr_score *score,
                               struct ipv6_saddr_dst *dst,
                               int i)
  {
                break;
        case IPV6_SADDR_RULE_LABEL:
                /* Rule 6: Prefer matching label */
 -              ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
 +              ret = ipv6_addr_label(net,
 +                                    &score->ifa->addr, score->addr_type,
                                      score->ifa->idev->dev->ifindex) == dst->label;
                break;
  #ifdef CONFIG_IPV6_PRIVACY
@@@ -1118,7 -1091,7 +1118,7 @@@ int ipv6_dev_get_saddr(struct net_devic
        dst.addr = daddr;
        dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
        dst.scope = __ipv6_addr_src_scope(dst_type);
 -      dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
 +      dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
        dst.prefs = prefs;
  
        hiscore->rule = -1;
                        for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
                                int minihiscore, miniscore;
  
 -                              minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
 -                              miniscore = ipv6_get_saddr_eval(score, &dst, i);
 +                              minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
 +                              miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
  
                                if (minihiscore > miniscore) {
                                        if (i == IPV6_SADDR_RULE_SCOPE &&
@@@ -1427,20 -1400,6 +1427,20 @@@ static void addrconf_dad_stop(struct in
  
  void addrconf_dad_failure(struct inet6_ifaddr *ifp)
  {
 +      struct inet6_dev *idev = ifp->idev;
 +      if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
 +              struct in6_addr addr;
 +
 +              addr.s6_addr32[0] = htonl(0xfe800000);
 +              addr.s6_addr32[1] = 0;
 +
 +              if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
 +                  ipv6_addr_equal(&ifp->addr, &addr)) {
 +                      /* DAD failed for link-local based on MAC address */
 +                      idev->cnf.disable_ipv6 = 1;
 +              }
 +      }
 +
        if (net_ratelimit())
                printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
        addrconf_dad_stop(ifp);
@@@ -1829,7 -1788,7 +1829,7 @@@ void addrconf_prefix_rcv(struct net_dev
                rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
                                dev->ifindex, 1);
  
 -              if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 +              if (rt && addrconf_is_prefix_route(rt)) {
                        /* Autoconf prefix route */
                        if (valid_lft == 0) {
                                ip6_del_rt(rt);
@@@ -2773,7 -2732,6 +2773,7 @@@ static void addrconf_dad_start(struct i
        spin_lock_bh(&ifp->lock);
  
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
 +          idev->cnf.accept_dad < 1 ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
            ifp->flags & IFA_F_NODAD) {
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
@@@ -2821,11 -2779,6 +2821,11 @@@ static void addrconf_dad_timer(unsigne
                read_unlock_bh(&idev->lock);
                goto out;
        }
 +      if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
 +              read_unlock_bh(&idev->lock);
 +              addrconf_dad_failure(ifp);
 +              return;
 +      }
        spin_lock_bh(&ifp->lock);
        if (ifp->probes == 0) {
                /*
@@@ -3685,8 -3638,6 +3685,8 @@@ static inline void ipv6_store_devconf(s
  #ifdef CONFIG_IPV6_MROUTE
        array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
  #endif
 +      array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
 +      array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
  }
  
  static inline size_t inet6_if_nlmsg_size(void)
@@@ -4245,22 -4196,6 +4245,22 @@@ static struct addrconf_sysctl_tabl
                        .proc_handler   =       &proc_dointvec,
                },
  #endif
 +              {
 +                      .ctl_name       =       CTL_UNNUMBERED,
 +                      .procname       =       "disable_ipv6",
 +                      .data           =       &ipv6_devconf.disable_ipv6,
 +                      .maxlen         =       sizeof(int),
 +                      .mode           =       0644,
 +                      .proc_handler   =       &proc_dointvec,
 +              },
 +              {
 +                      .ctl_name       =       CTL_UNNUMBERED,
 +                      .procname       =       "accept_dad",
 +                      .data           =       &ipv6_devconf.accept_dad,
 +                      .maxlen         =       sizeof(int),
 +                      .mode           =       0644,
 +                      .proc_handler   =       &proc_dointvec,
 +              },
                {
                        .ctl_name       =       0,      /* sentinel */
                }
diff --combined net/mac80211/main.c
index cc756e93e6c82c53cbaa8d03b7ba6617a7f44611,df0836ff1a206c4cfaf25d5ba602ed5496a95b89..cf477ad39daca2603bdf8020e3518b71c23c978a
@@@ -35,6 -35,8 +35,6 @@@
  #include "debugfs.h"
  #include "debugfs_netdev.h"
  
 -#define SUPP_MCS_SET_LEN 16
 -
  /*
   * For seeing transmitted packets on monitor interfaces
   * we have a radiotap header too.
@@@ -110,13 -112,7 +110,13 @@@ static int ieee80211_master_open(struc
                        break;
                }
        }
 -      return res;
 +
 +      if (res)
 +              return res;
 +
 +      netif_start_queue(local->mdev);
 +
 +      return 0;
  }
  
  static int ieee80211_master_stop(struct net_device *dev)
@@@ -151,7 -147,9 +151,7 @@@ static int ieee80211_change_mtu(struct 
        /* FIX: what would be proper limits for MTU?
         * This interface uses 802.3 frames. */
        if (new_mtu < 256 ||
 -              new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
 -              printk(KERN_WARNING "%s: invalid MTU %d\n",
 -                     dev->name, new_mtu);
 +          new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
                return -EINVAL;
        }
  
@@@ -182,11 -180,10 +182,11 @@@ static int ieee80211_open(struct net_de
  {
        struct ieee80211_sub_if_data *sdata, *nsdata;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 +      struct sta_info *sta;
        struct ieee80211_if_init_conf conf;
 +      u32 changed = 0;
        int res;
        bool need_hw_reconfig = 0;
 -      struct sta_info *sta;
  
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
                        goto err_stop;
  
                ieee80211_if_config(dev);
 -              ieee80211_reset_erp_info(dev);
 +              changed |= ieee80211_reset_erp_info(dev);
 +              ieee80211_bss_info_change_notify(sdata, changed);
                ieee80211_enable_keys(sdata);
  
                if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
                        goto err_del_interface;
                }
  
 +              /* no locking required since STA is not live yet */
                sta->flags |= WLAN_STA_AUTHORIZED;
  
                res = sta_info_insert(sta);
         * yet be effective. Trigger execution of ieee80211_sta_work
         * to fix this.
         */
 -      if(sdata->vif.type == IEEE80211_IF_TYPE_STA ||
 -         sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 +      if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
 +          sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
                queue_work(local->hw.workqueue, &ifsta->work);
        }
@@@ -535,8 -530,6 +535,6 @@@ static int ieee80211_stop(struct net_de
                                local->sta_hw_scanning = 0;
                }
  
-               flush_workqueue(local->hw.workqueue);
                sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
                kfree(sdata->u.sta.extra_ie);
                sdata->u.sta.extra_ie = NULL;
  
                ieee80211_led_radio(local, 0);
  
+               flush_workqueue(local->hw.workqueue);
                tasklet_disable(&local->tx_pending_tasklet);
                tasklet_disable(&local->tasklet);
        }
@@@ -589,19 -584,17 +589,19 @@@ int ieee80211_start_tx_ba_session(struc
  
        sta = sta_info_get(local, ra);
        if (!sta) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find the station\n");
 -              rcu_read_unlock();
 -              return -ENOENT;
 +#endif
 +              ret = -ENOENT;
 +              goto exit;
        }
  
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_lock_bh(&sta->lock);
  
        /* we have tried too many times, receiver does not want A-MPDU */
        if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
                ret = -EBUSY;
 -              goto start_ba_exit;
 +              goto err_unlock_sta;
        }
  
        state = &sta->ampdu_mlme.tid_state_tx[tid];
                                 "idle on tid %u\n", tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
                ret = -EAGAIN;
 -              goto start_ba_exit;
 +              goto err_unlock_sta;
        }
  
        /* prepare A-MPDU MLME for Tx aggregation */
        sta->ampdu_mlme.tid_tx[tid] =
                        kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
        if (!sta->ampdu_mlme.tid_tx[tid]) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
                                        tid);
 +#endif
                ret = -ENOMEM;
 -              goto start_ba_exit;
 +              goto err_unlock_sta;
        }
        /* Tx timer */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
                printk(KERN_DEBUG "BA request denied - queue unavailable for"
                                        " tid %d\n", tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
 -              goto start_ba_err;
 +              goto err_unlock_queue;
        }
        sdata = sta->sdata;
  
                                        " tid %d\n", tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
                *state = HT_AGG_STATE_IDLE;
 -              goto start_ba_err;
 +              goto err_unlock_queue;
        }
  
        /* Will put all the packets in the new SW queue */
        ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
        spin_unlock_bh(&local->mdev->queue_lock);
 +      spin_unlock_bh(&sta->lock);
  
        /* send an addBA request */
        sta->ampdu_mlme.dialog_token_allocator++;
                        sta->ampdu_mlme.dialog_token_allocator;
        sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
  
 +
        ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
                         sta->ampdu_mlme.tid_tx[tid]->dialog_token,
                         sta->ampdu_mlme.tid_tx[tid]->ssn,
                         0x40, 5000);
 -
        /* activate the timer for the recipient's addBA response */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
                                jiffies + ADDBA_RESP_INTERVAL;
        add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 +#ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
 -      goto start_ba_exit;
 +#endif
 +      goto exit;
  
 -start_ba_err:
 +err_unlock_queue:
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
        spin_unlock_bh(&local->mdev->queue_lock);
        ret = -EBUSY;
 -start_ba_exit:
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +err_unlock_sta:
 +      spin_unlock_bh(&sta->lock);
 +exit:
        rcu_read_unlock();
        return ret;
  }
@@@ -733,7 -720,7 +733,7 @@@ int ieee80211_stop_tx_ba_session(struc
  
        /* check if the TID is in aggregation */
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_lock_bh(&sta->lock);
  
        if (*state != HT_AGG_STATE_OPERATIONAL) {
                ret = -ENOENT;
        }
  
  stop_BA_exit:
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
        return ret;
  }
@@@ -777,10 -764,8 +777,10 @@@ void ieee80211_start_tx_ba_cb(struct ie
        DECLARE_MAC_BUF(mac);
  
        if (tid >= STA_TID_NUM) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
                                tid, STA_TID_NUM);
 +#endif
                return;
        }
  
        sta = sta_info_get(local, ra);
        if (!sta) {
                rcu_read_unlock();
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %s\n",
                                print_mac(mac, ra));
 +#endif
                return;
        }
  
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_lock_bh(&sta->lock);
  
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
                                *state);
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +#endif
 +              spin_unlock_bh(&sta->lock);
                rcu_read_unlock();
                return;
        }
        *state |= HT_ADDBA_DRV_READY_MSK;
  
        if (*state == HT_AGG_STATE_OPERATIONAL) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
 +#endif
                ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
        }
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
  }
  EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@@ -832,10 -811,8 +832,10 @@@ void ieee80211_stop_tx_ba_cb(struct iee
        DECLARE_MAC_BUF(mac);
  
        if (tid >= STA_TID_NUM) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
                                tid, STA_TID_NUM);
 +#endif
                return;
        }
  
        rcu_read_lock();
        sta = sta_info_get(local, ra);
        if (!sta) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %s\n",
                                print_mac(mac, ra));
 +#endif
                rcu_read_unlock();
                return;
        }
        state = &sta->ampdu_mlme.tid_state_tx[tid];
  
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      /* NOTE: no need to use sta->lock in this state check, as
 +       * ieee80211_stop_tx_ba_session will let only
 +       * one stop call to pass through per sta/tid */
        if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +#endif
                rcu_read_unlock();
                return;
        }
         * ieee80211_wake_queue is not used here as this queue is not
         * necessarily stopped */
        netif_schedule(local->mdev);
 +      spin_lock_bh(&sta->lock);
        *state = HT_AGG_STATE_IDLE;
        sta->ampdu_mlme.addba_req_num[tid] = 0;
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_unlock_bh(&sta->lock);
  
        rcu_read_unlock();
  }
@@@ -904,11 -875,9 +904,11 @@@ void ieee80211_start_tx_ba_cb_irqsafe(s
        struct sk_buff *skb = dev_alloc_skb(0);
  
        if (unlikely(!skb)) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
                               "dropping start BA session", skb->dev->name);
 +#endif
                return;
        }
        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@@ -929,11 -898,9 +929,11 @@@ void ieee80211_stop_tx_ba_cb_irqsafe(st
        struct sk_buff *skb = dev_alloc_skb(0);
  
        if (unlikely(!skb)) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
                               "dropping stop BA session", skb->dev->name);
 +#endif
                return;
        }
        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@@ -1000,7 -967,8 +1000,7 @@@ void ieee80211_if_setup(struct net_devi
  /* everything else */
  
  static int __ieee80211_if_config(struct net_device *dev,
 -                               struct sk_buff *beacon,
 -                               struct ieee80211_tx_control *control)
 +                               struct sk_buff *beacon)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
                conf.ssid_len = sdata->u.sta.ssid_len;
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                conf.beacon = beacon;
 -              conf.beacon_control = control;
                ieee80211_start_mesh(dev);
        } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                conf.ssid = sdata->u.ap.ssid;
                conf.ssid_len = sdata->u.ap.ssid_len;
                conf.beacon = beacon;
 -              conf.beacon_control = control;
        }
        return local->ops->config_interface(local_to_hw(local),
                                            &sdata->vif, &conf);
@@@ -1035,21 -1005,23 +1035,21 @@@ int ieee80211_if_config(struct net_devi
        if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
            (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
                return ieee80211_if_config_beacon(dev);
 -      return __ieee80211_if_config(dev, NULL, NULL);
 +      return __ieee80211_if_config(dev, NULL);
  }
  
  int ieee80211_if_config_beacon(struct net_device *dev)
  {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 -      struct ieee80211_tx_control control;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sk_buff *skb;
  
        if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
                return 0;
 -      skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
 -                                 &control);
 +      skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
        if (!skb)
                return -ENOMEM;
 -      return __ieee80211_if_config(dev, skb, &control);
 +      return __ieee80211_if_config(dev, skb);
  }
  
  int ieee80211_hw_config(struct ieee80211_local *local)
@@@ -1096,84 -1068,56 +1096,84 @@@ u32 ieee80211_handle_ht(struct ieee8021
        struct ieee80211_supported_band *sband;
        struct ieee80211_ht_info ht_conf;
        struct ieee80211_ht_bss_info ht_bss_conf;
 -      int i;
        u32 changed = 0;
 +      int i;
 +      u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
 +      u8 tx_mcs_set_cap;
  
        sband = local->hw.wiphy->bands[conf->channel->band];
  
 +      memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
 +      memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
 +
        /* HT is not supported */
        if (!sband->ht_info.ht_supported) {
                conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
 -              return 0;
 +              goto out;
        }
  
 -      memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
 -      memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
 -
 -      if (enable_ht) {
 -              if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
 +      /* disable HT */
 +      if (!enable_ht) {
 +              if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
                        changed |= BSS_CHANGED_HT;
 +              conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
 +              conf->ht_conf.ht_supported = 0;
 +              goto out;
 +      }
  
 -              conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
 -              ht_conf.ht_supported = 1;
  
 -              ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
 -              ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
 -              ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
 +      if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
 +              changed |= BSS_CHANGED_HT;
  
 -              for (i = 0; i < SUPP_MCS_SET_LEN; i++)
 -                      ht_conf.supp_mcs_set[i] =
 -                                      sband->ht_info.supp_mcs_set[i] &
 -                                      req_ht_cap->supp_mcs_set[i];
 +      conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
 +      ht_conf.ht_supported = 1;
  
 -              ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
 -              ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
 -              ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
 +      ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
 +      ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
 +      ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
 +      ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
 +      ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
 +      ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
  
 -              ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
 -              ht_conf.ampdu_density = req_ht_cap->ampdu_density;
 +      ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
 +      ht_conf.ampdu_density = req_ht_cap->ampdu_density;
  
 -              /* if bss configuration changed store the new one */
 -              if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
 -                  memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
 -                      changed |= BSS_CHANGED_HT;
 -                      memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
 -                      memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
 -              }
 -      } else {
 -              if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
 -                      changed |= BSS_CHANGED_HT;
 -              conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
 -      }
 +      /* Bits 96-100 */
 +      tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
 +
 +      /* configure suppoerted Tx MCS according to requested MCS
 +       * (based in most cases on Rx capabilities of peer) and self
 +       * Tx MCS capabilities (as defined by low level driver HW
 +       * Tx capabilities) */
 +      if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
 +              goto check_changed;
 +
 +      /* Counting from 0 therfore + 1 */
 +      if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
 +              max_tx_streams = ((tx_mcs_set_cap &
 +                              IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
 +
 +      for (i = 0; i < max_tx_streams; i++)
 +              ht_conf.supp_mcs_set[i] =
 +                      sband->ht_info.supp_mcs_set[i] &
 +                                      req_ht_cap->supp_mcs_set[i];
  
 +      if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
 +              for (i = IEEE80211_SUPP_MCS_SET_UEQM;
 +                   i < IEEE80211_SUPP_MCS_SET_LEN; i++)
 +                      ht_conf.supp_mcs_set[i] =
 +                              sband->ht_info.supp_mcs_set[i] &
 +                                      req_ht_cap->supp_mcs_set[i];
 +
 +check_changed:
 +      /* if bss configuration changed store the new one */
 +      if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
 +          memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
 +              changed |= BSS_CHANGED_HT;
 +              memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
 +              memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
 +      }
 +out:
        return changed;
  }
  
@@@ -1192,30 -1136,50 +1192,30 @@@ void ieee80211_bss_info_change_notify(s
                                             changed);
  }
  
 -void ieee80211_reset_erp_info(struct net_device *dev)
 +u32 ieee80211_reset_erp_info(struct net_device *dev)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
        sdata->bss_conf.use_cts_prot = 0;
        sdata->bss_conf.use_short_preamble = 0;
 -      ieee80211_bss_info_change_notify(sdata,
 -                                       BSS_CHANGED_ERP_CTS_PROT |
 -                                       BSS_CHANGED_ERP_PREAMBLE);
 +      return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
  }
  
  void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 -                               struct sk_buff *skb,
 -                               struct ieee80211_tx_status *status)
 +                               struct sk_buff *skb)
  {
        struct ieee80211_local *local = hw_to_local(hw);
 -      struct ieee80211_tx_status *saved;
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int tmp;
  
        skb->dev = local->mdev;
 -      saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
 -      if (unlikely(!saved)) {
 -              if (net_ratelimit())
 -                      printk(KERN_WARNING "%s: Not enough memory, "
 -                             "dropping tx status", skb->dev->name);
 -              /* should be dev_kfree_skb_irq, but due to this function being
 -               * named _irqsafe instead of just _irq we can't be sure that
 -               * people won't call it from non-irq contexts */
 -              dev_kfree_skb_any(skb);
 -              return;
 -      }
 -      memcpy(saved, status, sizeof(struct ieee80211_tx_status));
 -      /* copy pointer to saved status into skb->cb for use by tasklet */
 -      memcpy(skb->cb, &saved, sizeof(saved));
 -
        skb->pkt_type = IEEE80211_TX_STATUS_MSG;
 -      skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
 +      skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
                       &local->skb_queue : &local->skb_queue_unreliable, skb);
        tmp = skb_queue_len(&local->skb_queue) +
                skb_queue_len(&local->skb_queue_unreliable);
        while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
 -              memcpy(&saved, skb->cb, sizeof(saved));
 -              kfree(saved);
                dev_kfree_skb_irq(skb);
                tmp--;
                I802_DEBUG_INC(local->tx_status_drop);
@@@ -1229,6 -1193,7 +1229,6 @@@ static void ieee80211_tasklet_handler(u
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sk_buff *skb;
        struct ieee80211_rx_status rx_status;
 -      struct ieee80211_tx_status *tx_status;
        struct ieee80211_ra_tid *ra_tid;
  
        while ((skb = skb_dequeue(&local->skb_queue)) ||
                        __ieee80211_rx(local_to_hw(local), skb, &rx_status);
                        break;
                case IEEE80211_TX_STATUS_MSG:
 -                      /* get pointer to saved status out of skb->cb */
 -                      memcpy(&tx_status, skb->cb, sizeof(tx_status));
                        skb->pkt_type = 0;
 -                      ieee80211_tx_status(local_to_hw(local),
 -                                          skb, tx_status);
 -                      kfree(tx_status);
 +                      ieee80211_tx_status(local_to_hw(local), skb);
                        break;
                case IEEE80211_DELBA_MSG:
                        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
                                                 ra_tid->ra, ra_tid->tid);
                        dev_kfree_skb(skb);
                        break ;
 -              default: /* should never get here! */
 -                      printk(KERN_ERR "%s: Unknown message type (%d)\n",
 -                             wiphy_name(local->hw.wiphy), skb->pkt_type);
 +              default:
 +                      WARN_ON(1);
                        dev_kfree_skb(skb);
                        break;
                }
   * Also, tx_packet_data in cb is restored from tx_control. */
  static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                                      struct ieee80211_key *key,
 -                                    struct sk_buff *skb,
 -                                    struct ieee80211_tx_control *control)
 +                                    struct sk_buff *skb)
  {
        int hdrlen, iv_len, mic_len;
 -      struct ieee80211_tx_packet_data *pkt_data;
 -
 -      pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
 -      pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
 -      pkt_data->flags = 0;
 -      if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
 -              pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
 -      if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
 -              pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
 -      if (control->flags & IEEE80211_TXCTL_REQUEUE)
 -              pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
 -      if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
 -              pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 -      pkt_data->queue = control->queue;
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 +
 +      info->flags &=  IEEE80211_TX_CTL_REQ_TX_STATUS |
 +                      IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
 +                      IEEE80211_TX_CTL_REQUEUE |
 +                      IEEE80211_TX_CTL_EAPOL_FRAME;
  
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
  
@@@ -1327,10 -1306,9 +1327,10 @@@ no_key
  
  static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sta_info *sta,
 -                                          struct sk_buff *skb,
 -                                          struct ieee80211_tx_status *status)
 +                                          struct sk_buff *skb)
  {
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 +
        sta->tx_filtered_count++;
  
        /*
         * packet. If the STA went to power save mode, this will happen
         * when it wakes up for the next time.
         */
 -      sta->flags |= WLAN_STA_CLEAR_PS_FILT;
 +      set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
  
        /*
         * This code races in the following way:
         *      can be unknown, for example with different interrupt status
         *      bits.
         */
 -      if (sta->flags & WLAN_STA_PS &&
 +      if (test_sta_flags(sta, WLAN_STA_PS) &&
            skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
 -              ieee80211_remove_tx_extra(local, sta->key, skb,
 -                                        &status->control);
 +              ieee80211_remove_tx_extra(local, sta->key, skb);
                skb_queue_tail(&sta->tx_filtered, skb);
                return;
        }
  
 -      if (!(sta->flags & WLAN_STA_PS) &&
 -          !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
 +      if (!test_sta_flags(sta, WLAN_STA_PS) &&
 +          !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
                /* Software retry the packet once */
 -              status->control.flags |= IEEE80211_TXCTL_REQUEUE;
 -              ieee80211_remove_tx_extra(local, sta->key, skb,
 -                                        &status->control);
 +              info->flags |= IEEE80211_TX_CTL_REQUEUE;
 +              ieee80211_remove_tx_extra(local, sta->key, skb);
                dev_queue_xmit(skb);
                return;
        }
  
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: dropped TX filtered frame, "
                       "queue_len=%d PS=%d @%lu\n",
                       wiphy_name(local->hw.wiphy),
                       skb_queue_len(&sta->tx_filtered),
 -                     !!(sta->flags & WLAN_STA_PS), jiffies);
 +                     !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
 +#endif
        dev_kfree_skb(skb);
  }
  
 -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 -                       struct ieee80211_tx_status *status)
 +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
  {
        struct sk_buff *skb2;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_local *local = hw_to_local(hw);
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u16 frag, type;
 +      __le16 fc;
        struct ieee80211_tx_status_rtap_hdr *rthdr;
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
 -
 -      if (!status) {
 -              printk(KERN_ERR
 -                     "%s: ieee80211_tx_status called with NULL status\n",
 -                     wiphy_name(local->hw.wiphy));
 -              dev_kfree_skb(skb);
 -              return;
 -      }
 +      struct sta_info *sta;
  
        rcu_read_lock();
  
 -      if (status->excessive_retries) {
 -              struct sta_info *sta;
 +      if (info->status.excessive_retries) {
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
 -                      if (sta->flags & WLAN_STA_PS) {
 +                      if (test_sta_flags(sta, WLAN_STA_PS)) {
                                /*
                                 * The STA is in power save mode, so assume
                                 * that this TX packet failed because of that.
                                 */
 -                              status->excessive_retries = 0;
 -                              status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
 -                              ieee80211_handle_filtered_frame(local, sta,
 -                                                              skb, status);
 +                              ieee80211_handle_filtered_frame(local, sta, skb);
                                rcu_read_unlock();
                                return;
                        }
                }
        }
  
 -      if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
 -              struct sta_info *sta;
 +      fc = hdr->frame_control;
 +
 +      if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
 +          (ieee80211_is_data_qos(fc))) {
 +              u16 tid, ssn;
 +              u8 *qc;
 +              sta = sta_info_get(local, hdr->addr1);
 +              if (sta) {
 +                      qc = ieee80211_get_qos_ctl(hdr);
 +                      tid = qc[0] & 0xf;
 +                      ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
 +                                              & IEEE80211_SCTL_SEQ);
 +                      ieee80211_send_bar(sta->sdata->dev, hdr->addr1,
 +                                         tid, ssn);
 +              }
 +      }
 +
 +      if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
 -                      ieee80211_handle_filtered_frame(local, sta, skb,
 -                                                      status);
 +                      ieee80211_handle_filtered_frame(local, sta, skb);
                        rcu_read_unlock();
                        return;
                }
        } else
 -              rate_control_tx_status(local->mdev, skb, status);
 +              rate_control_tx_status(local->mdev, skb);
  
        rcu_read_unlock();
  
        frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
        type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
  
 -      if (status->flags & IEEE80211_TX_STATUS_ACK) {
 +      if (info->flags & IEEE80211_TX_STAT_ACK) {
                if (frag == 0) {
                        local->dot11TransmittedFrameCount++;
                        if (is_multicast_ether_addr(hdr->addr1))
                                local->dot11MulticastTransmittedFrameCount++;
 -                      if (status->retry_count > 0)
 +                      if (info->status.retry_count > 0)
                                local->dot11RetryCount++;
 -                      if (status->retry_count > 1)
 +                      if (info->status.retry_count > 1)
                                local->dot11MultipleRetryCount++;
                }
  
                return;
        }
  
 -      rthdr = (struct ieee80211_tx_status_rtap_hdr*)
 +      rthdr = (struct ieee80211_tx_status_rtap_hdr *)
                                skb_push(skb, sizeof(*rthdr));
  
        memset(rthdr, 0, sizeof(*rthdr));
                cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
                            (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
  
 -      if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
 +      if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
            !is_multicast_ether_addr(hdr->addr1))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
  
 -      if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
 -          (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
 +      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
 +          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
 -      else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
 +      else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
  
 -      rthdr->data_retries = status->retry_count;
 +      rthdr->data_retries = info->status.retry_count;
  
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
@@@ -1679,32 -1652,12 +1679,32 @@@ int ieee80211_register_hw(struct ieee80
        if (result < 0)
                return result;
  
 +      /*
 +       * We use the number of queues for feature tests (QoS, HT) internally
 +       * so restrict them appropriately.
 +       */
 +#ifdef CONFIG_MAC80211_QOS
 +      if (hw->queues > IEEE80211_MAX_QUEUES)
 +              hw->queues = IEEE80211_MAX_QUEUES;
 +      if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
 +              hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
 +      if (hw->queues < 4)
 +              hw->ampdu_queues = 0;
 +#else
 +      hw->queues = 1;
 +      hw->ampdu_queues = 0;
 +#endif
 +
        /* for now, mdev needs sub_if_data :/ */
 -      mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
 -                          "wmaster%d", ether_setup);
 +      mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
 +                             "wmaster%d", ether_setup,
 +                             ieee80211_num_queues(hw));
        if (!mdev)
                goto fail_mdev_alloc;
  
 +      if (ieee80211_num_queues(hw) > 1)
 +              mdev->features |= NETIF_F_MULTI_QUEUE;
 +
        sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
        mdev->ieee80211_ptr = &sdata->wdev;
        sdata->wdev.wiphy = local->hw.wiphy;
        list_add_tail(&sdata->list, &local->interfaces);
  
        name = wiphy_dev(local->hw.wiphy)->driver->name;
 -      local->hw.workqueue = create_singlethread_workqueue(name);
 +      local->hw.workqueue = create_freezeable_workqueue(name);
        if (!local->hw.workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
  
        debugfs_hw_add(local);
  
 -      local->hw.conf.beacon_int = 1000;
 +      if (local->hw.conf.beacon_int < 10)
 +              local->hw.conf.beacon_int = 100;
  
 -      local->wstats_flags |= local->hw.max_rssi ?
 -                             IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
 -      local->wstats_flags |= local->hw.max_signal ?
 +      local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
 +                                                IEEE80211_HW_SIGNAL_DB |
 +                                                IEEE80211_HW_SIGNAL_DBM) ?
                               IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
 -      local->wstats_flags |= local->hw.max_noise ?
 +      local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
                               IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
 -      if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
 +      if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->wstats_flags |= IW_QUAL_DBM;
  
        result = sta_info_start(local);
@@@ -1906,9 -1858,7 +1906,9 @@@ static int __init ieee80211_init(void
        struct sk_buff *skb;
        int ret;
  
 -      BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
 +      BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
 +      BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
 +                   IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
  
        ret = rc80211_pid_init();
        if (ret)
diff --combined net/mac80211/mlme.c
index 37ea04f5bab97badb7e80fc0aa08d18cd2323a8c,b404537c0bcd1a470f4f7e305ab18c1e263c0b34..dbc8cf454bc038af959198b70622a4259ce2618e
@@@ -87,7 -87,6 +87,7 @@@ static int ieee80211_sta_start_scan(str
                                    u8 *ssid, size_t ssid_len);
  static int ieee80211_sta_config_auth(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta);
 +static void sta_rx_agg_session_timer_expired(unsigned long data);
  
  
  void ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->perr = pos;
                        elems->perr_len = elen;
                        break;
 +              case WLAN_EID_CHANNEL_SWITCH:
 +                      elems->ch_switch_elem = pos;
 +                      elems->ch_switch_elem_len = elen;
 +                      break;
 +              case WLAN_EID_QUIET:
 +                      if (!elems->quiet_elem) {
 +                              elems->quiet_elem = pos;
 +                              elems->quiet_elem_len = elen;
 +                      }
 +                      elems->num_of_quiet_elem++;
 +                      break;
 +              case WLAN_EID_COUNTRY:
 +                      elems->country_elem = pos;
 +                      elems->country_elem_len = elen;
 +                      break;
 +              case WLAN_EID_PWR_CONSTRAINT:
 +                      elems->pwr_constr_elem = pos;
 +                      elems->pwr_constr_elem_len = elen;
 +                      break;
                default:
                        break;
                }
@@@ -276,8 -256,19 +276,8 @@@ static void ieee80211_sta_def_wmm_param
                qparam.cw_max = 1023;
                qparam.txop = 0;
  
 -              for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
 -                      local->ops->conf_tx(local_to_hw(local),
 -                                         i + IEEE80211_TX_QUEUE_DATA0,
 -                                         &qparam);
 -
 -              if (ibss) {
 -                      /* IBSS uses different parameters for Beacon sending */
 -                      qparam.cw_min++;
 -                      qparam.cw_min *= 2;
 -                      qparam.cw_min--;
 -                      local->ops->conf_tx(local_to_hw(local),
 -                                         IEEE80211_TX_QUEUE_BEACON, &qparam);
 -              }
 +              for (i = 0; i < local_to_hw(local)->queues; i++)
 +                      local->ops->conf_tx(local_to_hw(local), i, &qparam);
        }
  }
  
@@@ -291,12 -282,6 +291,12 @@@ static void ieee80211_sta_wmm_params(st
        int count;
        u8 *pos;
  
 +      if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
 +              return;
 +
 +      if (!wmm_param)
 +              return;
 +
        if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
                return;
        count = wmm_param[6] & 0x0f;
  
                switch (aci) {
                case 1:
 -                      queue = IEEE80211_TX_QUEUE_DATA3;
 -                      if (acm) {
 +                      queue = 3;
 +                      if (acm)
                                local->wmm_acm |= BIT(0) | BIT(3);
 -                      }
                        break;
                case 2:
 -                      queue = IEEE80211_TX_QUEUE_DATA1;
 -                      if (acm) {
 +                      queue = 1;
 +                      if (acm)
                                local->wmm_acm |= BIT(4) | BIT(5);
 -                      }
                        break;
                case 3:
 -                      queue = IEEE80211_TX_QUEUE_DATA0;
 -                      if (acm) {
 +                      queue = 0;
 +                      if (acm)
                                local->wmm_acm |= BIT(6) | BIT(7);
 -                      }
                        break;
                case 0:
                default:
 -                      queue = IEEE80211_TX_QUEUE_DATA2;
 -                      if (acm) {
 +                      queue = 2;
 +                      if (acm)
                                local->wmm_acm |= BIT(1) | BIT(2);
 -                      }
                        break;
                }
  
                params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
                params.cw_min = ecw2cw(pos[1] & 0x0f);
                params.txop = pos[2] | (pos[3] << 8);
 -#ifdef CONFIG_MAC80211_DEBUG
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
                       "cWmin=%d cWmax=%d txop=%d\n",
                       dev->name, queue, aci, acm, params.aifs, params.cw_min,
@@@ -366,14 -355,11 +366,14 @@@ static u32 ieee80211_handle_protect_pre
                                           bool use_short_preamble)
  {
        struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        DECLARE_MAC_BUF(mac);
 +#endif
        u32 changed = 0;
  
        if (use_protection != bss_conf->use_cts_prot) {
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
                               "%s)\n",
                               use_protection ? "enabled" : "disabled",
                               print_mac(mac, ifsta->bssid));
                }
 +#endif
                bss_conf->use_cts_prot = use_protection;
                changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
  
        if (use_short_preamble != bss_conf->use_short_preamble) {
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: switched to %s barker preamble"
                               " (BSSID=%s)\n",
                               use_short_preamble ? "short" : "long",
                               print_mac(mac, ifsta->bssid));
                }
 +#endif
                bss_conf->use_short_preamble = use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
@@@ -564,16 -547,15 +564,15 @@@ static void ieee80211_set_associated(st
                        sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
                }
  
-               netif_carrier_on(dev);
                ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
                memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
                memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
                ieee80211_sta_send_associnfo(dev, ifsta);
        } else {
+               netif_carrier_off(dev);
                ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
                ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-               netif_carrier_off(dev);
 -              ieee80211_reset_erp_info(dev);
 +              changed |= ieee80211_reset_erp_info(dev);
  
                sdata->bss_conf.assoc_ht = 0;
                sdata->bss_conf.ht_conf = NULL;
  
        sdata->bss_conf.assoc = assoc;
        ieee80211_bss_info_change_notify(sdata, changed);
+       if (assoc)
+               netif_carrier_on(dev);
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
  }
@@@ -603,7 -589,7 +606,7 @@@ void ieee80211_sta_tx(struct net_devic
                      int encrypt)
  {
        struct ieee80211_sub_if_data *sdata;
 -      struct ieee80211_tx_packet_data *pkt_data;
 +      struct ieee80211_tx_info *info;
  
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        skb->dev = sdata->local->mdev;
        skb_set_network_header(skb, 0);
        skb_set_transport_header(skb, 0);
  
 -      pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
 -      memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
 -      pkt_data->ifindex = sdata->dev->ifindex;
 +      info = IEEE80211_SKB_CB(skb);
 +      memset(info, 0, sizeof(struct ieee80211_tx_info));
 +      info->control.ifindex = sdata->dev->ifindex;
        if (!encrypt)
 -              pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
 +              info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
  
        dev_queue_xmit(skb);
  }
@@@ -744,8 -730,9 +747,8 @@@ static void ieee80211_send_assoc(struc
        if (bss) {
                if (bss->capability & WLAN_CAPABILITY_PRIVACY)
                        capab |= WLAN_CAPABILITY_PRIVACY;
 -              if (bss->wmm_ie) {
 +              if (bss->wmm_ie)
                        wmm = 1;
 -              }
  
                /* get all rates supported by the device and the AP as
                 * some APs don't like getting a superset of their rates
                 * b-only mode) */
                rates_len = ieee80211_compatible_rates(bss, sband, &rates);
  
 +              if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
 +                  (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
 +                      capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 +
                ieee80211_rx_bss_put(dev, bss);
        } else {
                rates = ~0;
                }
        }
  
 +      if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
 +              /* 1. power capabilities */
 +              pos = skb_put(skb, 4);
 +              *pos++ = WLAN_EID_PWR_CAPABILITY;
 +              *pos++ = 2;
 +              *pos++ = 0; /* min tx power */
 +              *pos++ = local->hw.conf.channel->max_power; /* max tx power */
 +
 +              /* 2. supported channels */
 +              /* TODO: get this in reg domain format */
 +              pos = skb_put(skb, 2 * sband->n_channels + 2);
 +              *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
 +              *pos++ = 2 * sband->n_channels;
 +              for (i = 0; i < sband->n_channels; i++) {
 +                      *pos++ = ieee80211_frequency_to_channel(
 +                                      sband->channels[i].center_freq);
 +                      *pos++ = 1; /* one channel in the subband*/
 +              }
 +      }
 +
        if (ifsta->extra_ie) {
                pos = skb_put(skb, ifsta->extra_ie_len);
                memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
                *pos++ = 1; /* WME ver */
                *pos++ = 0;
        }
 +
        /* wmm support is a must to HT */
 -      if (wmm && sband->ht_info.ht_supported) {
 -              __le16 tmp = cpu_to_le16(sband->ht_info.cap);
 +      if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
 +          sband->ht_info.ht_supported && bss->ht_add_ie) {
 +              struct ieee80211_ht_addt_info *ht_add_info =
 +                      (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
 +              u16 cap = sband->ht_info.cap;
 +              __le16 tmp;
 +              u32 flags = local->hw.conf.channel->flags;
 +
 +              switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
 +              case IEEE80211_HT_IE_CHA_SEC_ABOVE:
 +                      if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
 +                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
 +                              cap &= ~IEEE80211_HT_CAP_SGI_40;
 +                      }
 +                      break;
 +              case IEEE80211_HT_IE_CHA_SEC_BELOW:
 +                      if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
 +                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
 +                              cap &= ~IEEE80211_HT_CAP_SGI_40;
 +                      }
 +                      break;
 +              }
 +
 +              tmp = cpu_to_le16(cap);
                pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
                *pos++ = WLAN_EID_HT_CAPABILITY;
                *pos++ = sizeof(struct ieee80211_ht_cap);
@@@ -1181,10 -1121,14 +1184,10 @@@ static void ieee80211_auth_challenge(st
        u8 *pos;
        struct ieee802_11_elems elems;
  
 -      printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
        pos = mgmt->u.auth.variable;
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 -      if (!elems.challenge) {
 -              printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
 -                     "frame\n", dev->name);
 +      if (!elems.challenge)
                return;
 -      }
        ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
                            elems.challenge_len + 2, 1);
  }
@@@ -1200,8 -1144,8 +1203,8 @@@ static void ieee80211_send_addba_resp(s
        struct ieee80211_mgmt *mgmt;
        u16 capab;
  
 -      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
 -                                      sizeof(mgmt->u.action.u.addba_resp));
 +      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 +
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer "
                       "for addba resp frame\n", dev->name);
@@@ -1249,7 -1193,9 +1252,7 @@@ void ieee80211_send_addba_request(struc
        struct ieee80211_mgmt *mgmt;
        u16 capab;
  
 -      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
 -                              sizeof(mgmt->u.action.u.addba_req));
 -
 +      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
  
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
@@@ -1350,7 -1296,7 +1353,7 @@@ static void ieee80211_sta_process_addba
  
  
        /* examine state machine */
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
 +      spin_lock_bh(&sta->lock);
  
        if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
        sta->ampdu_mlme.tid_rx[tid] =
                        kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
        if (!sta->ampdu_mlme.tid_rx[tid]) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
                                        tid);
 +#endif
                goto end;
        }
        /* rx timer */
        tid_agg_rx->reorder_buf =
                kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
        if (!tid_agg_rx->reorder_buf) {
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_ERR "can not allocate reordering buffer "
                               "to tid %d\n", tid);
 +#endif
                kfree(sta->ampdu_mlme.tid_rx[tid]);
                goto end;
        }
        tid_agg_rx->stored_mpdu_num = 0;
        status = WLAN_STATUS_SUCCESS;
  end:
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
 +      spin_unlock_bh(&sta->lock);
  
  end_no_lock:
        ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
@@@ -1453,16 -1395,18 +1456,16 @@@ static void ieee80211_sta_process_addba
  
        state = &sta->ampdu_mlme.tid_state_tx[tid];
  
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_lock_bh(&sta->lock);
  
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 -              printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
 -                      "%d\n", *state);
 +              spin_unlock_bh(&sta->lock);
                goto addba_resp_exit;
        }
  
        if (mgmt->u.action.u.addba_resp.dialog_token !=
                sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +              spin_unlock_bh(&sta->lock);
  #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
  #endif /* CONFIG_MAC80211_HT_DEBUG */
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
                        == WLAN_STATUS_SUCCESS) {
 -              if (*state & HT_ADDBA_RECEIVED_MSK)
 -                      printk(KERN_DEBUG "double addBA response\n");
 -
                *state |= HT_ADDBA_RECEIVED_MSK;
                sta->ampdu_mlme.addba_req_num[tid] = 0;
  
 -              if (*state == HT_AGG_STATE_OPERATIONAL) {
 -                      printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
 +              if (*state == HT_AGG_STATE_OPERATIONAL)
                        ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 -              }
  
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 -              printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
 +              spin_unlock_bh(&sta->lock);
        } else {
 -              printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
 -
                sta->ampdu_mlme.addba_req_num[tid]++;
                /* this will allow the state check in stop_BA_session */
                *state = HT_AGG_STATE_OPERATIONAL;
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +              spin_unlock_bh(&sta->lock);
                ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
                                             WLAN_BACK_INITIATOR);
        }
@@@ -1505,7 -1457,8 +1508,7 @@@ void ieee80211_send_delba(struct net_de
        struct ieee80211_mgmt *mgmt;
        u16 params;
  
 -      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
 -                                      sizeof(mgmt->u.action.u.delba));
 +      skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
  
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
        ieee80211_sta_tx(dev, skb, 0);
  }
  
 +void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn)
 +{
 +      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 +      struct sk_buff *skb;
 +      struct ieee80211_bar *bar;
 +      u16 bar_control = 0;
 +
 +      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", dev->name);
 +              return;
 +      }
 +      skb_reserve(skb, local->hw.extra_tx_headroom);
 +      bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
 +      memset(bar, 0, sizeof(*bar));
 +      bar->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
 +                                      IEEE80211_STYPE_BACK_REQ);
 +      memcpy(bar->ra, ra, ETH_ALEN);
 +      memcpy(bar->ta, dev->dev_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);
 +      bar->control = cpu_to_le16(bar_control);
 +      bar->start_seq_num = cpu_to_le16(ssn);
 +
 +      ieee80211_sta_tx(dev, skb, 0);
 +}
 +
  void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
                                        u16 initiator, u16 reason)
  {
        }
  
        /* check if TID is in operational state */
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
 +      spin_lock_bh(&sta->lock);
        if (sta->ampdu_mlme.tid_state_rx[tid]
                                != HT_AGG_STATE_OPERATIONAL) {
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
 +              spin_unlock_bh(&sta->lock);
                rcu_read_unlock();
                return;
        }
        sta->ampdu_mlme.tid_state_rx[tid] =
                HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
 +      spin_unlock_bh(&sta->lock);
  
        /* stop HW Rx aggregation. ampdu_action existence
         * already verified in session init so we add the BUG_ON */
                                        ra, tid, NULL);
        if (ret)
                printk(KERN_DEBUG "HW problem - can not stop rx "
 -                              "aggergation for tid %d\n", tid);
 +                              "aggregation for tid %d\n", tid);
  
        /* shutdown timer has not expired */
        if (initiator != WLAN_BACK_TIMER)
@@@ -1672,10 -1596,10 +1675,10 @@@ static void ieee80211_sta_process_delba
                ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
                                                 WLAN_BACK_INITIATOR, 0);
        else { /* WLAN_BACK_RECIPIENT */
 -              spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +              spin_lock_bh(&sta->lock);
                sta->ampdu_mlme.tid_state_tx[tid] =
                                HT_AGG_STATE_OPERATIONAL;
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +              spin_unlock_bh(&sta->lock);
                ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
                                             WLAN_BACK_RECIPIENT);
        }
@@@ -1712,24 -1636,20 +1715,24 @@@ void sta_addba_resp_timer_expired(unsig
  
        state = &sta->ampdu_mlme.tid_state_tx[tid];
        /* check if the TID waits for addBA response */
 -      spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_lock_bh(&sta->lock);
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
 -              spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +              spin_unlock_bh(&sta->lock);
                *state = HT_AGG_STATE_IDLE;
 +#ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "timer expired on tid %d but we are not "
                                "expecting addBA response there", tid);
 +#endif
                goto timer_expired_exit;
        }
  
 +#ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
 +#endif
  
        /* go through the state check in stop_BA_session */
        *state = HT_AGG_STATE_OPERATIONAL;
 -      spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 +      spin_unlock_bh(&sta->lock);
        ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
                                     WLAN_BACK_INITIATOR);
  
@@@ -1742,7 -1662,7 +1745,7 @@@ timer_expired_exit
   * resetting it after each frame that arrives from the originator.
   * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
   */
 -void sta_rx_agg_session_timer_expired(unsigned long data)
 +static void sta_rx_agg_session_timer_expired(unsigned long data)
  {
        /* not an elegant detour, but there is no choice as the timer passes
         * only one argument, and various sta_info are needed here, so init
        struct sta_info *sta = container_of(timer_to_id, struct sta_info,
                                         timer_to_tid[0]);
  
 +#ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
 +#endif
        ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
                                         (u16)*ptid, WLAN_BACK_TIMER,
                                         WLAN_REASON_QSTA_TIMEOUT);
@@@ -1775,71 -1693,6 +1778,71 @@@ void ieee80211_sta_tear_down_BA_session
        }
  }
  
 +static void ieee80211_send_refuse_measurement_request(struct net_device *dev,
 +                                      struct ieee80211_msrment_ie *request_ie,
 +                                      const u8 *da, const u8 *bssid,
 +                                      u8 dialog_token)
 +{
 +      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 +      struct sk_buff *skb;
 +      struct ieee80211_mgmt *msr_report;
 +
 +      skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
 +                              sizeof(struct ieee80211_msrment_ie));
 +
 +      if (!skb) {
 +              printk(KERN_ERR "%s: failed to allocate buffer for "
 +                              "measurement report frame\n", dev->name);
 +              return;
 +      }
 +
 +      skb_reserve(skb, local->hw.extra_tx_headroom);
 +      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, dev->dev_addr, ETH_ALEN);
 +      memcpy(msr_report->bssid, bssid, ETH_ALEN);
 +      msr_report->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
 +                                              IEEE80211_STYPE_ACTION);
 +
 +      skb_put(skb, 1 + sizeof(msr_report->u.action.u.measurement));
 +      msr_report->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
 +      msr_report->u.action.u.measurement.action_code =
 +                              WLAN_ACTION_SPCT_MSR_RPRT;
 +      msr_report->u.action.u.measurement.dialog_token = dialog_token;
 +
 +      msr_report->u.action.u.measurement.element_id = WLAN_EID_MEASURE_REPORT;
 +      msr_report->u.action.u.measurement.length =
 +                      sizeof(struct ieee80211_msrment_ie);
 +
 +      memset(&msr_report->u.action.u.measurement.msr_elem, 0,
 +              sizeof(struct ieee80211_msrment_ie));
 +      msr_report->u.action.u.measurement.msr_elem.token = request_ie->token;
 +      msr_report->u.action.u.measurement.msr_elem.mode |=
 +                      IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
 +      msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
 +
 +      ieee80211_sta_tx(dev, skb, 0);
 +}
 +
 +static void ieee80211_sta_process_measurement_req(struct net_device *dev,
 +                                              struct ieee80211_mgmt *mgmt,
 +                                              size_t len)
 +{
 +      /*
 +       * Ignoring measurement request is spec violation.
 +       * Mandatory measurements must be reported optional
 +       * measurements might be refused or reported incapable
 +       * For now just refuse
 +       * TODO: Answer basic measurement as unmeasured
 +       */
 +      ieee80211_send_refuse_measurement_request(dev,
 +                      &mgmt->u.action.u.measurement.msr_elem,
 +                      mgmt->sa, mgmt->bssid,
 +                      mgmt->u.action.u.measurement.dialog_token);
 +}
 +
 +
  static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
                                   struct ieee80211_mgmt *mgmt,
        DECLARE_MAC_BUF(mac);
  
        if (ifsta->state != IEEE80211_AUTHENTICATE &&
 -          sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
 -              printk(KERN_DEBUG "%s: authentication frame received from "
 -                     "%s, but not in authenticate state - ignored\n",
 -                     dev->name, print_mac(mac, mgmt->sa));
 +          sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return;
 -      }
  
 -      if (len < 24 + 6) {
 -              printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
 -                     "received from %s - ignored\n",
 -                     dev->name, len, print_mac(mac, mgmt->sa));
 +      if (len < 24 + 6)
                return;
 -      }
  
        if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 -          memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 -              printk(KERN_DEBUG "%s: authentication frame received from "
 -                     "unknown AP (SA=%s BSSID=%s) - "
 -                     "ignored\n", dev->name, print_mac(mac, mgmt->sa),
 -                     print_mac(mac, mgmt->bssid));
 +          memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
 -      }
  
        if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 -          memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
 -              printk(KERN_DEBUG "%s: authentication frame received from "
 -                     "unknown BSSID (SA=%s BSSID=%s) - "
 -                     "ignored\n", dev->name, print_mac(mac, mgmt->sa),
 -                     print_mac(mac, mgmt->bssid));
 +          memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 -      }
  
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
  
 -      printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d "
 -             "transaction=%d status=%d)\n",
 -             dev->name, print_mac(mac, mgmt->sa), auth_alg,
 -             auth_transaction, status_code);
 -
        if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 -              /* IEEE 802.11 standard does not require authentication in IBSS
 +              /*
 +               * IEEE 802.11 standard does not require authentication in IBSS
                 * networks and most implementations do not seem to use it.
                 * However, try to reply to authentication attempts if someone
                 * has actually implemented this.
 -               * TODO: Could implement shared key authentication. */
 -              if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
 -                      printk(KERN_DEBUG "%s: unexpected IBSS authentication "
 -                             "frame (alg=%d transaction=%d)\n",
 -                             dev->name, auth_alg, auth_transaction);
 +               */
 +              if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
                        return;
 -              }
                ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
        }
  
        if (auth_alg != ifsta->auth_alg ||
 -          auth_transaction != ifsta->auth_transaction) {
 -              printk(KERN_DEBUG "%s: unexpected authentication frame "
 -                     "(alg=%d transaction=%d)\n",
 -                     dev->name, auth_alg, auth_transaction);
 +          auth_transaction != ifsta->auth_transaction)
                return;
 -      }
  
        if (status_code != WLAN_STATUS_SUCCESS) {
 -              printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d "
 -                     "code=%d)\n", dev->name, ifsta->auth_alg, status_code);
                if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
                        u8 algs[3];
                        const int num_algs = ARRAY_SIZE(algs);
                                    !ieee80211_sta_wep_configured(dev))
                                        continue;
                                ifsta->auth_alg = algs[pos];
 -                              printk(KERN_DEBUG "%s: set auth_alg=%d for "
 -                                     "next try\n",
 -                                     dev->name, ifsta->auth_alg);
                                break;
                        }
                }
@@@ -1942,16 -1830,30 +1945,16 @@@ static void ieee80211_rx_mgmt_deauth(st
        u16 reason_code;
        DECLARE_MAC_BUF(mac);
  
 -      if (len < 24 + 2) {
 -              printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
 -                     "received from %s - ignored\n",
 -                     dev->name, len, print_mac(mac, mgmt->sa));
 +      if (len < 24 + 2)
                return;
 -      }
  
 -      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 -              printk(KERN_DEBUG "%s: deauthentication frame received from "
 -                     "unknown AP (SA=%s BSSID=%s) - "
 -                     "ignored\n", dev->name, print_mac(mac, mgmt->sa),
 -                     print_mac(mac, mgmt->bssid));
 +      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
                return;
 -      }
  
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
  
 -      printk(KERN_DEBUG "%s: RX deauthentication from %s"
 -             " (reason=%d)\n",
 -             dev->name, print_mac(mac, mgmt->sa), reason_code);
 -
 -      if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
 +      if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
                printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
 -      }
  
        if (ifsta->state == IEEE80211_AUTHENTICATE ||
            ifsta->state == IEEE80211_ASSOCIATE ||
@@@ -1974,14 -1876,27 +1977,14 @@@ static void ieee80211_rx_mgmt_disassoc(
        u16 reason_code;
        DECLARE_MAC_BUF(mac);
  
 -      if (len < 24 + 2) {
 -              printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
 -                     "received from %s - ignored\n",
 -                     dev->name, len, print_mac(mac, mgmt->sa));
 +      if (len < 24 + 2)
                return;
 -      }
  
 -      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 -              printk(KERN_DEBUG "%s: disassociation frame received from "
 -                     "unknown AP (SA=%s BSSID=%s) - "
 -                     "ignored\n", dev->name, print_mac(mac, mgmt->sa),
 -                     print_mac(mac, mgmt->bssid));
 +      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
                return;
 -      }
  
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
  
 -      printk(KERN_DEBUG "%s: RX disassociation from %s"
 -             " (reason=%d)\n",
 -             dev->name, print_mac(mac, mgmt->sa), reason_code);
 -
        if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
                printk(KERN_DEBUG "%s: disassociated\n", dev->name);
  
@@@ -2017,14 -1932,27 +2020,14 @@@ static void ieee80211_rx_mgmt_assoc_res
        /* AssocResp and ReassocResp have identical structure, so process both
         * of them in this function. */
  
 -      if (ifsta->state != IEEE80211_ASSOCIATE) {
 -              printk(KERN_DEBUG "%s: association frame received from "
 -                     "%s, but not in associate state - ignored\n",
 -                     dev->name, print_mac(mac, mgmt->sa));
 +      if (ifsta->state != IEEE80211_ASSOCIATE)
                return;
 -      }
  
 -      if (len < 24 + 6) {
 -              printk(KERN_DEBUG "%s: too short (%zd) association frame "
 -                     "received from %s - ignored\n",
 -                     dev->name, len, print_mac(mac, mgmt->sa));
 +      if (len < 24 + 6)
                return;
 -      }
  
 -      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 -              printk(KERN_DEBUG "%s: association frame received from "
 -                     "unknown AP (SA=%s BSSID=%s) - "
 -                     "ignored\n", dev->name, print_mac(mac, mgmt->sa),
 -                     print_mac(mac, mgmt->bssid));
 +      if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
 -      }
  
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
                                           local->hw.conf.channel->center_freq,
                                           ifsta->ssid, ifsta->ssid_len);
                if (bss) {
 -                      sta->last_rssi = bss->rssi;
                        sta->last_signal = bss->signal;
 +                      sta->last_qual = bss->qual;
                        sta->last_noise = bss->noise;
                        ieee80211_rx_bss_put(dev, bss);
                }
         *        to between the sta_info_alloc() and sta_info_insert() above.
         */
  
 -      sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
 -                    WLAN_STA_AUTHORIZED;
 +      set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
 +                         WLAN_STA_AUTHORIZED);
  
        rates = 0;
        basic_rates = 0;
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
  
 -      if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
 +      if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
 +          (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                struct ieee80211_ht_bss_info bss_info;
                ieee80211_ht_cap_ie_to_ht_info(
                                (struct ieee80211_ht_cap *)
  
        rate_control_rate_init(sta, local);
  
 -      if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
 -              sta->flags |= WLAN_STA_WME;
 +      if (elems.wmm_param) {
 +              set_sta_flags(sta, WLAN_STA_WME);
                rcu_read_unlock();
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
@@@ -2357,7 -2284,6 +2360,7 @@@ static void ieee80211_rx_bss_free(struc
        kfree(bss->rsn_ie);
        kfree(bss->wmm_ie);
        kfree(bss->ht_ie);
 +      kfree(bss->ht_add_ie);
        kfree(bss_mesh_id(bss));
        kfree(bss_mesh_cfg(bss));
        kfree(bss);
@@@ -2408,7 -2334,7 +2411,7 @@@ static int ieee80211_sta_join_ibss(stru
        int res, rates, i, j;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
 -      struct ieee80211_tx_control control;
 +      struct ieee80211_tx_info *control;
        struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
                memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
                mgmt->u.beacon.beacon_int =
                        cpu_to_le16(local->hw.conf.beacon_int);
 +              mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
                mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
  
                pos = skb_put(skb, 2 + ifsta->ssid_len);
                        memcpy(pos, &bss->supp_rates[8], rates);
                }
  
 -              memset(&control, 0, sizeof(control));
 +              control = IEEE80211_SKB_CB(skb);
 +
                rate_control_get_rate(dev, sband, skb, &ratesel);
 -              if (!ratesel.rate) {
 +              if (ratesel.rate_idx < 0) {
                        printk(KERN_DEBUG "%s: Failed to determine TX rate "
                               "for IBSS beacon\n", dev->name);
                        break;
                }
 -              control.vif = &sdata->vif;
 -              control.tx_rate = ratesel.rate;
 +              control->control.vif = &sdata->vif;
 +              control->tx_rate_idx = ratesel.rate_idx;
                if (sdata->bss_conf.use_short_preamble &&
 -                  ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
 -                      control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 -              control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 -              control.flags |= IEEE80211_TXCTL_NO_ACK;
 -              control.retry_limit = 1;
 +                  sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
 +                      control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
 +              control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 +              control->flags |= IEEE80211_TX_CTL_NO_ACK;
 +              control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
 +              control->control.retry_limit = 1;
  
                ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
                if (ifsta->probe_resp) {
                }
  
                if (local->ops->beacon_update &&
 -                  local->ops->beacon_update(local_to_hw(local),
 -                                           skb, &control) == 0) {
 +                  local->ops->beacon_update(local_to_hw(local), skb) == 0) {
                        printk(KERN_DEBUG "%s: Configured IBSS beacon "
                               "template\n", dev->name);
                        skb = NULL;
@@@ -2604,10 -2528,11 +2607,10 @@@ static void ieee80211_rx_bss_info(struc
                                  struct ieee80211_mgmt *mgmt,
                                  size_t len,
                                  struct ieee80211_rx_status *rx_status,
 +                                struct ieee802_11_elems *elems,
                                  int beacon)
  {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 -      struct ieee802_11_elems elems;
 -      size_t baselen;
        int freq, clen;
        struct ieee80211_sta_bss *bss;
        struct sta_info *sta;
        if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
  
 -#if 0
 -      printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
 -             dev->name, beacon ? "Beacon" : "Probe Response",
 -             print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
 -#endif
 -
 -      baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
 -      if (baselen > len)
 -              return;
 -
        beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
 -      ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
  
 -      if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
 -          elems.mesh_config && mesh_matches_local(&elems, dev)) {
 -              u64 rates = ieee80211_sta_get_rates(local, &elems,
 +      if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
 +          elems->mesh_config && mesh_matches_local(elems, dev)) {
 +              u64 rates = ieee80211_sta_get_rates(local, elems,
                                                rx_status->band);
  
                mesh_neighbour_update(mgmt->sa, rates, dev,
 -                                    mesh_peer_accepts_plinks(&elems, dev));
 +                                    mesh_peer_accepts_plinks(elems, dev));
        }
  
        rcu_read_lock();
  
 -      if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
 +      if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
            memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
            (sta = sta_info_get(local, mgmt->sa))) {
                u64 prev_rates;
 -              u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
 +              u64 supp_rates = ieee80211_sta_get_rates(local, elems,
                                                        rx_status->band);
  
                prev_rates = sta->supp_rates[rx_status->band];
                        sta->supp_rates[rx_status->band] =
                                sdata->u.sta.supp_rates_bits[rx_status->band];
                }
 -              if (sta->supp_rates[rx_status->band] != prev_rates) {
 -                      printk(KERN_DEBUG "%s: updated supp_rates set for "
 -                             "%s based on beacon info (0x%llx & 0x%llx -> "
 -                             "0x%llx)\n",
 -                             dev->name, print_mac(mac, sta->addr),
 -                             (unsigned long long) prev_rates,
 -                             (unsigned long long) supp_rates,
 -                             (unsigned long long) sta->supp_rates[rx_status->band]);
 -              }
        }
  
        rcu_read_unlock();
  
 -      if (elems.ds_params && elems.ds_params_len == 1)
 -              freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
 +      if (elems->ds_params && elems->ds_params_len == 1)
 +              freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
        else
                freq = rx_status->freq;
  
                return;
  
  #ifdef CONFIG_MAC80211_MESH
 -      if (elems.mesh_config)
 -              bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
 -                              elems.mesh_id_len, elems.mesh_config, freq);
 +      if (elems->mesh_config)
 +              bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id,
 +                              elems->mesh_id_len, elems->mesh_config, freq);
        else
  #endif
                bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
 -                                         elems.ssid, elems.ssid_len);
 +                                         elems->ssid, elems->ssid_len);
        if (!bss) {
  #ifdef CONFIG_MAC80211_MESH
 -              if (elems.mesh_config)
 -                      bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
 -                              elems.mesh_id_len, elems.mesh_config,
 -                              elems.mesh_config_len, freq);
 +              if (elems->mesh_config)
 +                      bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id,
 +                              elems->mesh_id_len, elems->mesh_config,
 +                              elems->mesh_config_len, freq);
                else
  #endif
                        bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
 -                                                 elems.ssid, elems.ssid_len);
 +                                                elems->ssid, elems->ssid_len);
                if (!bss)
                        return;
        } else {
        }
  
        /* save the ERP value so that it is available at association time */
 -      if (elems.erp_info && elems.erp_info_len >= 1) {
 -              bss->erp_value = elems.erp_info[0];
 +      if (elems->erp_info && elems->erp_info_len >= 1) {
 +              bss->erp_value = elems->erp_info[0];
                bss->has_erp_value = 1;
        }
  
 -      if (elems.ht_cap_elem &&
 -           (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
 -           memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
 +      if (elems->ht_cap_elem &&
 +           (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
 +           memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
                kfree(bss->ht_ie);
 -              bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
 +              bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
                if (bss->ht_ie) {
 -                      memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
 -                              elems.ht_cap_elem_len + 2);
 -                      bss->ht_ie_len = elems.ht_cap_elem_len + 2;
 +                      memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
 +                              elems->ht_cap_elem_len + 2);
 +                      bss->ht_ie_len = elems->ht_cap_elem_len + 2;
                } else
                        bss->ht_ie_len = 0;
 -      } else if (!elems.ht_cap_elem && bss->ht_ie) {
 +      } else if (!elems->ht_cap_elem && bss->ht_ie) {
                kfree(bss->ht_ie);
                bss->ht_ie = NULL;
                bss->ht_ie_len = 0;
        }
  
 +      if (elems->ht_info_elem &&
 +           (!bss->ht_add_ie ||
 +           bss->ht_add_ie_len != elems->ht_info_elem_len ||
 +           memcmp(bss->ht_add_ie, elems->ht_info_elem,
 +                      elems->ht_info_elem_len))) {
 +              kfree(bss->ht_add_ie);
 +              bss->ht_add_ie =
 +                      kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
 +              if (bss->ht_add_ie) {
 +                      memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
 +                              elems->ht_info_elem_len + 2);
 +                      bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
 +              } else
 +                      bss->ht_add_ie_len = 0;
 +      } else if (!elems->ht_info_elem && bss->ht_add_ie) {
 +              kfree(bss->ht_add_ie);
 +              bss->ht_add_ie = NULL;
 +              bss->ht_add_ie_len = 0;
 +      }
 +
        bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
        bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
  
        bss->supp_rates_len = 0;
 -      if (elems.supp_rates) {
 +      if (elems->supp_rates) {
                clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
 -              if (clen > elems.supp_rates_len)
 -                      clen = elems.supp_rates_len;
 -              memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
 +              if (clen > elems->supp_rates_len)
 +                      clen = elems->supp_rates_len;
 +              memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
                       clen);
                bss->supp_rates_len += clen;
        }
 -      if (elems.ext_supp_rates) {
 +      if (elems->ext_supp_rates) {
                clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
 -              if (clen > elems.ext_supp_rates_len)
 -                      clen = elems.ext_supp_rates_len;
 +              if (clen > elems->ext_supp_rates_len)
 +                      clen = elems->ext_supp_rates_len;
                memcpy(&bss->supp_rates[bss->supp_rates_len],
 -                     elems.ext_supp_rates, clen);
 +                     elems->ext_supp_rates, clen);
                bss->supp_rates_len += clen;
        }
  
  
        bss->timestamp = beacon_timestamp;
        bss->last_update = jiffies;
 -      bss->rssi = rx_status->ssi;
        bss->signal = rx_status->signal;
        bss->noise = rx_status->noise;
 +      bss->qual = rx_status->qual;
        if (!beacon && !bss->probe_resp)
                bss->probe_resp = true;
  
                return;
        }
  
 -      if (elems.wpa &&
 -          (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
 -           memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
 +      if (elems->wpa &&
 +          (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
 +           memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
                kfree(bss->wpa_ie);
 -              bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
 +              bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
                if (bss->wpa_ie) {
 -                      memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
 -                      bss->wpa_ie_len = elems.wpa_len + 2;
 +                      memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
 +                      bss->wpa_ie_len = elems->wpa_len + 2;
                } else
                        bss->wpa_ie_len = 0;
 -      } else if (!elems.wpa && bss->wpa_ie) {
 +      } else if (!elems->wpa && bss->wpa_ie) {
                kfree(bss->wpa_ie);
                bss->wpa_ie = NULL;
                bss->wpa_ie_len = 0;
        }
  
 -      if (elems.rsn &&
 -          (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
 -           memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
 +      if (elems->rsn &&
 +          (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
 +           memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
                kfree(bss->rsn_ie);
 -              bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
 +              bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
                if (bss->rsn_ie) {
 -                      memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
 -                      bss->rsn_ie_len = elems.rsn_len + 2;
 +                      memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
 +                      bss->rsn_ie_len = elems->rsn_len + 2;
                } else
                        bss->rsn_ie_len = 0;
 -      } else if (!elems.rsn && bss->rsn_ie) {
 +      } else if (!elems->rsn && bss->rsn_ie) {
                kfree(bss->rsn_ie);
                bss->rsn_ie = NULL;
                bss->rsn_ie_len = 0;
         * inclusion of the WMM Parameters in beacons, however, is optional.
         */
  
 -      if (elems.wmm_param &&
 -          (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
 -           memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
 +      if (elems->wmm_param &&
 +          (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
 +           memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
                kfree(bss->wmm_ie);
 -              bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
 +              bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
                if (bss->wmm_ie) {
 -                      memcpy(bss->wmm_ie, elems.wmm_param - 2,
 -                             elems.wmm_param_len + 2);
 -                      bss->wmm_ie_len = elems.wmm_param_len + 2;
 +                      memcpy(bss->wmm_ie, elems->wmm_param - 2,
 +                             elems->wmm_param_len + 2);
 +                      bss->wmm_ie_len = elems->wmm_param_len + 2;
                } else
                        bss->wmm_ie_len = 0;
 -      } else if (elems.wmm_info &&
 -                  (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len ||
 -                   memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) {
 +      } else if (elems->wmm_info &&
 +                  (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
 +                   memcmp(bss->wmm_ie, elems->wmm_info,
 +                                              elems->wmm_info_len))) {
                 /* As for certain AP's Fifth bit is not set in WMM IE in
                  * beacon frames.So while parsing the beacon frame the
                  * wmm_info structure is used instead of wmm_param.
                  * n-band association.
                  */
                kfree(bss->wmm_ie);
 -              bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC);
 +              bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
                if (bss->wmm_ie) {
 -                      memcpy(bss->wmm_ie, elems.wmm_info - 2,
 -                             elems.wmm_info_len + 2);
 -                      bss->wmm_ie_len = elems.wmm_info_len + 2;
 +                      memcpy(bss->wmm_ie, elems->wmm_info - 2,
 +                             elems->wmm_info_len + 2);
 +                      bss->wmm_ie_len = elems->wmm_info_len + 2;
                } else
                        bss->wmm_ie_len = 0;
 -      } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) {
 +      } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
                kfree(bss->wmm_ie);
                bss->wmm_ie = NULL;
                bss->wmm_ie_len = 0;
            !local->sta_sw_scanning && !local->sta_hw_scanning &&
            bss->capability & WLAN_CAPABILITY_IBSS &&
            bss->freq == local->oper_channel->center_freq &&
 -          elems.ssid_len == sdata->u.sta.ssid_len &&
 -          memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
 +          elems->ssid_len == sdata->u.sta.ssid_len &&
 +          memcmp(elems->ssid, sdata->u.sta.ssid,
 +                              sdata->u.sta.ssid_len) == 0) {
                if (rx_status->flag & RX_FLAG_TSFT) {
                        /* in order for correct IBSS merging we need mactime
                         *
  #endif /* CONFIG_MAC80211_IBSS_DEBUG */
                if (beacon_timestamp > rx_timestamp) {
  #ifndef CONFIG_MAC80211_IBSS_DEBUG
 -                      if (net_ratelimit())
 +                      printk(KERN_DEBUG "%s: beacon TSF higher than "
 +                             "local TSF - IBSS merge with BSSID %s\n",
 +                             dev->name, print_mac(mac, mgmt->bssid));
  #endif
 -                              printk(KERN_DEBUG "%s: beacon TSF higher than "
 -                                     "local TSF - IBSS merge with BSSID %s\n",
 -                                     dev->name, print_mac(mac, mgmt->bssid));
                        ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
                        ieee80211_ibss_add_sta(dev, NULL,
 -                                             mgmt->bssid, mgmt->sa);
 +                                             mgmt->bssid, mgmt->sa,
 +                                             BIT(rx_status->rate_idx));
                }
        }
  
@@@ -2924,17 -2847,7 +2927,17 @@@ static void ieee80211_rx_mgmt_probe_res
                                         size_t len,
                                         struct ieee80211_rx_status *rx_status)
  {
 -      ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);
 +      size_t baselen;
 +      struct ieee802_11_elems elems;
 +
 +      baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
 +      if (baselen > len)
 +              return;
 +
 +      ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
 +                              &elems);
 +
 +      ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0);
  }
  
  
@@@ -2951,14 -2864,7 +2954,14 @@@ static void ieee80211_rx_mgmt_beacon(st
        struct ieee80211_conf *conf = &local->hw.conf;
        u32 changed = 0;
  
 -      ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
 +      /* Process beacon from the current BSS */
 +      baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
 +      if (baselen > len)
 +              return;
 +
 +      ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 +
 +      ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1);
  
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
            memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
  
 -      /* Process beacon from the current BSS */
 -      baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
 -      if (baselen > len)
 -              return;
 -
 -      ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 -
 -      if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
 -              ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
 -                                       elems.wmm_param_len);
 -      }
 +      ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
 +                               elems.wmm_param_len);
  
        /* Do not send changes to driver if we are scanning. This removes
         * requirement that driver's bss_info_changed function needs to be
@@@ -3047,11 -2962,11 +3050,11 @@@ static void ieee80211_rx_mgmt_probe_req
        pos = mgmt->u.probe_req.variable;
        if (pos[0] != WLAN_EID_SSID ||
            pos + 2 + pos[1] > end) {
 -              if (net_ratelimit()) {
 -                      printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
 -                             "from %s\n",
 -                             dev->name, print_mac(mac, mgmt->sa));
 -              }
 +#ifdef CONFIG_MAC80211_IBSS_DEBUG
 +              printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
 +                     "from %s\n",
 +                     dev->name, print_mac(mac, mgmt->sa));
 +#endif
                return;
        }
        if (pos[1] != 0 &&
@@@ -3082,24 -2997,11 +3085,24 @@@ static void ieee80211_rx_mgmt_action(st
                                     struct ieee80211_rx_status *rx_status)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 +      struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
  
        if (len < IEEE80211_MIN_ACTION_SIZE)
                return;
  
        switch (mgmt->u.action.category) {
 +      case WLAN_CATEGORY_SPECTRUM_MGMT:
 +              if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
 +                      break;
 +              switch (mgmt->u.action.u.chan_switch.action_code) {
 +              case WLAN_ACTION_SPCT_MSR_REQ:
 +                      if (len < (IEEE80211_MIN_ACTION_SIZE +
 +                                 sizeof(mgmt->u.action.u.measurement)))
 +                              break;
 +                      ieee80211_sta_process_measurement_req(dev, mgmt, len);
 +                      break;
 +              }
 +              break;
        case WLAN_CATEGORY_BACK:
                switch (mgmt->u.action.u.addba_req.action_code) {
                case WLAN_ACTION_ADDBA_REQ:
                                break;
                        ieee80211_sta_process_delba(dev, mgmt, len);
                        break;
 -              default:
 -                      if (net_ratelimit())
 -                         printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
 -                                      dev->name);
 -                      break;
                }
                break;
        case PLINK_CATEGORY:
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        mesh_rx_path_sel_frame(dev, mgmt, len);
                break;
 -      default:
 -              if (net_ratelimit())
 -                      printk(KERN_DEBUG "%s: Rx unknown action frame - "
 -                      "category=%d\n", dev->name, mgmt->u.action.category);
 -              break;
        }
  }
  
@@@ -3165,6 -3077,11 +3168,6 @@@ void ieee80211_sta_rx_mgmt(struct net_d
                skb_queue_tail(&ifsta->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifsta->work);
                return;
 -      default:
 -              printk(KERN_DEBUG "%s: received unknown management frame - "
 -                     "stype=%d\n", dev->name,
 -                     (fc & IEEE80211_FCTL_STYPE) >> 4);
 -              break;
        }
  
   fail:
@@@ -3228,32 -3145,33 +3231,32 @@@ ieee80211_sta_rx_scan(struct net_devic
                      struct ieee80211_rx_status *rx_status)
  {
        struct ieee80211_mgmt *mgmt;
 -      u16 fc;
 +      __le16 fc;
  
        if (skb->len < 2)
                return RX_DROP_UNUSABLE;
  
        mgmt = (struct ieee80211_mgmt *) skb->data;
 -      fc = le16_to_cpu(mgmt->frame_control);
 +      fc = mgmt->frame_control;
  
 -      if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
 +      if (ieee80211_is_ctl(fc))
                return RX_CONTINUE;
  
        if (skb->len < 24)
                return RX_DROP_MONITOR;
  
 -      if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 -              if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
 -                      ieee80211_rx_mgmt_probe_resp(dev, mgmt,
 -                                                   skb->len, rx_status);
 -                      dev_kfree_skb(skb);
 -                      return RX_QUEUED;
 -              } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
 -                      ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
 -                                               rx_status);
 -                      dev_kfree_skb(skb);
 -                      return RX_QUEUED;
 -              }
 +      if (ieee80211_is_probe_resp(fc)) {
 +              ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
 +              dev_kfree_skb(skb);
 +              return RX_QUEUED;
 +      }
 +
 +      if (ieee80211_is_beacon(fc)) {
 +              ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
 +              dev_kfree_skb(skb);
 +              return RX_QUEUED;
        }
 +
        return RX_CONTINUE;
  }
  
@@@ -3293,10 -3211,8 +3296,10 @@@ static void ieee80211_sta_expire(struc
        spin_lock_irqsave(&local->sta_lock, flags);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
                if (time_after(jiffies, sta->last_rx + exp_time)) {
 +#ifdef CONFIG_MAC80211_IBSS_DEBUG
                        printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
                               dev->name, print_mac(mac, sta->addr));
 +#endif
                        __sta_info_unlink(&sta);
                        if (sta)
                                list_add(&sta->list, &tmp_list);
@@@ -3379,10 -3295,13 +3382,10 @@@ void ieee80211_sta_work(struct work_str
        if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
  
 -      if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
 -          sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 -          sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
 -              printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
 -                     "(type=%d)\n", dev->name, sdata->vif.type);
 +      if (WARN_ON(sdata->vif.type != IEEE80211_IF_TYPE_STA &&
 +                  sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 +                  sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT))
                return;
 -      }
        ifsta = &sdata->u.sta;
  
        while ((skb = skb_dequeue(&ifsta->skb_queue)))
                break;
  #endif
        default:
 -              printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
 -                     ifsta->state);
 +              WARN_ON(1);
                break;
        }
  
@@@ -3471,6 -3391,8 +3474,6 @@@ static void ieee80211_sta_reset_auth(st
                ifsta->auth_alg = WLAN_AUTH_LEAP;
        else
                ifsta->auth_alg = WLAN_AUTH_OPEN;
 -      printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
 -             ifsta->auth_alg);
        ifsta->auth_transaction = -1;
        ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
        ifsta->auth_tries = ifsta->assoc_tries = 0;
@@@ -3559,9 -3481,9 +3562,9 @@@ static int ieee80211_sta_config_auth(st
                    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
                        continue;
  
 -              if (!selected || top_rssi < bss->rssi) {
 +              if (!selected || top_rssi < bss->signal) {
                        selected = bss;
 -                      top_rssi = bss->rssi;
 +                      top_rssi = bss->signal;
                }
        }
        if (selected)
@@@ -3634,16 -3556,14 +3637,16 @@@ static int ieee80211_sta_create_ibss(st
        sband = local->hw.wiphy->bands[bss->band];
  
        if (local->hw.conf.beacon_int == 0)
 -              local->hw.conf.beacon_int = 10000;
 +              local->hw.conf.beacon_int = 100;
        bss->beacon_int = local->hw.conf.beacon_int;
        bss->last_update = jiffies;
        bss->capability = WLAN_CAPABILITY_IBSS;
 -      if (sdata->default_key) {
 +
 +      if (sdata->default_key)
                bss->capability |= WLAN_CAPABILITY_PRIVACY;
 -      else
 +      else
                sdata->drop_unencrypted = 0;
 +
        bss->supp_rates_len = sband->n_bitrates;
        pos = bss->supp_rates;
        for (i = 0; i < sband->n_bitrates; i++) {
@@@ -3694,8 -3614,10 +3697,10 @@@ static int ieee80211_sta_find_ibss(stru
        spin_unlock_bh(&local->sta_bss_lock);
  
  #ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
-              "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
+       if (found)
+               printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+                      "%s\n", print_mac(mac, bssid),
+                      print_mac(mac2, ifsta->bssid));
  #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
            (bss = ieee80211_rx_bss_get(dev, bssid,
@@@ -3827,7 -3749,7 +3832,7 @@@ static void ieee80211_send_nullfunc(str
  {
        struct sk_buff *skb;
        struct ieee80211_hdr *nullfunc;
 -      u16 fc;
 +      __le16 fc;
  
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
        if (!skb) {
  
        nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
        memset(nullfunc, 0, 24);
 -      fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
 -           IEEE80211_FCTL_TODS;
 +      fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
 +                       IEEE80211_FCTL_TODS);
        if (powersave)
 -              fc |= IEEE80211_FCTL_PM;
 -      nullfunc->frame_control = cpu_to_le16(fc);
 +              fc |= cpu_to_le16(IEEE80211_FCTL_PM);
 +      nullfunc->frame_control = fc;
        memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
@@@ -4137,7 -4059,6 +4142,7 @@@ int ieee80211_sta_req_scan(struct net_d
  
  static char *
  ieee80211_sta_scan_result(struct net_device *dev,
 +                        struct iw_request_info *info,
                          struct ieee80211_sta_bss *bss,
                          char *current_ev, char *end_buf)
  {
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
        memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
 -      current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 +      current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_ADDR_LEN);
  
        memset(&iwe, 0, sizeof(iwe));
        if (bss_mesh_cfg(bss)) {
                iwe.u.data.length = bss_mesh_id_len(bss);
                iwe.u.data.flags = 1;
 -              current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
 -                                                bss_mesh_id(bss));
 +              current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                                &iwe, bss_mesh_id(bss));
        } else {
                iwe.u.data.length = bss->ssid_len;
                iwe.u.data.flags = 1;
 -              current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
 -                                                bss->ssid);
 +              current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                                &iwe, bss->ssid);
        }
  
        if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
                        iwe.u.mode = IW_MODE_MASTER;
                else
                        iwe.u.mode = IW_MODE_ADHOC;
 -              current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 -                                                IW_EV_UINT_LEN);
 +              current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 +                                                &iwe, IW_EV_UINT_LEN);
        }
  
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
        iwe.u.freq.e = 0;
 -      current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 +      current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
  
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWFREQ;
        iwe.u.freq.m = bss->freq;
        iwe.u.freq.e = 6;
 -      current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 +      current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = IWEVQUAL;
 -      iwe.u.qual.qual = bss->signal;
 -      iwe.u.qual.level = bss->rssi;
 +      iwe.u.qual.qual = bss->qual;
 +      iwe.u.qual.level = bss->signal;
        iwe.u.qual.noise = bss->noise;
        iwe.u.qual.updated = local->wstats_flags;
 -      current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 +      current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_QUAL_LEN);
  
        memset(&iwe, 0, sizeof(iwe));
        else
                iwe.u.data.flags = IW_ENCODE_DISABLED;
        iwe.u.data.length = 0;
 -      current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
 +      current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                        &iwe, "");
  
        if (bss && bss->wpa_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->wpa_ie_len;
 -              current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
 -                                                bss->wpa_ie);
 +              current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                                &iwe, bss->wpa_ie);
        }
  
        if (bss && bss->rsn_ie) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVGENIE;
                iwe.u.data.length = bss->rsn_ie_len;
 -              current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
 -                                                bss->rsn_ie);
 +              current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                                &iwe, bss->rsn_ie);
 +      }
 +
 +      if (bss && bss->ht_ie) {
 +              memset(&iwe, 0, sizeof(iwe));
 +              iwe.cmd = IWEVGENIE;
 +              iwe.u.data.length = bss->ht_ie_len;
 +              current_ev = iwe_stream_add_point(info, current_ev, end_buf,
 +                                                &iwe, bss->ht_ie);
        }
  
        if (bss && bss->supp_rates_len > 0) {
                /* display all supported rates in readable format */
 -              char *p = current_ev + IW_EV_LCP_LEN;
 +              char *p = current_ev + iwe_stream_lcp_len(info);
                int i;
  
                memset(&iwe, 0, sizeof(iwe));
                for (i = 0; i < bss->supp_rates_len; i++) {
                        iwe.u.bitrate.value = ((bss->supp_rates[i] &
                                                        0x7f) * 500000);
 -                      p = iwe_stream_add_value(current_ev, p,
 +                      p = iwe_stream_add_value(info, current_ev, p,
                                        end_buf, &iwe, IW_EV_PARAM_LEN);
                }
                current_ev = p;
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
 +                      memset(&iwe, 0, sizeof(iwe));
 +                      iwe.cmd = IWEVCUSTOM;
 +                      sprintf(buf, " Last beacon: %dms ago",
 +                              jiffies_to_msecs(jiffies - bss->last_update));
 +                      iwe.u.data.length = strlen(buf);
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf, &iwe, buf);
                        kfree(buf);
                }
        }
                        iwe.cmd = IWEVCUSTOM;
                        sprintf(buf, "Mesh network (version %d)", cfg[0]);
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Protocol ID: "
                                "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
                                                        cfg[4]);
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Path Selection Metric ID: "
                                "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
                                                        cfg[8]);
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Congestion Control Mode ID: "
                                "0x%02X%02X%02X%02X", cfg[9], cfg[10],
                                                        cfg[11], cfg[12]);
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
                        sprintf(buf, "Channel Precedence: "
                                "0x%02X%02X%02X%02X", cfg[13], cfg[14],
                                                        cfg[15], cfg[16]);
                        iwe.u.data.length = strlen(buf);
 -                      current_ev = iwe_stream_add_point(current_ev, end_buf,
 +                      current_ev = iwe_stream_add_point(info, current_ev,
 +                                                        end_buf,
                                                          &iwe, buf);
                        kfree(buf);
                }
  }
  
  
 -int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
 +int ieee80211_sta_scan_results(struct net_device *dev,
 +                             struct iw_request_info *info,
 +                             char *buf, size_t len)
  {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        char *current_ev = buf;
                        spin_unlock_bh(&local->sta_bss_lock);
                        return -E2BIG;
                }
 -              current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
 -                                                     end_buf);
 +              current_ev = ieee80211_sta_scan_result(dev, info, bss,
 +                                                     current_ev, end_buf);
        }
        spin_unlock_bh(&local->sta_bss_lock);
        return current_ev - buf;
@@@ -4355,7 -4252,6 +4360,7 @@@ int ieee80211_sta_set_extra_ie(struct n
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 +
        kfree(ifsta->extra_ie);
        if (len == 0) {
                ifsta->extra_ie = NULL;
  }
  
  
 -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 -                                       struct sk_buff *skb, u8 *bssid,
 -                                       u8 *addr)
 +struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 +                                      struct sk_buff *skb, u8 *bssid,
 +                                      u8 *addr, u64 supp_rates)
  {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        DECLARE_MAC_BUF(mac);
 +      int band = local->hw.conf.channel->band;
  
        /* TODO: Could consider removing the least recently used entry and
         * allow new one to be added. */
                return NULL;
        }
  
 +      if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
 +              return NULL;
 +
 +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
               wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
 +#endif
  
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
        if (!sta)
                return NULL;
  
 -      sta->flags |= WLAN_STA_AUTHORIZED;
 +      set_sta_flags(sta, WLAN_STA_AUTHORIZED);
  
 -      sta->supp_rates[local->hw.conf.channel->band] =
 -              sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
 +      if (supp_rates)
 +              sta->supp_rates[band] = supp_rates;
 +      else
 +              sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band];
  
        rate_control_rate_init(sta, local);
  
@@@ -4426,7 -4314,7 +4431,7 @@@ int ieee80211_sta_deauthenticate(struc
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
  
 -      printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
 +      printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
               dev->name, reason);
  
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
@@@ -4444,7 -4332,7 +4449,7 @@@ int ieee80211_sta_disassociate(struct n
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
  
 -      printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
 +      printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
               dev->name, reason);
  
        if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
diff --combined net/sctp/sm_statefuns.c
index b66a41d03c0d0de7855447809fcd99d08b6610fc,fcdb45d1071bb9c0ca90c7b680145b5521c87f1d..8848d329aa2cea8bea3e3aec60405a4af51767cb
@@@ -795,6 -795,8 +795,6 @@@ sctp_disposition_t sctp_sf_do_5_1D_ce(c
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
  
 -      sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 -
        /* This will send the COOKIE ACK */
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
  
@@@ -881,6 -883,7 +881,6 @@@ sctp_disposition_t sctp_sf_do_5_1E_ca(c
        if (asoc->autoclose)
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
 -      sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
  
        /* It may also notify its ULP about the successful
         * establishment of the association with a Communication Up
@@@ -1778,6 -1781,7 +1778,6 @@@ static sctp_disposition_t sctp_sf_do_du
                goto nomem;
  
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 -      sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
  
        /* RFC 2960 5.1 Normal Establishment of an Association
         *
@@@ -1894,13 -1898,12 +1894,13 @@@ static sctp_disposition_t sctp_sf_do_du
  
                }
        }
 -      sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
  
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem;
  
 +      sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 +
        if (ev)
                sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
                                SCTP_ULPEVENT(ev));
                sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
                                        SCTP_ULPEVENT(ai_ev));
  
 -      sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 -      sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 -
        return SCTP_DISPOSITION_CONSUME;
  
  nomem:
@@@ -3964,6 -3970,9 +3964,6 @@@ sctp_disposition_t sctp_sf_unk_chunk(co
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                break;
        case SCTP_CID_ACTION_DISCARD_ERR:
 -              /* Discard the packet.  */
 -              sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 -
                /* Generate an ERROR chunk as response. */
                hdr = unk_chunk->chunk_hdr;
                err_chunk = sctp_make_op_error(asoc, unk_chunk,
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err_chunk));
                }
 +
 +              /* Discard the packet.  */
 +              sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                return SCTP_DISPOSITION_CONSUME;
                break;
        case SCTP_CID_ACTION_SKIP:
@@@ -5893,12 -5899,6 +5893,6 @@@ static int sctp_eat_data(const struct s
                return SCTP_IERROR_NO_DATA;
        }
  
-       /* If definately accepting the DATA chunk, record its TSN, otherwise
-        * wait for renege processing.
-        */
-       if (SCTP_CMD_CHUNK_ULP == deliver)
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
        chunk->data_accepted = 1;
  
        /* Note: Some chunks may get overcounted (if we drop) or overcounted
         * and discard the DATA chunk.
         */
        if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
+               /* Mark tsn as received even though we drop it */
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
                err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
                                         &data_hdr->stream,
                                         sizeof(data_hdr->stream));