Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 26 Apr 2011 19:39:10 +0000 (15:39 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 26 Apr 2011 19:39:10 +0000 (15:39 -0400)
13 files changed:
1  2 
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/mac80211/cfg.c

  #include "htc.h"
  
  /* identify firmware images */
 -#define FIRMWARE_AR7010               "ar7010.fw"
 -#define FIRMWARE_AR7010_1_1   "ar7010_1_1.fw"
 -#define FIRMWARE_AR9271               "ar9271.fw"
 +#define FIRMWARE_AR7010_1_1     "htc_7010.fw"
 +#define FIRMWARE_AR9271         "htc_9271.fw"
  
 -MODULE_FIRMWARE(FIRMWARE_AR7010);
  MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
  MODULE_FIRMWARE(FIRMWARE_AR9271);
  
@@@ -78,7 -80,7 +78,7 @@@ static void hif_usb_regout_cb(struct ur
  
        if (cmd) {
                ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
 -                                        cmd->skb, 1);
 +                                        cmd->skb, true);
                kfree(cmd);
        }
  
@@@ -124,90 -126,6 +124,90 @@@ static int hif_usb_send_regout(struct h
        return ret;
  }
  
 +static void hif_usb_mgmt_cb(struct urb *urb)
 +{
 +      struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
 +      struct hif_device_usb *hif_dev = cmd->hif_dev;
 +      bool txok = true;
 +
 +      if (!cmd || !cmd->skb || !cmd->hif_dev)
 +              return;
 +
 +      switch (urb->status) {
 +      case 0:
 +              break;
 +      case -ENOENT:
 +      case -ECONNRESET:
 +      case -ENODEV:
 +      case -ESHUTDOWN:
 +              txok = false;
 +
 +              /*
 +               * If the URBs are being flushed, no need to complete
 +               * this packet.
 +               */
 +              spin_lock(&hif_dev->tx.tx_lock);
 +              if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
 +                      spin_unlock(&hif_dev->tx.tx_lock);
 +                      dev_kfree_skb_any(cmd->skb);
 +                      kfree(cmd);
 +                      return;
 +              }
 +              spin_unlock(&hif_dev->tx.tx_lock);
 +
 +              break;
 +      default:
 +              txok = false;
 +              break;
 +      }
 +
 +      skb_pull(cmd->skb, 4);
 +      ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
 +                                cmd->skb, txok);
 +      kfree(cmd);
 +}
 +
 +static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
 +                           struct sk_buff *skb)
 +{
 +      struct urb *urb;
 +      struct cmd_buf *cmd;
 +      int ret = 0;
 +      __le16 *hdr;
 +
 +      urb = usb_alloc_urb(0, GFP_ATOMIC);
 +      if (urb == NULL)
 +              return -ENOMEM;
 +
 +      cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
 +      if (cmd == NULL) {
 +              usb_free_urb(urb);
 +              return -ENOMEM;
 +      }
 +
 +      cmd->skb = skb;
 +      cmd->hif_dev = hif_dev;
 +
 +      hdr = (__le16 *) skb_push(skb, 4);
 +      *hdr++ = cpu_to_le16(skb->len - 4);
 +      *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
 +
 +      usb_fill_bulk_urb(urb, hif_dev->udev,
 +                       usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
 +                       skb->data, skb->len,
 +                       hif_usb_mgmt_cb, cmd);
 +
 +      usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
 +      ret = usb_submit_urb(urb, GFP_ATOMIC);
 +      if (ret) {
 +              usb_unanchor_urb(urb);
 +              kfree(cmd);
 +      }
 +      usb_free_urb(urb);
 +
 +      return ret;
 +}
 +
  static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
                                         struct sk_buff_head *list)
  {
  
        while ((skb = __skb_dequeue(list)) != NULL) {
                dev_kfree_skb_any(skb);
 -              TX_STAT_INC(skb_dropped);
 +      }
 +}
 +
 +static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
 +                                          struct sk_buff_head *queue,
 +                                          bool txok)
 +{
 +      struct sk_buff *skb;
 +
 +      while ((skb = __skb_dequeue(queue)) != NULL) {
 +              ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
 +                                        skb, txok);
 +              if (txok)
 +                      TX_STAT_INC(skb_success);
 +              else
 +                      TX_STAT_INC(skb_failed);
        }
  }
  
@@@ -238,7 -141,7 +238,7 @@@ static void hif_usb_tx_cb(struct urb *u
  {
        struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
        struct hif_device_usb *hif_dev;
 -      struct sk_buff *skb;
 +      bool txok = true;
  
        if (!tx_buf || !tx_buf->hif_dev)
                return;
        case -ECONNRESET:
        case -ENODEV:
        case -ESHUTDOWN:
 -              /*
 -               * The URB has been killed, free the SKBs.
 -               */
 -              ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
 +              txok = false;
  
                /*
                 * If the URBs are being flushed, no need to add this
                spin_lock(&hif_dev->tx.tx_lock);
                if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
                        spin_unlock(&hif_dev->tx.tx_lock);
 +                      ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
                        return;
                }
                spin_unlock(&hif_dev->tx.tx_lock);
  
 -              /*
 -               * In the stop() case, this URB has to be added to
 -               * the free list.
 -               */
 -              goto add_free;
 +              break;
        default:
 +              txok = false;
                break;
        }
  
 -      /*
 -       * Check if TX has been stopped, this is needed because
 -       * this CB could have been invoked just after the TX lock
 -       * was released in hif_stop() and kill_urb() hasn't been
 -       * called yet.
 -       */
 -      spin_lock(&hif_dev->tx.tx_lock);
 -      if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
 -              spin_unlock(&hif_dev->tx.tx_lock);
 -              ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
 -              goto add_free;
 -      }
 -      spin_unlock(&hif_dev->tx.tx_lock);
 -
 -      /* Complete the queued SKBs. */
 -      while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
 -              ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
 -                                        skb, 1);
 -              TX_STAT_INC(skb_completed);
 -      }
 +      ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
  
 -add_free:
        /* Re-initialize the SKB queue */
        tx_buf->len = tx_buf->offset = 0;
        __skb_queue_head_init(&tx_buf->skb_queue);
@@@ -346,7 -274,7 +346,7 @@@ static int __hif_usb_tx(struct hif_devi
        ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
        if (ret) {
                tx_buf->len = tx_buf->offset = 0;
 -              ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
 +              ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
                __skb_queue_head_init(&tx_buf->skb_queue);
                list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
                hif_dev->tx.tx_buf_cnt++;
        return ret;
  }
  
 -static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
 -                         struct ath9k_htc_tx_ctl *tx_ctl)
 +static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
  {
 +      struct ath9k_htc_tx_ctl *tx_ctl;
        unsigned long flags;
 +      int ret = 0;
  
        spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
  
                return -ENOMEM;
        }
  
 -      __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
 -      hif_dev->tx.tx_skb_cnt++;
 +      spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
  
 -      /* Send normal frames immediately */
 -      if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
 -              __hif_usb_tx(hif_dev);
 +      tx_ctl = HTC_SKB_CB(skb);
 +
 +      /* Mgmt/Beacon frames don't use the TX buffer pool */
 +      if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
 +          (tx_ctl->type == ATH9K_HTC_BEACON)) {
 +              ret = hif_usb_send_mgmt(hif_dev, skb);
 +      }
 +
 +      spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 +
 +      if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
 +          (tx_ctl->type == ATH9K_HTC_AMPDU)) {
 +              __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
 +              hif_dev->tx.tx_skb_cnt++;
 +      }
  
        /* Check if AMPDUs have to be sent immediately */
 -      if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) &&
 -          (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
 +      if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
            (hif_dev->tx.tx_skb_cnt < 2)) {
                __hif_usb_tx(hif_dev);
        }
  
        spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
  
 -      return 0;
 +      return ret;
  }
  
 -static void hif_usb_start(void *hif_handle, u8 pipe_id)
 +static void hif_usb_start(void *hif_handle)
  {
        struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
        unsigned long flags;
        spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
  }
  
 -static void hif_usb_stop(void *hif_handle, u8 pipe_id)
 +static void hif_usb_stop(void *hif_handle)
  {
        struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
        struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
        unsigned long flags;
  
        spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 -      ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
 +      ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
        hif_dev->tx.tx_skb_cnt = 0;
        hif_dev->tx.flags |= HIF_USB_TX_STOP;
        spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
                                 &hif_dev->tx.tx_pending, list) {
                usb_kill_urb(tx_buf->urb);
        }
 +
 +      usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
  }
  
 -static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
 -                      struct ath9k_htc_tx_ctl *tx_ctl)
 +static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
  {
        struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
        int ret = 0;
  
        switch (pipe_id) {
        case USB_WLAN_TX_PIPE:
 -              ret = hif_usb_send_tx(hif_dev, skb, tx_ctl);
 +              ret = hif_usb_send_tx(hif_dev, skb);
                break;
        case USB_REG_OUT_PIPE:
                ret = hif_usb_send_regout(hif_dev, skb);
        return ret;
  }
  
 +static inline bool check_index(struct sk_buff *skb, u8 idx)
 +{
 +      struct ath9k_htc_tx_ctl *tx_ctl;
 +
 +      tx_ctl = HTC_SKB_CB(skb);
 +
 +      if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
 +          (tx_ctl->sta_idx == idx))
 +              return true;
 +
 +      return false;
 +}
 +
 +static void hif_usb_sta_drain(void *hif_handle, u8 idx)
 +{
 +      struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
 +      struct sk_buff *skb, *tmp;
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
 +
 +      skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
 +              if (check_index(skb, idx)) {
 +                      __skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
 +                      ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
 +                                                skb, false);
 +                      hif_dev->tx.tx_skb_cnt--;
 +                      TX_STAT_INC(skb_failed);
 +              }
 +      }
 +
 +      spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
 +}
 +
  static struct ath9k_htc_hif hif_usb = {
        .transport = ATH9K_HIF_USB,
        .name = "ath9k_hif_usb",
  
        .start = hif_usb_start,
        .stop = hif_usb_stop,
 +      .sta_drain = hif_usb_sta_drain,
        .send = hif_usb_send,
  };
  
@@@ -686,9 -567,6 +686,9 @@@ static void ath9k_hif_usb_reg_in_cb(str
        case -ESHUTDOWN:
                goto free;
        default:
 +              skb_reset_tail_pointer(skb);
 +              skb_trim(skb, 0);
 +
                goto resubmit;
        }
  
                                                 USB_REG_IN_PIPE),
                                 nskb->data, MAX_REG_IN_BUF_SIZE,
                                 ath9k_hif_usb_reg_in_cb, nskb);
 -
 -              ret = usb_submit_urb(urb, GFP_ATOMIC);
 -              if (ret) {
 -                      kfree_skb(nskb);
 -                      urb->context = NULL;
 -              }
 -
 -              return;
        }
  
  resubmit:
 -      skb_reset_tail_pointer(skb);
 -      skb_trim(skb, 0);
 -
 +      usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
        ret = usb_submit_urb(urb, GFP_ATOMIC);
 -      if (ret)
 +      if (ret) {
 +              usb_unanchor_urb(urb);
                goto free;
 +      }
  
        return;
  free:
@@@ -755,8 -641,6 +755,8 @@@ static void ath9k_hif_usb_dealloc_tx_ur
                kfree(tx_buf->buf);
                kfree(tx_buf);
        }
 +
 +      usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
  }
  
  static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
        INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
        spin_lock_init(&hif_dev->tx.tx_lock);
        __skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
 +      init_usb_anchor(&hif_dev->mgmt_submitted);
  
        for (i = 0; i < MAX_TX_URB_NUM; i++) {
                tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
@@@ -865,67 -748,43 +865,67 @@@ err_urb
        return ret;
  }
  
 -static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
 +static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
  {
 -      if (hif_dev->reg_in_urb) {
 -              usb_kill_urb(hif_dev->reg_in_urb);
 -              if (hif_dev->reg_in_urb->context)
 -                      kfree_skb((void *)hif_dev->reg_in_urb->context);
 -              usb_free_urb(hif_dev->reg_in_urb);
 -              hif_dev->reg_in_urb = NULL;
 -      }
 +      usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
  }
  
 -static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
 +static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
  {
 -      struct sk_buff *skb;
 +      struct urb *urb = NULL;
 +      struct sk_buff *skb = NULL;
 +      int i, ret;
  
 -      hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL);
 -      if (hif_dev->reg_in_urb == NULL)
 -              return -ENOMEM;
 +      init_usb_anchor(&hif_dev->reg_in_submitted);
  
 -      skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
 -      if (!skb)
 -              goto err;
 +      for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
  
 -      usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
 -                       usb_rcvbulkpipe(hif_dev->udev,
 -                                       USB_REG_IN_PIPE),
 -                       skb->data, MAX_REG_IN_BUF_SIZE,
 -                       ath9k_hif_usb_reg_in_cb, skb);
 +              /* Allocate URB */
 +              urb = usb_alloc_urb(0, GFP_KERNEL);
 +              if (urb == NULL) {
 +                      ret = -ENOMEM;
 +                      goto err_urb;
 +              }
  
 -      if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
 -              goto err;
 +              /* Allocate buffer */
 +              skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
 +              if (!skb) {
 +                      ret = -ENOMEM;
 +                      goto err_skb;
 +              }
 +
 +              usb_fill_bulk_urb(urb, hif_dev->udev,
 +                                usb_rcvbulkpipe(hif_dev->udev,
 +                                                USB_REG_IN_PIPE),
 +                                skb->data, MAX_REG_IN_BUF_SIZE,
 +                                ath9k_hif_usb_reg_in_cb, skb);
 +
 +              /* Anchor URB */
 +              usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
 +
 +              /* Submit URB */
 +              ret = usb_submit_urb(urb, GFP_KERNEL);
 +              if (ret) {
 +                      usb_unanchor_urb(urb);
 +                      goto err_submit;
 +              }
 +
 +              /*
 +               * Drop reference count.
 +               * This ensures that the URB is freed when killing them.
 +               */
 +              usb_free_urb(urb);
 +      }
  
        return 0;
  
 -err:
 -      ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
 -      return -ENOMEM;
 +err_submit:
 +      kfree_skb(skb);
 +err_skb:
 +      usb_free_urb(urb);
 +err_urb:
 +      ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
 +      return ret;
  }
  
  static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
                goto err_rx;
  
        /* Register Read */
 -      if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
 +      if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
                goto err_reg;
  
        return 0;
@@@ -957,7 -816,7 +957,7 @@@ err
  static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
  {
        usb_kill_anchored_urbs(&hif_dev->regout_submitted);
 -      ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
 +      ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
        ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
        ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
  }
@@@ -1167,7 -1026,10 +1167,7 @@@ static int ath9k_hif_usb_probe(struct u
        /* Find out which firmware to load */
  
        if (IS_AR7010_DEVICE(id->driver_info))
 -              if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
 -                      hif_dev->fw_name = FIRMWARE_AR7010_1_1;
 -              else
 -                      hif_dev->fw_name = FIRMWARE_AR7010;
 +              hif_dev->fw_name = FIRMWARE_AR7010_1_1;
        else
                hif_dev->fw_name = FIRMWARE_AR9271;
  
        }
  
        ret = ath9k_htc_hw_init(hif_dev->htc_handle,
-                               &hif_dev->udev->dev, hif_dev->device_id,
+                               &interface->dev, hif_dev->device_id,
                                hif_dev->udev->product, id->driver_info);
        if (ret) {
                ret = -EINVAL;
@@@ -1296,7 -1158,7 +1296,7 @@@ fail_resume
  #endif
  
  static struct usb_driver ath9k_hif_usb_driver = {
-       .name = "ath9k_hif_usb",
+       .name = KBUILD_MODNAME,
        .probe = ath9k_hif_usb_probe,
        .disconnect = ath9k_hif_usb_disconnect,
  #ifdef CONFIG_PM
@@@ -130,20 -130,6 +130,20 @@@ bool ath9k_hw_wait(struct ath_hw *ah, u
  }
  EXPORT_SYMBOL(ath9k_hw_wait);
  
 +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
 +                        int column, unsigned int *writecnt)
 +{
 +      int r;
 +
 +      ENABLE_REGWRITE_BUFFER(ah);
 +      for (r = 0; r < array->ia_rows; r++) {
 +              REG_WRITE(ah, INI_RA(array, r, 0),
 +                        INI_RA(array, r, column));
 +              DO_DELAY(*writecnt);
 +      }
 +      REGWRITE_BUFFER_FLUSH(ah);
 +}
 +
  u32 ath9k_hw_reverse_bits(u32 val, u32 n)
  {
        u32 retval;
        return retval;
  }
  
 -bool ath9k_get_channel_edges(struct ath_hw *ah,
 -                           u16 flags, u16 *low,
 -                           u16 *high)
 -{
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
 -
 -      if (flags & CHANNEL_5GHZ) {
 -              *low = pCap->low_5ghz_chan;
 -              *high = pCap->high_5ghz_chan;
 -              return true;
 -      }
 -      if ((flags & CHANNEL_2GHZ)) {
 -              *low = pCap->low_2ghz_chan;
 -              *high = pCap->high_2ghz_chan;
 -              return true;
 -      }
 -      return false;
 -}
 -
  u16 ath9k_hw_computetxtime(struct ath_hw *ah,
                           u8 phy, int kbps,
                           u32 frameLen, u16 rateix,
@@@ -247,17 -252,6 +247,17 @@@ static void ath9k_hw_read_revisions(str
  {
        u32 val;
  
 +      switch (ah->hw_version.devid) {
 +      case AR5416_AR9100_DEVID:
 +              ah->hw_version.macVersion = AR_SREV_VERSION_9100;
 +              break;
 +      case AR9300_DEVID_AR9340:
 +              ah->hw_version.macVersion = AR_SREV_VERSION_9340;
 +              val = REG_READ(ah, AR_SREV);
 +              ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
 +              return;
 +      }
 +
        val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
  
        if (val == 0xFF) {
@@@ -370,6 -364,11 +370,6 @@@ static void ath9k_hw_init_config(struc
                ah->config.spurchans[i][1] = AR_NO_SPUR;
        }
  
 -      if (ah->hw_version.devid != AR2427_DEVID_PCIE)
 -              ah->config.ht_enable = 1;
 -      else
 -              ah->config.ht_enable = 0;
 -
        /* PAPRD needs some more work to be enabled */
        ah->config.paprd_disable = 1;
  
@@@ -411,8 -410,6 +411,8 @@@ static void ath9k_hw_init_defaults(stru
        ah->sta_id1_defaults =
                AR_STA_ID1_CRPT_MIC_ENABLE |
                AR_STA_ID1_MCAST_KSRCH;
 +      if (AR_SREV_9100(ah))
 +              ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
        ah->enable_32kHz_clock = DONT_USE_32KHZ;
        ah->slottime = 20;
        ah->globaltxtimeout = (u32) -1;
@@@ -473,7 -470,7 +473,7 @@@ static int ath9k_hw_post_init(struct at
                return ecode;
        }
  
 -      if (!AR_SREV_9100(ah)) {
 +      if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) {
                ath9k_hw_ani_setup(ah);
                ath9k_hw_ani_init(ah);
        }
@@@ -495,6 -492,9 +495,6 @@@ static int __ath9k_hw_init(struct ath_h
        struct ath_common *common = ath9k_hw_common(ah);
        int r = 0;
  
 -      if (ah->hw_version.devid == AR5416_AR9100_DEVID)
 -              ah->hw_version.macVersion = AR_SREV_VERSION_9100;
 -
        ath9k_hw_read_revisions(ah);
  
        /*
        case AR_SREV_VERSION_9271:
        case AR_SREV_VERSION_9300:
        case AR_SREV_VERSION_9485:
 +      case AR_SREV_VERSION_9340:
                break;
        default:
                ath_err(common,
                return -EOPNOTSUPP;
        }
  
 -      if (AR_SREV_9271(ah) || AR_SREV_9100(ah))
 +      if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah))
                ah->is_pciexpress = false;
  
        ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
@@@ -630,7 -629,6 +630,7 @@@ int ath9k_hw_init(struct ath_hw *ah
        case AR2427_DEVID_PCIE:
        case AR9300_DEVID_PCIE:
        case AR9300_DEVID_AR9485_PCIE:
 +      case AR9300_DEVID_AR9340:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
@@@ -673,89 -671,48 +673,89 @@@ static void ath9k_hw_init_qos(struct at
        REGWRITE_BUFFER_FLUSH(ah);
  }
  
 -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
 +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
  {
 -              REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK)));
 -              udelay(100);
 -              REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK));
 +      REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
 +      udelay(100);
 +      REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
  
 -              while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
 -                      udelay(100);
 +      while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
 +              udelay(100);
  
 -              return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
 +      return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
  }
  EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
  
 -#define DPLL2_KD_VAL            0x3D
 -#define DPLL2_KI_VAL            0x06
 -#define DPLL3_PHASE_SHIFT_VAL   0x1
 -
  static void ath9k_hw_init_pll(struct ath_hw *ah,
                              struct ath9k_channel *chan)
  {
        u32 pll;
  
        if (AR_SREV_9485(ah)) {
 -              REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
 -              REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01);
 -
 -              REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
 -                            AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
  
 -              REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
 -              udelay(1000);
 +              /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 +                            AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 +                            AR_CH0_DPLL2_KD, 0x40);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 +                            AR_CH0_DPLL2_KI, 0x4);
  
 -              REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
 +                            AR_CH0_BB_DPLL1_REFDIV, 0x5);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
 +                            AR_CH0_BB_DPLL1_NINI, 0x58);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
 +                            AR_CH0_BB_DPLL1_NFRAC, 0x0);
  
                REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 -                            AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
 +                            AR_CH0_BB_DPLL2_OUTDIV, 0x1);
                REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 -                            AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
 +                            AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 +                            AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
  
 +              /* program BB PLL phase_shift to 0x6 */
                REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
 -                            AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
 -              REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
 +                            AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
 +
 +              REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
 +                            AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
 +              udelay(1000);
 +      } else if (AR_SREV_9340(ah)) {
 +              u32 regval, pll2_divint, pll2_divfrac, refdiv;
 +
 +              REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
 +              udelay(1000);
 +
 +              REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
 +              udelay(100);
 +
 +              if (ah->is_clk_25mhz) {
 +                      pll2_divint = 0x54;
 +                      pll2_divfrac = 0x1eb85;
 +                      refdiv = 3;
 +              } else {
 +                      pll2_divint = 88;
 +                      pll2_divfrac = 0;
 +                      refdiv = 5;
 +              }
 +
 +              regval = REG_READ(ah, AR_PHY_PLL_MODE);
 +              regval |= (0x1 << 16);
 +              REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
 +              udelay(100);
 +
 +              REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) |
 +                        (pll2_divint << 18) | pll2_divfrac);
 +              udelay(100);
 +
 +              regval = REG_READ(ah, AR_PHY_PLL_MODE);
 +              regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) |
 +                       (0x4 << 26) | (0x18 << 19);
 +              REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
 +              REG_WRITE(ah, AR_PHY_PLL_MODE,
 +                        REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
                udelay(1000);
        }
  
  
        REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
  
 +      if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
 +              udelay(1000);
 +
        /* Switch the core clock for ar9271 to 117Mhz */
        if (AR_SREV_9271(ah)) {
                udelay(500);
        udelay(RTC_PLL_SETTLE_DELAY);
  
        REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
 +
 +      if (AR_SREV_9340(ah)) {
 +              if (ah->is_clk_25mhz) {
 +                      REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
 +                      REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
 +                      REG_WRITE(ah,  AR_SLP32_INC, 0x0001e7ae);
 +              } else {
 +                      REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
 +                      REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
 +                      REG_WRITE(ah,  AR_SLP32_INC, 0x0001e800);
 +              }
 +              udelay(100);
 +      }
  }
  
  static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                                          enum nl80211_iftype opmode)
  {
 +      u32 sync_default = AR_INTR_SYNC_DEFAULT;
        u32 imr_reg = AR_IMR_TXERR |
                AR_IMR_TXURN |
                AR_IMR_RXERR |
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
  
 +      if (AR_SREV_9340(ah))
 +              sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
 +
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                imr_reg |= AR_IMR_RXOK_HP;
                if (ah->config.rx_intr_mitigation)
  
        if (!AR_SREV_9100(ah)) {
                REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
 -              REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
 +              REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
                REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
        }
  
@@@ -893,7 -830,8 +893,7 @@@ void ath9k_hw_init_global_settings(stru
                ah->misc_mode);
  
        if (ah->misc_mode != 0)
 -              REG_WRITE(ah, AR_PCU_MISC,
 -                        REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
 +              REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
  
        if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
                sifstime = 16;
@@@ -961,19 -899,23 +961,19 @@@ u32 ath9k_regd_get_ctl(struct ath_regul
  static inline void ath9k_hw_set_dma(struct ath_hw *ah)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 -      u32 regval;
  
        ENABLE_REGWRITE_BUFFER(ah);
  
        /*
         * set AHB_MODE not to do cacheline prefetches
        */
 -      if (!AR_SREV_9300_20_OR_LATER(ah)) {
 -              regval = REG_READ(ah, AR_AHB_MODE);
 -              REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
 -      }
 +      if (!AR_SREV_9300_20_OR_LATER(ah))
 +              REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
  
        /*
         * let mac dma reads be in 128 byte chunks
         */
 -      regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
 -      REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 +      REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK);
  
        REGWRITE_BUFFER_FLUSH(ah);
  
        /*
         * let mac dma writes be in 128 byte chunks
         */
 -      regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
 -      REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
 +      REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK);
  
        /*
         * Setup receive FIFO threshold to hold off TX activities
  
  static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
  {
 -      u32 val;
 +      u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
 +      u32 set = AR_STA_ID1_KSRCH_MODE;
  
 -      val = REG_READ(ah, AR_STA_ID1);
 -      val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
        switch (opmode) {
 -      case NL80211_IFTYPE_AP:
 -              REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
 -                        | AR_STA_ID1_KSRCH_MODE);
 -              REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
 -              break;
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
 -              REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
 -                        | AR_STA_ID1_KSRCH_MODE);
 +              set |= AR_STA_ID1_ADHOC;
                REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
                break;
 +      case NL80211_IFTYPE_AP:
 +              set |= AR_STA_ID1_STA_AP;
 +              /* fall through */
        case NL80211_IFTYPE_STATION:
 -              REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
 +              REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
                break;
        default:
 -              if (ah->is_monitoring)
 -                      REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
 +              if (!ah->is_monitoring)
 +                      set = 0;
                break;
        }
 +      REG_RMW(ah, AR_STA_ID1, set, mask);
  }
  
  void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
@@@ -1075,8 -1021,10 +1075,8 @@@ static bool ath9k_hw_set_reset(struct a
        u32 tmpReg;
  
        if (AR_SREV_9100(ah)) {
 -              u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK);
 -              val &= ~AR_RTC_DERIVED_CLK_PERIOD;
 -              val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
 -              REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
 +              REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK,
 +                            AR_RTC_DERIVED_CLK_PERIOD, 1);
                (void)REG_READ(ah, AR_RTC_DERIVED_CLK);
        }
  
@@@ -1264,20 -1212,6 +1264,20 @@@ static bool ath9k_hw_channel_change(str
        return true;
  }
  
 +static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
 +{
 +      u32 gpio_mask = ah->gpio_mask;
 +      int i;
 +
 +      for (i = 0; gpio_mask; i++, gpio_mask >>= 1) {
 +              if (!(gpio_mask & 1))
 +                      continue;
 +
 +              ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 +              ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
 +      }
 +}
 +
  bool ath9k_hw_check_alive(struct ath_hw *ah)
  {
        int count = 50;
@@@ -1320,15 -1254,6 +1320,6 @@@ int ath9k_hw_reset(struct ath_hw *ah, s
        ah->txchainmask = common->tx_chainmask;
        ah->rxchainmask = common->rx_chainmask;
  
-       if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) {
-               ath9k_hw_abortpcurecv(ah);
-               if (!ath9k_hw_stopdmarecv(ah)) {
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "Failed to stop receive dma\n");
-                       bChannelChange = false;
-               }
-       }
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
  
        REGWRITE_BUFFER_FLUSH(ah);
  
        ah->intr_txqs = 0;
 -      for (i = 0; i < ah->caps.total_queues; i++)
 +      for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                ath9k_hw_resettxqueue(ah, i);
  
        ath9k_hw_init_interrupt_masks(ah, ah->opmode);
                ar9002_hw_enable_wep_aggregation(ah);
        }
  
 -      REG_WRITE(ah, AR_STA_ID1,
 -                REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
 +      REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
  
        ath9k_hw_set_dma(ah);
  
                                REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
                }
  #ifdef __BIG_ENDIAN
 -                else
 +              else if (AR_SREV_9340(ah))
 +                      REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
 +              else
                        REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
  #endif
        }
        if (AR_SREV_9300_20_OR_LATER(ah))
                ar9003_hw_bb_watchdog_config(ah);
  
 +      ath9k_hw_apply_gpio_override(ah);
 +
        return 0;
  }
  EXPORT_SYMBOL(ath9k_hw_reset);
@@@ -1748,15 -1670,21 +1739,15 @@@ void ath9k_hw_beaconinit(struct ath_hw 
        case NL80211_IFTYPE_MESH_POINT:
                REG_SET_BIT(ah, AR_TXCFG,
                            AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
 -              REG_WRITE(ah, AR_NEXT_NDP_TIMER,
 -                        TU_TO_USEC(next_beacon +
 -                                   (ah->atim_window ? ah->
 -                                    atim_window : 1)));
 +              REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
 +                        TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
                flags |= AR_NDP_TIMER_EN;
        case NL80211_IFTYPE_AP:
 -              REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
 -              REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
 -                        TU_TO_USEC(next_beacon -
 -                                   ah->config.
 -                                   dma_beacon_response_time));
 -              REG_WRITE(ah, AR_NEXT_SWBA,
 -                        TU_TO_USEC(next_beacon -
 -                                   ah->config.
 -                                   sw_beacon_response_time));
 +              REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
 +              REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
 +                        TU_TO_USEC(ah->config.dma_beacon_response_time));
 +              REG_WRITE(ah, AR_NEXT_SWBA, next_beacon -
 +                        TU_TO_USEC(ah->config.sw_beacon_response_time));
                flags |=
                        AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
                break;
                break;
        }
  
 -      REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
 -      REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
 -      REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
 -      REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
 +      REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
 +      REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
 +      REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
 +      REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
  
        REGWRITE_BUFFER_FLUSH(ah);
  
 -      beacon_period &= ~ATH9K_BEACON_ENA;
 -      if (beacon_period & ATH9K_BEACON_RESET_TSF) {
 -              ath9k_hw_reset_tsf(ah);
 -      }
 -
        REG_SET_BIT(ah, AR_TIMER_MODE, flags);
  }
  EXPORT_SYMBOL(ath9k_hw_beaconinit);
@@@ -1862,7 -1795,7 +1853,7 @@@ int ath9k_hw_fill_cap_info(struct ath_h
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
  
 -      u16 capField = 0, eeval;
 +      u16 eeval;
        u8 ant_div_ctl1, tx_chainmask, rx_chainmask;
  
        eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
                eeval |= AR9285_RDEXT_DEFAULT;
        regulatory->current_rd_ext = eeval;
  
 -      capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
 -
        if (ah->opmode != NL80211_IFTYPE_AP &&
            ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
                if (regulatory->current_rd == 0x64 ||
            !(AR_SREV_9271(ah)))
                /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
                pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
 +      else if (AR_SREV_9100(ah))
 +              pCap->rx_chainmask = 0x7;
        else
                /* Use rx_chainmask from EEPROM. */
                pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
        if (AR_SREV_9300_20_OR_LATER(ah))
                ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH;
  
 -      pCap->low_2ghz_chan = 2312;
 -      pCap->high_2ghz_chan = 2732;
 -
 -      pCap->low_5ghz_chan = 4920;
 -      pCap->high_5ghz_chan = 6100;
 -
        common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
  
 -      if (ah->config.ht_enable)
 +      if (ah->hw_version.devid != AR2427_DEVID_PCIE)
                pCap->hw_caps |= ATH9K_HW_CAP_HT;
        else
                pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
  
 -      if (capField & AR_EEPROM_EEPCAP_MAXQCU)
 -              pCap->total_queues =
 -                      MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
 -      else
 -              pCap->total_queues = ATH9K_NUM_TX_QUEUES;
 -
 -      if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
 -              pCap->keycache_size =
 -                      1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
 -      else
 -              pCap->keycache_size = AR_KEYTABLE_SIZE;
 -
 -      if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
 -              pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
 -      else
 -              pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
 -
        if (AR_SREV_9271(ah))
                pCap->num_gpio_pins = AR9271_NUM_GPIO;
        else if (AR_DEVID_7010(ah))
                pCap->rts_aggr_limit = (8 * 1024);
        }
  
 -      pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 -
  #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
        if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
        else
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
  
 -      if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
 -              pCap->reg_cap =
 -                      AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
 -                      AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
 -                      AR_EEPROM_EEREGCAP_EN_KK_U2 |
 -                      AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
 -      } else {
 -              pCap->reg_cap =
 -                      AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
 -                      AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
 -      }
 -
 -      /* Advertise midband for AR5416 with FCC midband set in eeprom */
 -      if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) &&
 -          AR_SREV_5416(ah))
 -              pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
 -
        if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
                btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
                btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
@@@ -2211,9 -2186,11 +2202,9 @@@ void ath9k_hw_setrxfilter(struct ath_h
        REG_WRITE(ah, AR_PHY_ERR, phybits);
  
        if (phybits)
 -              REG_WRITE(ah, AR_RXCFG,
 -                        REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
 +              REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
        else
 -              REG_WRITE(ah, AR_RXCFG,
 -                        REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
 +              REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
  
        REGWRITE_BUFFER_FLUSH(ah);
  }
@@@ -2389,11 -2366,10 +2380,11 @@@ static u32 rightmost_index(struct ath_g
        return timer_table->gen_timer_index[b];
  }
  
 -static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
 +u32 ath9k_hw_gettsf32(struct ath_hw *ah)
  {
        return REG_READ(ah, AR_TSF_L32);
  }
 +EXPORT_SYMBOL(ath9k_hw_gettsf32);
  
  struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
                                          void (*trigger)(void *),
@@@ -2426,11 -2402,11 +2417,11 @@@ EXPORT_SYMBOL(ath_gen_timer_alloc)
  
  void ath9k_hw_gen_timer_start(struct ath_hw *ah,
                              struct ath_gen_timer *timer,
 -                            u32 timer_next,
 +                            u32 trig_timeout,
                              u32 timer_period)
  {
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
 -      u32 tsf;
 +      u32 tsf, timer_next;
  
        BUG_ON(!timer_period);
  
  
        tsf = ath9k_hw_gettsf32(ah);
  
 +      timer_next = tsf + trig_timeout;
 +
        ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
                "current tsf %x period %x timer_next %x\n",
                tsf, timer_period, timer_next);
  
 -      /*
 -       * Pull timer_next forward if the current TSF already passed it
 -       * because of software latency
 -       */
 -      if (timer_next < tsf)
 -              timer_next = tsf + timer_period;
 -
        /*
         * Program generic timer registers
         */
@@@ -209,8 -209,15 +209,8 @@@ bool ath9k_hw_set_txq_props(struct ath_
  {
        u32 cw;
        struct ath_common *common = ath9k_hw_common(ah);
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath9k_tx_queue_info *qi;
  
 -      if (q >= pCap->total_queues) {
 -              ath_dbg(common, ATH_DBG_QUEUE,
 -                      "Set TXQ properties, invalid queue: %u\n", q);
 -              return false;
 -      }
 -
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
                ath_dbg(common, ATH_DBG_QUEUE,
@@@ -273,8 -280,15 +273,8 @@@ bool ath9k_hw_get_txq_props(struct ath_
                            struct ath9k_tx_queue_info *qinfo)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath9k_tx_queue_info *qi;
  
 -      if (q >= pCap->total_queues) {
 -              ath_dbg(common, ATH_DBG_QUEUE,
 -                      "Get TXQ properties, invalid queue: %u\n", q);
 -              return false;
 -      }
 -
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
                ath_dbg(common, ATH_DBG_QUEUE,
@@@ -306,27 -320,28 +306,27 @@@ int ath9k_hw_setuptxqueue(struct ath_h
  {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_tx_queue_info *qi;
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
        int q;
  
        switch (type) {
        case ATH9K_TX_QUEUE_BEACON:
 -              q = pCap->total_queues - 1;
 +              q = ATH9K_NUM_TX_QUEUES - 1;
                break;
        case ATH9K_TX_QUEUE_CAB:
 -              q = pCap->total_queues - 2;
 +              q = ATH9K_NUM_TX_QUEUES - 2;
                break;
        case ATH9K_TX_QUEUE_PSPOLL:
                q = 1;
                break;
        case ATH9K_TX_QUEUE_UAPSD:
 -              q = pCap->total_queues - 3;
 +              q = ATH9K_NUM_TX_QUEUES - 3;
                break;
        case ATH9K_TX_QUEUE_DATA:
 -              for (q = 0; q < pCap->total_queues; q++)
 +              for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
                        if (ah->txq[q].tqi_type ==
                            ATH9K_TX_QUEUE_INACTIVE)
                                break;
 -              if (q == pCap->total_queues) {
 +              if (q == ATH9K_NUM_TX_QUEUES) {
                        ath_err(common, "No available TX queue\n");
                        return -1;
                }
@@@ -367,9 -382,15 +367,9 @@@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue)
  
  bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
  {
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_tx_queue_info *qi;
  
 -      if (q >= pCap->total_queues) {
 -              ath_dbg(common, ATH_DBG_QUEUE,
 -                      "Release TXQ, invalid queue: %u\n", q);
 -              return false;
 -      }
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
                ath_dbg(common, ATH_DBG_QUEUE,
@@@ -393,11 -414,18 +393,11 @@@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue)
  
  bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
  {
 -      struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
        struct ath9k_tx_queue_info *qi;
        u32 cwMin, chanCwMin, value;
  
 -      if (q >= pCap->total_queues) {
 -              ath_dbg(common, ATH_DBG_QUEUE,
 -                      "Reset TXQ, invalid queue: %u\n", q);
 -              return false;
 -      }
 -
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
                ath_dbg(common, ATH_DBG_QUEUE,
                REG_WRITE(ah, AR_QCBRCFG(q),
                          SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
                          SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
 -              REG_WRITE(ah, AR_QMISC(q),
 -                        REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
 -                        (qi->tqi_cbrOverflowLimit ?
 -                         AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
 +              REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
 +                          (qi->tqi_cbrOverflowLimit ?
 +                           AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
        }
        if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
                REG_WRITE(ah, AR_QRDYTIMECFG(q),
                  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
  
        if (qi->tqi_burstTime
 -          && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
 -              REG_WRITE(ah, AR_QMISC(q),
 -                        REG_READ(ah, AR_QMISC(q)) |
 -                        AR_Q_MISC_RDYTIME_EXP_POLICY);
 +          && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
 +              REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
  
 -      }
 -
 -      if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
 -              REG_WRITE(ah, AR_DMISC(q),
 -                        REG_READ(ah, AR_DMISC(q)) |
 -                        AR_D_MISC_POST_FR_BKOFF_DIS);
 -      }
 +      if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
 +              REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
  
        REGWRITE_BUFFER_FLUSH(ah);
  
 -      if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
 -              REG_WRITE(ah, AR_DMISC(q),
 -                        REG_READ(ah, AR_DMISC(q)) |
 -                        AR_D_MISC_FRAG_BKOFF_EN);
 -      }
 +      if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
 +              REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
 +
        switch (qi->tqi_type) {
        case ATH9K_TX_QUEUE_BEACON:
                ENABLE_REGWRITE_BUFFER(ah);
  
 -              REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
 -                        | AR_Q_MISC_FSP_DBA_GATED
 -                        | AR_Q_MISC_BEACON_USE
 -                        | AR_Q_MISC_CBR_INCR_DIS1);
 +              REG_SET_BIT(ah, AR_QMISC(q),
 +                          AR_Q_MISC_FSP_DBA_GATED
 +                          | AR_Q_MISC_BEACON_USE
 +                          | AR_Q_MISC_CBR_INCR_DIS1);
  
 -              REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
 -                        | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
 +              REG_SET_BIT(ah, AR_DMISC(q),
 +                          (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
                             AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
 -                        | AR_D_MISC_BEACON_USE
 -                        | AR_D_MISC_POST_FR_BKOFF_DIS);
 +                          | AR_D_MISC_BEACON_USE
 +                          | AR_D_MISC_POST_FR_BKOFF_DIS);
  
                REGWRITE_BUFFER_FLUSH(ah);
  
        case ATH9K_TX_QUEUE_CAB:
                ENABLE_REGWRITE_BUFFER(ah);
  
 -              REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
 -                        | AR_Q_MISC_FSP_DBA_GATED
 -                        | AR_Q_MISC_CBR_INCR_DIS1
 -                        | AR_Q_MISC_CBR_INCR_DIS0);
 +              REG_SET_BIT(ah, AR_QMISC(q),
 +                          AR_Q_MISC_FSP_DBA_GATED
 +                          | AR_Q_MISC_CBR_INCR_DIS1
 +                          | AR_Q_MISC_CBR_INCR_DIS0);
                value = (qi->tqi_readyTime -
                         (ah->config.sw_beacon_response_time -
                          ah->config.dma_beacon_response_time) -
                         ah->config.additional_swba_backoff) * 1024;
                REG_WRITE(ah, AR_QRDYTIMECFG(q),
                          value | AR_Q_RDYTIMECFG_EN);
 -              REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
 -                        | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
 +              REG_SET_BIT(ah, AR_DMISC(q),
 +                          (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
                             AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
  
                REGWRITE_BUFFER_FLUSH(ah);
  
                break;
        case ATH9K_TX_QUEUE_PSPOLL:
 -              REG_WRITE(ah, AR_QMISC(q),
 -                        REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
 +              REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1);
                break;
        case ATH9K_TX_QUEUE_UAPSD:
 -              REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
 -                        AR_D_MISC_POST_FR_BKOFF_DIS);
 +              REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
                break;
        default:
                break;
        }
  
        if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
 -              REG_WRITE(ah, AR_DMISC(q),
 -                        REG_READ(ah, AR_DMISC(q)) |
 -                        SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
 -                           AR_D_MISC_ARB_LOCKOUT_CNTRL) |
 -                        AR_D_MISC_POST_FR_BKOFF_DIS);
 +              REG_SET_BIT(ah, AR_DMISC(q),
 +                          SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
 +                             AR_D_MISC_ARB_LOCKOUT_CNTRL) |
 +                          AR_D_MISC_POST_FR_BKOFF_DIS);
        }
  
        if (AR_SREV_9300_20_OR_LATER(ah))
@@@ -710,32 -751,53 +710,51 @@@ void ath9k_hw_abortpcurecv(struct ath_h
  }
  EXPORT_SYMBOL(ath9k_hw_abortpcurecv);
  
- bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
+ bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
  {
  #define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
 -#define AH_RX_TIME_QUANTUM     100     /* usec */
        struct ath_common *common = ath9k_hw_common(ah);
+       u32 mac_status, last_mac_status = 0;
        int i;
  
+       /* Enable access to the DMA observation bus */
+       REG_WRITE(ah, AR_MACMISC,
+                 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+                  (AR_MACMISC_MISC_OBS_BUS_1 <<
+                   AR_MACMISC_MISC_OBS_BUS_MSB_S)));
        REG_WRITE(ah, AR_CR, AR_CR_RXD);
  
        /* Wait for rx enable bit to go low */
        for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
                if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
                        break;
+               if (!AR_SREV_9300_20_OR_LATER(ah)) {
+                       mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0;
+                       if (mac_status == 0x1c0 && mac_status == last_mac_status) {
+                               *reset = true;
+                               break;
+                       }
+                       last_mac_status = mac_status;
+               }
                udelay(AH_TIME_QUANTUM);
        }
  
        if (i == 0) {
                ath_err(common,
-                       "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+                       "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
                        AH_RX_STOP_DMA_TIMEOUT / 1000,
                        REG_READ(ah, AR_CR),
-                       REG_READ(ah, AR_DIAG_SW));
+                       REG_READ(ah, AR_DIAG_SW),
+                       REG_READ(ah, AR_DMADBG_7));
                return false;
        } else {
                return true;
        }
  
 -#undef AH_RX_TIME_QUANTUM
  #undef AH_RX_STOP_DMA_TIMEOUT
  }
  EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
@@@ -793,14 -855,10 +812,14 @@@ EXPORT_SYMBOL(ath9k_hw_disable_interrup
  void ath9k_hw_enable_interrupts(struct ath_hw *ah)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 +      u32 sync_default = AR_INTR_SYNC_DEFAULT;
  
        if (!(ah->imask & ATH9K_INT_GLOBAL))
                return;
  
 +      if (AR_SREV_9340(ah))
 +              sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
 +
        ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
        REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
        if (!AR_SREV_9100(ah)) {
                REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
  
  
 -              REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
 -                        AR_INTR_SYNC_DEFAULT);
 -              REG_WRITE(ah, AR_INTR_SYNC_MASK,
 -                        AR_INTR_SYNC_DEFAULT);
 +              REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
 +              REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
        }
        ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
                REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
@@@ -239,6 -239,7 +239,6 @@@ struct ath_desc 
        void *ds_vdata;
  } __packed __aligned(4);
  
 -#define ATH9K_TXDESC_CLRDMASK         0x0001
  #define ATH9K_TXDESC_NOACK            0x0002
  #define ATH9K_TXDESC_RTSENA           0x0004
  #define ATH9K_TXDESC_CTSENA           0x0008
@@@ -694,7 -695,7 +694,7 @@@ bool ath9k_hw_setrxabort(struct ath_hw 
  void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
  void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
  void ath9k_hw_abortpcurecv(struct ath_hw *ah);
- bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
+ bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset);
  int ath9k_hw_beaconq_setup(struct ath_hw *ah);
  
  /* Interrupt Handling */
@@@ -299,7 -299,7 +299,7 @@@ int ath_set_channel(struct ath_softc *s
  
        if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
                if (sc->sc_flags & SC_OP_BEACONS)
 -                      ath_beacon_config(sc, NULL);
 +                      ath_set_beacon(sc);
                ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
                ath_start_ani(common);
@@@ -624,43 -624,6 +624,43 @@@ out
        ath9k_ps_restore(sc);
  }
  
 +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
 +{
 +      static int count;
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +
 +      if (pll_sqsum >= 0x40000) {
 +              count++;
 +              if (count == 3) {
 +                      /* Rx is hung for more than 500ms. Reset it */
 +                      ath_dbg(common, ATH_DBG_RESET,
 +                              "Possible RX hang, resetting");
 +                      ath_reset(sc, true);
 +                      count = 0;
 +              }
 +      } else
 +              count = 0;
 +}
 +
 +void ath_hw_pll_work(struct work_struct *work)
 +{
 +      struct ath_softc *sc = container_of(work, struct ath_softc,
 +                                          hw_pll_work.work);
 +      u32 pll_sqsum;
 +
 +      if (AR_SREV_9485(sc->sc_ah)) {
 +
 +              ath9k_ps_wakeup(sc);
 +              pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
 +              ath9k_ps_restore(sc);
 +
 +              ath_hw_pll_rx_hang_check(sc, pll_sqsum);
 +
 +              ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
 +      }
 +}
 +
 +
  void ath9k_tasklet(unsigned long data)
  {
        struct ath_softc *sc = (struct ath_softc *)data;
@@@ -865,6 -828,48 +865,6 @@@ chip_reset
  #undef SCHED_INTR
  }
  
 -static void ath9k_bss_assoc_info(struct ath_softc *sc,
 -                               struct ieee80211_hw *hw,
 -                               struct ieee80211_vif *vif,
 -                               struct ieee80211_bss_conf *bss_conf)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -
 -      if (bss_conf->assoc) {
 -              ath_dbg(common, ATH_DBG_CONFIG,
 -                      "Bss Info ASSOC %d, bssid: %pM\n",
 -                      bss_conf->aid, common->curbssid);
 -
 -              /* New association, store aid */
 -              common->curaid = bss_conf->aid;
 -              ath9k_hw_write_associd(ah);
 -
 -              /*
 -               * Request a re-configuration of Beacon related timers
 -               * on the receipt of the first Beacon frame (i.e.,
 -               * after time sync with the AP).
 -               */
 -              sc->ps_flags |= PS_BEACON_SYNC;
 -
 -              /* Configure the beacon */
 -              ath_beacon_config(sc, vif);
 -
 -              /* Reset rssi stats */
 -              sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 -              sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 -
 -              sc->sc_flags |= SC_OP_ANI_RUN;
 -              ath_start_ani(common);
 -      } else {
 -              ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
 -              common->curaid = 0;
 -              /* Stop ANI */
 -              sc->sc_flags &= ~SC_OP_ANI_RUN;
 -              del_timer_sync(&common->ani.timer);
 -      }
 -}
 -
  void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
  {
        struct ath_hw *ah = sc->sc_ah;
                goto out;
        }
        if (sc->sc_flags & SC_OP_BEACONS)
 -              ath_beacon_config(sc, NULL);    /* restart beacons */
 +              ath_set_beacon(sc);     /* restart beacons */
  
        /* Re-Enable  interrupts */
        ath9k_hw_set_interrupts(ah, ah->imask);
@@@ -1001,7 -1006,7 +1001,7 @@@ int ath_reset(struct ath_softc *sc, boo
                               sc->config.txpowlimit, &sc->curtxpow);
  
        if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
 -              ath_beacon_config(sc, NULL);    /* restart beacons */
 +              ath_set_beacon(sc);     /* restart beacons */
  
        ath9k_hw_set_interrupts(ah, ah->imask);
  
@@@ -1371,7 -1376,6 +1371,6 @@@ static void ath9k_calculate_summary_sta
  
        ath9k_calculate_iter_data(hw, vif, &iter_data);
  
-       ath9k_ps_wakeup(sc);
        /* Set BSSID mask. */
        memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
        ath_hw_setbssidmask(common);
        }
  
        ath9k_hw_set_interrupts(ah, ah->imask);
-       ath9k_ps_restore(sc);
  
        /* Set up ANI */
        if ((iter_data.naps + iter_data.nadhocs) > 0) {
@@@ -1449,8 -1452,10 +1447,9 @@@ static int ath9k_add_interface(struct i
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 -      struct ath_vif *avp = (void *)vif->drv_priv;
        int ret = 0;
  
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
  
        switch (vif->type) {
                }
        }
  
 -      if ((vif->type == NL80211_IFTYPE_ADHOC) &&
 -          sc->nvifs > 0) {
 +      if ((ah->opmode == NL80211_IFTYPE_ADHOC) ||
 +          ((vif->type == NL80211_IFTYPE_ADHOC) &&
 +           sc->nvifs > 0)) {
                ath_err(common, "Cannot create ADHOC interface when other"
                        " interfaces already exist.\n");
                ret = -EINVAL;
        ath_dbg(common, ATH_DBG_CONFIG,
                "Attach a VIF of type: %d\n", vif->type);
  
 -      /* Set the VIF opmode */
 -      avp->av_opmode = vif->type;
 -      avp->av_bslot = -1;
 -
        sc->nvifs++;
  
        ath9k_do_vif_add_setup(hw, vif);
  out:
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
        return ret;
  }
  
@@@ -1508,6 -1517,7 +1508,7 @@@ static int ath9k_change_interface(struc
  
        ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
        mutex_lock(&sc->mutex);
+       ath9k_ps_wakeup(sc);
  
        /* See if new interface type is valid. */
        if ((new_type == NL80211_IFTYPE_ADHOC) &&
  
        ath9k_do_vif_add_setup(hw, vif);
  out:
+       ath9k_ps_restore(sc);
        mutex_unlock(&sc->mutex);
        return ret;
  }
@@@ -1549,6 -1560,7 +1551,7 @@@ static void ath9k_remove_interface(stru
  
        ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
  
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
  
        sc->nvifs--;
        ath9k_calculate_summary_state(hw, NULL);
  
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
  }
  
  static void ath9k_enable_ps(struct ath_softc *sc)
@@@ -1769,63 -1782,23 +1773,63 @@@ static int ath9k_sta_add(struct ieee802
                         struct ieee80211_sta *sta)
  {
        struct ath_softc *sc = hw->priv;
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ath_node *an = (struct ath_node *) sta->drv_priv;
 +      struct ieee80211_key_conf ps_key = { };
  
        ath_node_attach(sc, sta);
 +      an->ps_key = ath_key_config(common, vif, sta, &ps_key);
  
        return 0;
  }
  
 +static void ath9k_del_ps_key(struct ath_softc *sc,
 +                           struct ieee80211_vif *vif,
 +                           struct ieee80211_sta *sta)
 +{
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ath_node *an = (struct ath_node *) sta->drv_priv;
 +      struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
 +
 +      if (!an->ps_key)
 +          return;
 +
 +      ath_key_delete(common, &ps_key);
 +}
 +
  static int ath9k_sta_remove(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta)
  {
        struct ath_softc *sc = hw->priv;
  
 +      ath9k_del_ps_key(sc, vif, sta);
        ath_node_detach(sc, sta);
  
        return 0;
  }
  
 +static void ath9k_sta_notify(struct ieee80211_hw *hw,
 +                       struct ieee80211_vif *vif,
 +                       enum sta_notify_cmd cmd,
 +                       struct ieee80211_sta *sta)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_node *an = (struct ath_node *) sta->drv_priv;
 +
 +      switch (cmd) {
 +      case STA_NOTIFY_SLEEP:
 +              an->sleeping = true;
 +              if (ath_tx_aggr_sleep(sc, an))
 +                      ieee80211_sta_set_tim(sta);
 +              break;
 +      case STA_NOTIFY_AWAKE:
 +              an->sleeping = false;
 +              ath_tx_aggr_wakeup(sc, an);
 +              break;
 +      }
 +}
 +
  static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
                         const struct ieee80211_tx_queue_params *params)
  {
  
        txq = sc->tx.txq_map[queue];
  
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
  
        memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
                        ath_beaconq_config(sc);
  
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
  
        return ret;
  }
@@@ -1880,29 -1855,12 +1886,29 @@@ static int ath9k_set_key(struct ieee802
        if (ath9k_modparam_nohwcrypt)
                return -ENOSPC;
  
 +      if (vif->type == NL80211_IFTYPE_ADHOC &&
 +          (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
 +           key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
 +          !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
 +              /*
 +               * For now, disable hw crypto for the RSN IBSS group keys. This
 +               * could be optimized in the future to use a modified key cache
 +               * design to support per-STA RX GTK, but until that gets
 +               * implemented, use of software crypto for group addressed
 +               * frames is a acceptable to allow RSN IBSS to be used.
 +               */
 +              return -EOPNOTSUPP;
 +      }
 +
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
        ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
  
        switch (cmd) {
        case SET_KEY:
 +              if (sta)
 +                      ath9k_del_ps_key(sc, vif, sta);
 +
                ret = ath_key_config(common, vif, sta, key);
                if (ret >= 0) {
                        key->hw_key_idx = ret;
  
        return ret;
  }
 +static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 +{
 +      struct ath_softc *sc = data;
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 +      struct ath_vif *avp = (void *)vif->drv_priv;
 +
 +      switch (sc->sc_ah->opmode) {
 +      case NL80211_IFTYPE_ADHOC:
 +              /* There can be only one vif available */
 +              memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
 +              common->curaid = bss_conf->aid;
 +              ath9k_hw_write_associd(sc->sc_ah);
 +              /* configure beacon */
 +              if (bss_conf->enable_beacon)
 +                      ath_beacon_config(sc, vif);
 +              break;
 +      case NL80211_IFTYPE_STATION:
 +              /*
 +               * Skip iteration if primary station vif's bss info
 +               * was not changed
 +               */
 +              if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
 +                      break;
 +
 +              if (bss_conf->assoc) {
 +                      sc->sc_flags |= SC_OP_PRIM_STA_VIF;
 +                      avp->primary_sta_vif = true;
 +                      memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
 +                      common->curaid = bss_conf->aid;
 +                      ath9k_hw_write_associd(sc->sc_ah);
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "Bss Info ASSOC %d, bssid: %pM\n",
 +                              bss_conf->aid, common->curbssid);
 +                      ath_beacon_config(sc, vif);
 +                      /* Reset rssi stats */
 +                      sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
 +                      sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 +
 +                      sc->sc_flags |= SC_OP_ANI_RUN;
 +                      ath_start_ani(common);
 +              }
 +              break;
 +      default:
 +              break;
 +      }
 +}
 +
 +static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
 +{
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 +      struct ath_vif *avp = (void *)vif->drv_priv;
 +
 +      /* Reconfigure bss info */
 +      if (avp->primary_sta_vif && !bss_conf->assoc) {
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Bss Info DISASSOC %d, bssid %pM\n",
 +                      common->curaid, common->curbssid);
 +              sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
 +              avp->primary_sta_vif = false;
 +              memset(common->curbssid, 0, ETH_ALEN);
 +              common->curaid = 0;
 +      }
 +
 +      ieee80211_iterate_active_interfaces_atomic(
 +                      sc->hw, ath9k_bss_iter, sc);
 +
 +      /*
 +       * None of station vifs are associated.
 +       * Clear bssid & aid
 +       */
 +      if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
 +          !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
 +              ath9k_hw_write_associd(sc->sc_ah);
 +              /* Stop ANI */
 +              sc->sc_flags &= ~SC_OP_ANI_RUN;
 +              del_timer_sync(&common->ani.timer);
 +      }
 +}
  
  static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
                                   u32 changed)
  {
        struct ath_softc *sc = hw->priv;
 -      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        int slottime;
        int error;
  
+       ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
  
        if (changed & BSS_CHANGED_BSSID) {
 -              /* Set BSSID */
 -              memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
 -              memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
 -              common->curaid = 0;
 -              ath9k_hw_write_associd(ah);
 +              ath9k_config_bss(sc, vif);
  
                /* Set aggregation protection mode parameters */
                sc->config.ath_aggr_prot = 0;
  
                ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
                        common->curbssid, common->curaid);
 -
 -              /* need to reconfigure the beacon */
 -              sc->sc_flags &= ~SC_OP_BEACONS ;
        }
  
        /* Enable transmission of beacons (AP, IBSS, MESH) */
        }
  
        if (changed & BSS_CHANGED_BEACON_INT) {
 -              cur_conf->beacon_interval = bss_conf->beacon_int;
                /*
                 * In case of AP mode, the HW TSF has to be reset
                 * when the beacon interval changes.
                        if (!error)
                                ath_beacon_config(sc, vif);
                        ath9k_set_beaconing_status(sc, true);
 -              } else {
 +              } else
                        ath_beacon_config(sc, vif);
 -              }
        }
  
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
                        sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
        }
  
 -      if (changed & BSS_CHANGED_ASSOC) {
 -              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 -                      bss_conf->assoc);
 -              ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
 -      }
 -
        mutex_unlock(&sc->mutex);
+       ath9k_ps_restore(sc);
  }
  
  static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
@@@ -2248,7 -2144,9 +2256,7 @@@ static void ath9k_flush(struct ieee8021
        int timeout = 200; /* ms */
        int i, j;
  
 -      ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 -
        cancel_delayed_work_sync(&sc->tx_complete_work);
  
        if (drop)
                    goto out;
        }
  
 +      ath9k_ps_wakeup(sc);
        if (!ath_drain_all_txq(sc, false))
                ath_reset(sc, false);
 -
 +      ath9k_ps_restore(sc);
        ieee80211_wake_queues(hw);
  
  out:
        ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
        mutex_unlock(&sc->mutex);
 -      ath9k_ps_restore(sc);
 +}
 +
 +static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      int i;
 +
 +      for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 +              if (!ATH_TXQ_SETUP(sc, i))
 +                      continue;
 +
 +              if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
 +                      return true;
 +      }
 +      return false;
  }
  
  struct ieee80211_ops ath9k_ops = {
        .configure_filter   = ath9k_configure_filter,
        .sta_add            = ath9k_sta_add,
        .sta_remove         = ath9k_sta_remove,
 +      .sta_notify         = ath9k_sta_notify,
        .conf_tx            = ath9k_conf_tx,
        .bss_info_changed   = ath9k_bss_info_changed,
        .set_key            = ath9k_set_key,
        .rfkill_poll        = ath9k_rfkill_poll_state,
        .set_coverage_class = ath9k_set_coverage_class,
        .flush              = ath9k_flush,
 +      .tx_frames_pending  = ath9k_tx_frames_pending,
  };
@@@ -75,6 -75,7 +75,6 @@@ static void ath_rx_buf_link(struct ath_
                *sc->rx.rxlink = bf->bf_daddr;
  
        sc->rx.rxlink = &ds->ds_link;
 -      ath9k_hw_rxena(ah);
  }
  
  static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
@@@ -425,7 -426,9 +425,7 @@@ u32 ath_calcrxfilter(struct ath_softc *
        else
                rfilt |= ATH9K_RX_FILTER_BEACON;
  
 -      if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) ||
 -          AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
 -          (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
 +      if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
            (sc->rx.rxfilter & FIF_PSPOLL))
                rfilt |= ATH9K_RX_FILTER_PSPOLL;
  
@@@ -483,12 -486,12 +483,12 @@@ start_recv
  bool ath_stoprecv(struct ath_softc *sc)
  {
        struct ath_hw *ah = sc->sc_ah;
-       bool stopped;
+       bool stopped, reset = false;
  
        spin_lock_bh(&sc->rx.rxbuflock);
        ath9k_hw_abortpcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
-       stopped = ath9k_hw_stopdmarecv(ah);
+       stopped = ath9k_hw_stopdmarecv(ah, &reset);
  
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ath_edma_stop_recv(sc);
                        "confusing the DMA engine when we start RX up\n");
                ATH_DBG_WARN_ON_ONCE(!stopped);
        }
-       return stopped;
+       return stopped && !reset;
  }
  
  void ath_flushrecv(struct ath_softc *sc)
@@@ -571,7 -574,7 +571,7 @@@ static void ath_rx_ps_beacon(struct ath
                sc->ps_flags &= ~PS_BEACON_SYNC;
                ath_dbg(common, ATH_DBG_PS,
                        "Reconfigure Beacon timers based on timestamp from the AP\n");
 -              ath_beacon_config(sc, NULL);
 +              ath_set_beacon(sc);
        }
  
        if (ath_beacon_dtim_pending_cab(skb)) {
@@@ -1339,7 -1342,7 +1339,7 @@@ static void ath_ant_comb_scan(struct at
        struct ath_hw_antcomb_conf div_ant_conf;
        struct ath_ant_comb *antcomb = &sc->ant_comb;
        int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
 -      int curr_main_set, curr_bias;
 +      int curr_main_set;
        int main_rssi = rs->rs_rssi_ctl0;
        int alt_rssi = rs->rs_rssi_ctl1;
        int rx_ant_conf,  main_ant_conf;
        ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
        curr_alt_set = div_ant_conf.alt_lna_conf;
        curr_main_set = div_ant_conf.main_lna_conf;
 -      curr_bias = div_ant_conf.fast_div_bias;
  
        antcomb->count++;
  
@@@ -1742,7 -1746,7 +1742,7 @@@ int ath_rx_tasklet(struct ath_softc *sc
                if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                              PS_WAIT_FOR_CAB |
                                              PS_WAIT_FOR_PSPOLL_DATA)) ||
 -                                      unlikely(ath9k_check_auto_sleep(sc)))
 +                                              ath9k_check_auto_sleep(sc))
                        ath_rx_ps(sc, skb);
                spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  
@@@ -1763,7 -1767,6 +1763,7 @@@ requeue
                } else {
                        list_move_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_buf_link(sc, bf);
 +                      ath9k_hw_rxena(ah);
                }
        } while (1);
  
@@@ -3140,12 -3140,6 +3140,6 @@@ static int iwl4965_init_drv(struct iwl_
  
        iwl_legacy_init_scan_params(priv);
  
-       /* Set the tx_power_user_lmt to the lowest power level
-        * this value will get overwritten by channel max power avg
-        * from eeprom */
-       priv->tx_power_user_lmt = IWL4965_TX_POWER_TARGET_POWER_MIN;
-       priv->tx_power_next = IWL4965_TX_POWER_TARGET_POWER_MIN;
        ret = iwl_legacy_init_channel_map(priv);
        if (ret) {
                IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
@@@ -3179,7 -3173,7 +3173,7 @@@ static void iwl4965_hw_detect(struct iw
  {
        priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV);
        priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG);
 -      pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
 +      priv->rev_id = priv->pci_dev->revision;
        IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
  }
  
@@@ -1,6 -1,6 +1,6 @@@
  /******************************************************************************
   *
 - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
 + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2 of the GNU General Public License as
@@@ -29,7 -29,6 +29,7 @@@
  #include "iwl-sta.h"
  #include "iwl-core.h"
  #include "iwl-agn-calib.h"
 +#include "iwl-helpers.h"
  
  static int iwlagn_disable_bss(struct iwl_priv *priv,
                              struct iwl_rxon_context *ctx,
@@@ -58,9 -57,8 +58,9 @@@ static int iwlagn_disable_pan(struct iw
        u8 old_dev_type = send->dev_type;
        int ret;
  
 -      iwlagn_init_notification_wait(priv, &disable_wait, NULL,
 -                                    REPLY_WIPAN_DEACTIVATION_COMPLETE);
 +      iwlagn_init_notification_wait(priv, &disable_wait,
 +                                    REPLY_WIPAN_DEACTIVATION_COMPLETE,
 +                                    NULL, NULL);
  
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        send->dev_type = RXON_DEV_TYPE_P2P;
                IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
                iwlagn_remove_notification(priv, &disable_wait);
        } else {
 -              signed long wait_res;
 -
 -              wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
 -              if (wait_res == 0) {
 +              ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
 +              if (ret)
                        IWL_ERR(priv, "Timed out waiting for PAN disable\n");
 -                      ret = -EIO;
 -              }
        }
  
        return ret;
@@@ -333,7 -335,6 +333,6 @@@ int iwlagn_mac_config(struct ieee80211_
        struct ieee80211_channel *channel = conf->channel;
        const struct iwl_channel_info *ch_info;
        int ret = 0;
-       bool ht_changed[NUM_IWL_RXON_CTX] = {};
  
        IWL_DEBUG_MAC80211(priv, "changed %#x", changed);
  
  
                for_each_context(priv, ctx) {
                        /* Configure HT40 channels */
-                       if (ctx->ht.enabled != conf_is_ht(conf)) {
+                       if (ctx->ht.enabled != conf_is_ht(conf))
                                ctx->ht.enabled = conf_is_ht(conf);
-                               ht_changed[ctx->ctxid] = true;
-                       }
  
                        if (ctx->ht.enabled) {
                                if (conf_is_ht40_minus(conf)) {
                if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
                        continue;
                iwlagn_commit_rxon(priv, ctx);
-               if (ht_changed[ctx->ctxid])
-                       iwlagn_update_qos(priv, ctx);
        }
   out:
        mutex_unlock(&priv->mutex);
@@@ -598,18 -595,6 +593,18 @@@ void iwlagn_bss_info_changed(struct iee
                        priv->timestamp = bss_conf->timestamp;
                        ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                } else {
 +                      /*
 +                       * If we disassociate while there are pending
 +                       * frames, just wake up the queues and let the
 +                       * frames "escape" ... This shouldn't really
 +                       * be happening to start with, but we should
 +                       * not get stuck in this case either since it
 +                       * can happen if userspace gets confused.
 +                       */
 +                      if (ctx->last_tx_rejected) {
 +                              ctx->last_tx_rejected = false;
 +                              iwl_wake_any_queue(priv, ctx);
 +                      }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
                }
        }
@@@ -2,7 -2,7 +2,7 @@@
   *
   * GPL LICENSE SUMMARY
   *
 - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
 + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
@@@ -222,8 -222,13 +222,8 @@@ void iwlagn_tx_queue_set_status(struct 
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
  }
  
 -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 -                        int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
  {
 -      unsigned long flags;
 -      u16 ra_tid;
 -      int ret;
 -
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWLAGN_FIRST_AMPDU_QUEUE +
                priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
                return -EINVAL;
        }
  
 -      ra_tid = BUILD_RAxTID(sta_id, tid);
 -
        /* Modify device's station table to Tx this TID */
 -      ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 -      if (ret)
 -              return ret;
 +      return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 +}
 +
 +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
 +                              struct ieee80211_sta *sta,
 +                              int tid, int frame_limit)
 +{
 +      int sta_id, tx_fifo, txq_id, ssn_idx;
 +      u16 ra_tid;
 +      unsigned long flags;
 +      struct iwl_tid_data *tid_data;
 +
 +      sta_id = iwl_sta_id(sta);
 +      if (WARN_ON(sta_id == IWL_INVALID_STATION))
 +              return;
 +      if (WARN_ON(tid >= MAX_TID_COUNT))
 +              return;
 +
 +      spin_lock_irqsave(&priv->sta_lock, flags);
 +      tid_data = &priv->stations[sta_id].tid[tid];
 +      ssn_idx = SEQ_TO_SN(tid_data->seq_number);
 +      txq_id = tid_data->agg.txq_id;
 +      tx_fifo = tid_data->agg.tx_fifo;
 +      spin_unlock_irqrestore(&priv->sta_lock, flags);
 +
 +      ra_tid = BUILD_RAxTID(sta_id, tid);
  
        spin_lock_irqsave(&priv->lock, flags);
  
        iwl_write_targ_mem(priv, priv->scd_base_addr +
                        IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
                        sizeof(u32),
 -                      ((SCD_WIN_SIZE <<
 +                      ((frame_limit <<
                        IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
                        IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
 -                      ((SCD_FRAME_LIMIT <<
 +                      ((frame_limit <<
                        IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
                        IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
  
        iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
  
        spin_unlock_irqrestore(&priv->lock, flags);
 -
 -      return 0;
  }
  
 -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 -                         u16 ssn_idx, u8 tx_fifo)
 +static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 +                                u16 ssn_idx, u8 tx_fifo)
  {
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWLAGN_FIRST_AMPDU_QUEUE +
@@@ -1048,11 -1034,11 +1048,11 @@@ int iwlagn_tx_agg_start(struct iwl_pri
        tid_data = &priv->stations[sta_id].tid[tid];
        *ssn = SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
 +      tid_data->agg.tx_fifo = tx_fifo;
        iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
 -      ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
 -                                                sta_id, tid, *ssn);
 +      ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
        if (ret)
                return ret;
  
@@@ -1139,7 -1125,8 +1139,7 @@@ int iwlagn_tx_agg_stop(struct iwl_priv 
         * to deactivate the uCode queue, just return "success" to allow
         *  mac80211 to clean up it own data.
         */
 -      priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
 -                                                 tx_fifo_id);
 +      iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id);
        spin_unlock_irqrestore(&priv->lock, flags);
  
        ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@@ -1168,7 -1155,8 +1168,7 @@@ int iwlagn_txq_check_empty(struct iwl_p
                        u16 ssn = SEQ_TO_SN(tid_data->seq_number);
                        int tx_fifo = get_fifo_from_tid(ctx, tid);
                        IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
 -                      priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
 -                                                           ssn, tx_fifo);
 +                      iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo);
                        tid_data->agg.state = IWL_AGG_OFF;
                        ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
                }
@@@ -1236,12 -1224,16 +1236,16 @@@ int iwlagn_tx_queue_reclaim(struct iwl_
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
  
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info,
-                                txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
+               if (WARN_ON_ONCE(tx_info->skb == NULL))
+                       continue;
  
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
-               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+               if (ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
+               iwlagn_tx_status(priv, tx_info,
+                                txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
                tx_info->skb = NULL;
  
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
@@@ -1263,11 -1255,11 +1267,11 @@@ static int iwlagn_tx_status_reply_compr
                                 struct iwl_compressed_ba_resp *ba_resp)
  
  {
 -      int i, sh, ack;
 +      int sh;
        u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
 -      int successes = 0;
        struct ieee80211_tx_info *info;
 +      u64 bitmap, sent_bitmap;
  
        if (unlikely(!agg->wait_for_ba))  {
                if (unlikely(ba_resp->bitmap))
  
        /* Calculate shift to align block-ack bits with our Tx window bits */
        sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
 -      if (sh < 0) /* tbw something is wrong with indices */
 +      if (sh < 0)
                sh += 0x100;
  
 -      if (agg->frame_count > (64 - sh)) {
 -              IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
 -              return -1;
 -      }
 -      if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
 +      /*
 +       * Check for success or failure according to the
 +       * transmitted bitmap and block-ack bitmap
 +       */
 +      bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
 +      sent_bitmap = bitmap & agg->bitmap;
 +
 +      /* Sanity check values reported by uCode */
 +      if (ba_resp->txed_2_done > ba_resp->txed) {
 +              IWL_DEBUG_TX_REPLY(priv,
 +                      "bogus sent(%d) and ack(%d) count\n",
 +                      ba_resp->txed, ba_resp->txed_2_done);
                /*
 -               * sent and ack information provided by uCode
 -               * use it instead of figure out ourself
 +               * set txed_2_done = txed,
 +               * so it won't impact rate scale
                 */
 -              if (ba_resp->txed_2_done > ba_resp->txed) {
 -                      IWL_DEBUG_TX_REPLY(priv,
 -                              "bogus sent(%d) and ack(%d) count\n",
 -                              ba_resp->txed, ba_resp->txed_2_done);
 -                      /*
 -                       * set txed_2_done = txed,
 -                       * so it won't impact rate scale
 -                       */
 -                      ba_resp->txed = ba_resp->txed_2_done;
 -              }
 -              IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
 -                              ba_resp->txed, ba_resp->txed_2_done);
 -      } else {
 -              u64 bitmap, sent_bitmap;
 -
 -              /* don't use 64-bit values for now */
 -              bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
 -
 -              /* check for success or failure according to the
 -               * transmitted bitmap and block-ack bitmap */
 -              sent_bitmap = bitmap & agg->bitmap;
 -
 -              /* For each frame attempted in aggregation,
 -               * update driver's record of tx frame's status. */
 -              i = 0;
 -              while (sent_bitmap) {
 -                      ack = sent_bitmap & 1ULL;
 -                      successes += ack;
 -                      IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
 -                              ack ? "ACK" : "NACK", i,
 -                              (agg->start_idx + i) & 0xff,
 -                              agg->start_idx + i);
 -                      sent_bitmap >>= 1;
 -                      ++i;
 -              }
 +              ba_resp->txed = ba_resp->txed_2_done;
 +      }
 +      IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
 +                      ba_resp->txed, ba_resp->txed_2_done);
  
 -              IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n",
 -                                 (unsigned long long)bitmap);
 +      /* Find the first ACKed frame to store the TX status */
 +      while (sent_bitmap && !(sent_bitmap & 1)) {
 +              agg->start_idx = (agg->start_idx + 1) & 0xff;
 +              sent_bitmap >>= 1;
        }
  
        info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
        memset(&info->status, 0, sizeof(info->status));
        info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
 -      if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
 -              info->status.ampdu_ack_len = ba_resp->txed_2_done;
 -              info->status.ampdu_len = ba_resp->txed;
 -
 -      } else {
 -              info->status.ampdu_ack_len = successes;
 -              info->status.ampdu_len = agg->frame_count;
 -      }
 +      info->status.ampdu_ack_len = ba_resp->txed_2_done;
 +      info->status.ampdu_len = ba_resp->txed;
        iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
  
        return 0;
diff --combined net/bluetooth/hci_core.c
@@@ -56,6 -56,7 +56,6 @@@
  static void hci_cmd_task(unsigned long arg);
  static void hci_rx_task(unsigned long arg);
  static void hci_tx_task(unsigned long arg);
 -static void hci_notify(struct hci_dev *hdev, int event);
  
  static DEFINE_RWLOCK(hci_task_lock);
  
@@@ -586,10 -587,8 +586,8 @@@ static int hci_dev_do_close(struct hci_
        hci_req_cancel(hdev, ENODEV);
        hci_req_lock(hdev);
  
-       /* Stop timer, it might be running */
-       del_timer_sync(&hdev->cmd_timer);
        if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
+               del_timer_sync(&hdev->cmd_timer);
                hci_req_unlock(hdev);
                return 0;
        }
  
        /* Drop last sent command */
        if (hdev->sent_cmd) {
+               del_timer_sync(&hdev->cmd_timer);
                kfree_skb(hdev->sent_cmd);
                hdev->sent_cmd = NULL;
        }
@@@ -1082,70 -1082,6 +1081,70 @@@ static void hci_cmd_timer(unsigned lon
        tasklet_schedule(&hdev->cmd_task);
  }
  
 +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
 +                                                      bdaddr_t *bdaddr)
 +{
 +      struct oob_data *data;
 +
 +      list_for_each_entry(data, &hdev->remote_oob_data, list)
 +              if (bacmp(bdaddr, &data->bdaddr) == 0)
 +                      return data;
 +
 +      return NULL;
 +}
 +
 +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
 +{
 +      struct oob_data *data;
 +
 +      data = hci_find_remote_oob_data(hdev, bdaddr);
 +      if (!data)
 +              return -ENOENT;
 +
 +      BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
 +
 +      list_del(&data->list);
 +      kfree(data);
 +
 +      return 0;
 +}
 +
 +int hci_remote_oob_data_clear(struct hci_dev *hdev)
 +{
 +      struct oob_data *data, *n;
 +
 +      list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
 +              list_del(&data->list);
 +              kfree(data);
 +      }
 +
 +      return 0;
 +}
 +
 +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 +                                                              u8 *randomizer)
 +{
 +      struct oob_data *data;
 +
 +      data = hci_find_remote_oob_data(hdev, bdaddr);
 +
 +      if (!data) {
 +              data = kmalloc(sizeof(*data), GFP_ATOMIC);
 +              if (!data)
 +                      return -ENOMEM;
 +
 +              bacpy(&data->bdaddr, bdaddr);
 +              list_add(&data->list, &hdev->remote_oob_data);
 +      }
 +
 +      memcpy(data->hash, hash, sizeof(data->hash));
 +      memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
 +
 +      BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
 +
 +      return 0;
 +}
 +
  /* Register HCI device */
  int hci_register_dev(struct hci_dev *hdev)
  {
  
        INIT_LIST_HEAD(&hdev->link_keys);
  
 +      INIT_LIST_HEAD(&hdev->remote_oob_data);
 +
        INIT_WORK(&hdev->power_on, hci_power_on);
        INIT_WORK(&hdev->power_off, hci_power_off);
        setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@@ -1291,7 -1225,6 +1290,7 @@@ int hci_unregister_dev(struct hci_dev *
        hci_blacklist_clear(hdev);
        hci_uuids_clear(hdev);
        hci_link_keys_clear(hdev);
 +      hci_remote_oob_data_clear(hdev);
        hci_dev_unlock_bh(hdev);
  
        __hci_dev_put(hdev);
@@@ -1341,7 -1274,7 +1340,7 @@@ int hci_recv_frame(struct sk_buff *skb
  EXPORT_SYMBOL(hci_recv_frame);
  
  static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
 -                        int count, __u8 index, gfp_t gfp_mask)
 +                                                int count, __u8 index)
  {
        int len = 0;
        int hlen = 0;
                        break;
                }
  
 -              skb = bt_skb_alloc(len, gfp_mask);
 +              skb = bt_skb_alloc(len, GFP_ATOMIC);
                if (!skb)
                        return -ENOMEM;
  
@@@ -1457,7 -1390,8 +1456,7 @@@ int hci_recv_fragment(struct hci_dev *h
                return -EILSEQ;
  
        while (count) {
 -              rem = hci_reassembly(hdev, type, data, count,
 -                                              type - 1, GFP_ATOMIC);
 +              rem = hci_reassembly(hdev, type, data, count, type - 1);
                if (rem < 0)
                        return rem;
  
@@@ -1491,8 -1425,8 +1490,8 @@@ int hci_recv_stream_fragment(struct hci
                } else
                        type = bt_cb(skb)->pkt_type;
  
 -              rem = hci_reassembly(hdev, type, data,
 -                                      count, STREAM_REASSEMBLY, GFP_ATOMIC);
 +              rem = hci_reassembly(hdev, type, data, count,
 +                                                      STREAM_REASSEMBLY);
                if (rem < 0)
                        return rem;
  
@@@ -195,17 -195,14 +195,17 @@@ static void hci_cc_write_local_name(str
  
        BT_DBG("%s status 0x%x", hdev->name, status);
  
 -      if (status)
 -              return;
 -
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
        if (!sent)
                return;
  
 -      memcpy(hdev->dev_name, sent, 248);
 +      if (test_bit(HCI_MGMT, &hdev->flags))
 +              mgmt_set_local_name_complete(hdev->id, sent, status);
 +
 +      if (status)
 +              return;
 +
 +      memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
  }
  
  static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
  
 -      memcpy(hdev->dev_name, rp->name, 248);
 +      memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
  }
  
  static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@@ -824,17 -821,6 +824,17 @@@ static void hci_cc_user_confirm_neg_rep
                                                                rp->status);
  }
  
 +static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 +                                                      struct sk_buff *skb)
 +{
 +      struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 +
 +      BT_DBG("%s status 0x%x", hdev->name, rp->status);
 +
 +      mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
 +                                              rp->randomizer, rp->status);
 +}
 +
  static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
  {
        BT_DBG("%s status 0x%x", hdev->name, status);
@@@ -1228,7 -1214,7 +1228,7 @@@ static inline void hci_inquiry_result_e
  
        hci_dev_lock(hdev);
  
 -      for (; num_rsp; num_rsp--) {
 +      for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
                data.clock_offset       = info->clock_offset;
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
 -              info++;
                hci_inquiry_cache_update(hdev, &data);
 +              mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
 +                                                                      NULL);
        }
  
        hci_dev_unlock(hdev);
@@@ -1497,9 -1482,6 +1497,9 @@@ static inline void hci_remote_name_evt(
  
        hci_dev_lock(hdev);
  
 +      if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
 +              mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
 +
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn && hci_outgoing_auth_needed(hdev, conn)) {
                struct hci_cp_auth_requested cp;
@@@ -1769,10 -1751,6 +1769,10 @@@ static inline void hci_cmd_complete_evt
                hci_cc_pin_code_neg_reply(hdev, skb);
                break;
  
 +      case HCI_OP_READ_LOCAL_OOB_DATA:
 +              hci_cc_read_local_oob_data_reply(hdev, skb);
 +              break;
 +
        case HCI_OP_LE_READ_BUFFER_SIZE:
                hci_cc_le_read_buffer_size(hdev, skb);
                break;
@@@ -2162,7 -2140,7 +2162,7 @@@ static inline void hci_inquiry_result_w
                struct inquiry_info_with_rssi_and_pscan_mode *info;
                info = (void *) (skb->data + 1);
  
 -              for (; num_rsp; num_rsp--) {
 +              for (; num_rsp; num_rsp--, info++) {
                        bacpy(&data.bdaddr, &info->bdaddr);
                        data.pscan_rep_mode     = info->pscan_rep_mode;
                        data.pscan_period_mode  = info->pscan_period_mode;
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
 -                      info++;
                        hci_inquiry_cache_update(hdev, &data);
 +                      mgmt_device_found(hdev->id, &info->bdaddr,
 +                                              info->dev_class, info->rssi,
 +                                              NULL);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
  
 -              for (; num_rsp; num_rsp--) {
 +              for (; num_rsp; num_rsp--, info++) {
                        bacpy(&data.bdaddr, &info->bdaddr);
                        data.pscan_rep_mode     = info->pscan_rep_mode;
                        data.pscan_period_mode  = info->pscan_period_mode;
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
 -                      info++;
                        hci_inquiry_cache_update(hdev, &data);
 +                      mgmt_device_found(hdev->id, &info->bdaddr,
 +                                              info->dev_class, info->rssi,
 +                                              NULL);
                }
        }
  
@@@ -2322,7 -2296,7 +2322,7 @@@ static inline void hci_extended_inquiry
  
        hci_dev_lock(hdev);
  
 -      for (; num_rsp; num_rsp--) {
 +      for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
                data.clock_offset       = info->clock_offset;
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
 -              info++;
                hci_inquiry_cache_update(hdev, &data);
 +              mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
 +                                              info->rssi, info->data);
        }
  
        hci_dev_unlock(hdev);
@@@ -2382,14 -2355,9 +2382,14 @@@ static inline void hci_io_capa_request_
  
                bacpy(&cp.bdaddr, &ev->bdaddr);
                cp.capability = conn->io_capability;
 -              cp.oob_data = 0;
                cp.authentication = hci_get_auth_req(conn);
  
 +              if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
 +                              hci_find_remote_oob_data(hdev, &conn->dst))
 +                      cp.oob_data = 0x01;
 +              else
 +                      cp.oob_data = 0x00;
 +
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
                                                        sizeof(cp), &cp);
        } else {
@@@ -2419,8 -2387,6 +2419,6 @@@ static inline void hci_io_capa_reply_ev
        if (!conn)
                goto unlock;
  
-       hci_conn_hold(conn);
        conn->remote_cap = ev->capability;
        conn->remote_oob = ev->oob_data;
        conn->remote_auth = ev->authentication;
@@@ -2487,41 -2453,6 +2485,41 @@@ static inline void hci_remote_host_feat
        hci_dev_unlock(hdev);
  }
  
 +static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 +                                                      struct sk_buff *skb)
 +{
 +      struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
 +      struct oob_data *data;
 +
 +      BT_DBG("%s", hdev->name);
 +
 +      hci_dev_lock(hdev);
 +
 +      if (!test_bit(HCI_MGMT, &hdev->flags))
 +              goto unlock;
 +
 +      data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 +      if (data) {
 +              struct hci_cp_remote_oob_data_reply cp;
 +
 +              bacpy(&cp.bdaddr, &ev->bdaddr);
 +              memcpy(cp.hash, data->hash, sizeof(cp.hash));
 +              memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
 +
 +              hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
 +                                                                      &cp);
 +      } else {
 +              struct hci_cp_remote_oob_data_neg_reply cp;
 +
 +              bacpy(&cp.bdaddr, &ev->bdaddr);
 +              hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
 +                                                                      &cp);
 +      }
 +
 +unlock:
 +      hci_dev_unlock(hdev);
 +}
 +
  static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@@ -2724,10 -2655,6 +2722,10 @@@ void hci_event_packet(struct hci_dev *h
                hci_le_meta_evt(hdev, skb);
                break;
  
 +      case HCI_EV_REMOTE_OOB_DATA_REQUEST:
 +              hci_remote_oob_data_request_evt(hdev, skb);
 +              break;
 +
        default:
                BT_DBG("%s event 0x%x", hdev->name, event);
                break;
@@@ -70,101 -70,108 +70,101 @@@ static void l2cap_busy_work(struct work
  
  static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
                                u8 code, u8 ident, u16 dlen, void *data);
 +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
  
  static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
  
  /* ---- L2CAP channels ---- */
 -static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
 +static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
  {
 -      struct sock *s;
 -      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 +      struct l2cap_chan *c;
 +
 +      list_for_each_entry(c, &conn->chan_l, list) {
 +              struct sock *s = c->sk;
                if (l2cap_pi(s)->dcid == cid)
 -                      break;
 +                      return c;
        }
 -      return s;
 +      return NULL;
 +
  }
  
 -static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
 +static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
  {
 -      struct sock *s;
 -      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 +      struct l2cap_chan *c;
 +
 +      list_for_each_entry(c, &conn->chan_l, list) {
 +              struct sock *s = c->sk;
                if (l2cap_pi(s)->scid == cid)
 -                      break;
 +                      return c;
        }
 -      return s;
 +      return NULL;
  }
  
  /* Find channel with given SCID.
   * Returns locked socket */
 -static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid)
 +static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
  {
 -      struct sock *s;
 -      read_lock(&l->lock);
 -      s = __l2cap_get_chan_by_scid(l, cid);
 -      if (s)
 -              bh_lock_sock(s);
 -      read_unlock(&l->lock);
 -      return s;
 +      struct l2cap_chan *c;
 +
 +      read_lock(&conn->chan_lock);
 +      c = __l2cap_get_chan_by_scid(conn, cid);
 +      if (c)
 +              bh_lock_sock(c->sk);
 +      read_unlock(&conn->chan_lock);
 +      return c;
  }
  
 -static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
 +static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
  {
 -      struct sock *s;
 -      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 -              if (l2cap_pi(s)->ident == ident)
 -                      break;
 +      struct l2cap_chan *c;
 +
 +      list_for_each_entry(c, &conn->chan_l, list) {
 +              if (c->ident == ident)
 +                      return c;
        }
 -      return s;
 +      return NULL;
  }
  
 -static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
 +static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
  {
 -      struct sock *s;
 -      read_lock(&l->lock);
 -      s = __l2cap_get_chan_by_ident(l, ident);
 -      if (s)
 -              bh_lock_sock(s);
 -      read_unlock(&l->lock);
 -      return s;
 +      struct l2cap_chan *c;
 +
 +      read_lock(&conn->chan_lock);
 +      c = __l2cap_get_chan_by_ident(conn, ident);
 +      if (c)
 +              bh_lock_sock(c->sk);
 +      read_unlock(&conn->chan_lock);
 +      return c;
  }
  
 -static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
 +static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
  {
        u16 cid = L2CAP_CID_DYN_START;
  
        for (; cid < L2CAP_CID_DYN_END; cid++) {
 -              if (!__l2cap_get_chan_by_scid(l, cid))
 +              if (!__l2cap_get_chan_by_scid(conn, cid))
                        return cid;
        }
  
        return 0;
  }
  
 -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
 -{
 -      sock_hold(sk);
 -
 -      if (l->head)
 -              l2cap_pi(l->head)->prev_c = sk;
 -
 -      l2cap_pi(sk)->next_c = l->head;
 -      l2cap_pi(sk)->prev_c = NULL;
 -      l->head = sk;
 -}
 -
 -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
 +static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
  {
 -      struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
 +      struct l2cap_chan *chan;
  
 -      write_lock_bh(&l->lock);
 -      if (sk == l->head)
 -              l->head = next;
 +      chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
 +      if (!chan)
 +              return NULL;
  
 -      if (next)
 -              l2cap_pi(next)->prev_c = prev;
 -      if (prev)
 -              l2cap_pi(prev)->next_c = next;
 -      write_unlock_bh(&l->lock);
 +      chan->sk = sk;
  
 -      __sock_put(sk);
 +      return chan;
  }
  
 -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
 +static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
 +      struct sock *sk = chan->sk;
  
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
                        l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
                } else {
                        /* Alloc CID for connection-oriented socket */
 -                      l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
 +                      l2cap_pi(sk)->scid = l2cap_alloc_cid(conn);
                        l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
                }
        } else if (sk->sk_type == SOCK_DGRAM) {
                l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
        }
  
 -      __l2cap_chan_link(l, sk);
 +      sock_hold(sk);
  
 -      if (parent)
 -              bt_accept_enqueue(parent, sk);
 +      list_add(&chan->list, &conn->chan_l);
  }
  
  /* Delete channel.
   * Must be called on the locked socket. */
 -void l2cap_chan_del(struct sock *sk, int err)
 +void l2cap_chan_del(struct l2cap_chan *chan, int err)
  {
 +      struct sock *sk = chan->sk;
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
        struct sock *parent = bt_sk(sk)->parent;
  
        l2cap_sock_clear_timer(sk);
  
 -      BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
 +      BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
  
        if (conn) {
 -              /* Unlink from channel list */
 -              l2cap_chan_unlink(&conn->chan_list, sk);
 +              /* Delete from channel list */
 +              write_lock_bh(&conn->chan_lock);
 +              list_del(&chan->list);
 +              write_unlock_bh(&conn->chan_lock);
 +              __sock_put(sk);
 +
                l2cap_pi(sk)->conn = NULL;
                hci_conn_put(conn->hcon);
        }
        } else
                sk->sk_state_change(sk);
  
 -      skb_queue_purge(TX_QUEUE(sk));
 +      if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE &&
 +                      l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE))
 +              goto free;
 +
 +      skb_queue_purge(&chan->tx_q);
  
        if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
                struct srej_list *l, *tmp;
  
 -              del_timer(&l2cap_pi(sk)->retrans_timer);
 -              del_timer(&l2cap_pi(sk)->monitor_timer);
 -              del_timer(&l2cap_pi(sk)->ack_timer);
 +              del_timer(&chan->retrans_timer);
 +              del_timer(&chan->monitor_timer);
 +              del_timer(&chan->ack_timer);
  
 -              skb_queue_purge(SREJ_QUEUE(sk));
 -              skb_queue_purge(BUSY_QUEUE(sk));
 +              skb_queue_purge(&chan->srej_q);
 +              skb_queue_purge(&chan->busy_q);
  
 -              list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
 +              list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                        list_del(&l->list);
                        kfree(l);
                }
        }
 +
 +free:
 +      kfree(chan);
  }
  
  static inline u8 l2cap_get_auth_type(struct sock *sk)
@@@ -345,11 -341,10 +345,11 @@@ void l2cap_send_cmd(struct l2cap_conn *
        hci_send_acl(conn->hcon, skb, flags);
  }
  
 -static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
 +static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
  {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct l2cap_conn *conn = pi->conn;
        struct sock *sk = (struct sock *)pi;
        int count, hlen = L2CAP_HDR_SIZE + 2;
        if (pi->fcs == L2CAP_FCS_CRC16)
                hlen += 2;
  
 -      BT_DBG("pi %p, control 0x%2.2x", pi, control);
 +      BT_DBG("chan %p, control 0x%2.2x", chan, control);
  
        count = min_t(unsigned int, conn->mtu, hlen);
        control |= L2CAP_CTRL_FRAME_TYPE;
  
 -      if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
 +      if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
                control |= L2CAP_CTRL_FINAL;
 -              pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 +              chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
        }
  
 -      if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
 +      if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
                control |= L2CAP_CTRL_POLL;
 -              pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
 +              chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
        }
  
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        hci_send_acl(pi->conn->hcon, skb, flags);
  }
  
 -static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
 +static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
  {
 -      if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
 -              pi->conn_state |= L2CAP_CONN_RNR_SENT;
 +              chan->conn_state |= L2CAP_CONN_RNR_SENT;
        } else
                control |= L2CAP_SUPER_RCV_READY;
  
 -      control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +      control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      l2cap_send_sframe(pi, control);
 +      l2cap_send_sframe(chan, control);
  }
  
  static inline int __l2cap_no_conn_pending(struct sock *sk)
        return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND);
  }
  
 -static void l2cap_do_start(struct sock *sk)
 +static void l2cap_do_start(struct l2cap_chan *chan)
  {
 +      struct sock *sk = chan->sk;
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
  
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
                        req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                        req.psm  = l2cap_pi(sk)->psm;
  
 -                      l2cap_pi(sk)->ident = l2cap_get_ident(conn);
 +                      chan->ident = l2cap_get_ident(conn);
                        l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
  
 -                      l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 -                                      L2CAP_CONN_REQ, sizeof(req), &req);
 +                      l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
 +                                                      sizeof(req), &req);
                }
        } else {
                struct l2cap_info_req req;
@@@ -467,20 -461,19 +467,20 @@@ static inline int l2cap_mode_supported(
        }
  }
  
 -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
 +void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
  {
 +      struct sock *sk;
        struct l2cap_disconn_req req;
  
        if (!conn)
                return;
  
 -      skb_queue_purge(TX_QUEUE(sk));
 +      sk = chan->sk;
  
        if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
 -              del_timer(&l2cap_pi(sk)->retrans_timer);
 -              del_timer(&l2cap_pi(sk)->monitor_timer);
 -              del_timer(&l2cap_pi(sk)->ack_timer);
 +              del_timer(&chan->retrans_timer);
 +              del_timer(&chan->monitor_timer);
 +              del_timer(&chan->ack_timer);
        }
  
        req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
  /* ---- L2CAP connections ---- */
  static void l2cap_conn_start(struct l2cap_conn *conn)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
 -      struct sock_del_list del, *tmp1, *tmp2;
 -      struct sock *sk;
 +      struct l2cap_chan *chan, *tmp;
  
        BT_DBG("conn %p", conn);
  
 -      INIT_LIST_HEAD(&del.list);
 +      read_lock(&conn->chan_lock);
  
 -      read_lock(&l->lock);
 +      list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
 +              struct sock *sk = chan->sk;
  
 -      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
  
                if (sk->sk_type != SOCK_SEQPACKET &&
                                        conn->feat_mask)
                                        && l2cap_pi(sk)->conf_state &
                                        L2CAP_CONF_STATE2_DEVICE) {
 -                              tmp1 = kzalloc(sizeof(struct sock_del_list),
 -                                              GFP_ATOMIC);
 -                              tmp1->sk = sk;
 -                              list_add_tail(&tmp1->list, &del.list);
 +                              /* __l2cap_sock_close() calls list_del(chan)
 +                               * so release the lock */
 +                              read_unlock_bh(&conn->chan_lock);
 +                               __l2cap_sock_close(sk, ECONNRESET);
 +                              read_lock_bh(&conn->chan_lock);
                                bh_unlock_sock(sk);
                                continue;
                        }
                        req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                        req.psm  = l2cap_pi(sk)->psm;
  
 -                      l2cap_pi(sk)->ident = l2cap_get_ident(conn);
 +                      chan->ident = l2cap_get_ident(conn);
                        l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
  
 -                      l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 -                              L2CAP_CONN_REQ, sizeof(req), &req);
 +                      l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
 +                                                      sizeof(req), &req);
  
                } else if (sk->sk_state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
                                rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
                        }
  
 -                      l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 -                                      L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 +                      l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 +                                                      sizeof(rsp), &rsp);
  
                        if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
                                        rsp.result != L2CAP_CR_SUCCESS) {
  
                        l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
                        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 -                                              l2cap_build_conf_req(sk, buf), buf);
 -                      l2cap_pi(sk)->num_conf_req++;
 +                                              l2cap_build_conf_req(chan, buf), buf);
 +                      chan->num_conf_req++;
                }
  
                bh_unlock_sock(sk);
        }
  
 -      read_unlock(&l->lock);
 -
 -      list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
 -              bh_lock_sock(tmp1->sk);
 -              __l2cap_sock_close(tmp1->sk, ECONNRESET);
 -              bh_unlock_sock(tmp1->sk);
 -              list_del(&tmp1->list);
 -              kfree(tmp1);
 -      }
 +      read_unlock(&conn->chan_lock);
  }
  
  /* Find socket with cid and source bdaddr.
   */
  static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
  {
 -      struct sock *s, *sk = NULL, *sk1 = NULL;
 +      struct sock *sk = NULL, *sk1 = NULL;
        struct hlist_node *node;
  
        read_lock(&l2cap_sk_list.lock);
                                sk1 = sk;
                }
        }
 -      s = node ? sk : sk1;
 -      if (s)
 -              bh_lock_sock(s);
 +
        read_unlock(&l2cap_sk_list.lock);
  
 -      return s;
 +      return node ? sk : sk1;
  }
  
  static void l2cap_le_conn_ready(struct l2cap_conn *conn)
  {
 -      struct l2cap_chan_list *list = &conn->chan_list;
 -      struct sock *parent, *uninitialized_var(sk);
 +      struct sock *parent, *sk;
 +      struct l2cap_chan *chan;
  
        BT_DBG("");
  
        if (!parent)
                return;
  
 +      bh_lock_sock(parent);
 +
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
                BT_DBG("backlog full %d", parent->sk_ack_backlog);
        if (!sk)
                goto clean;
  
 -      write_lock_bh(&list->lock);
 +      chan = l2cap_chan_alloc(sk);
 +      if (!chan) {
 +              l2cap_sock_kill(sk);
 +              goto clean;
 +      }
 +
 +      write_lock_bh(&conn->chan_lock);
  
        hci_conn_hold(conn->hcon);
  
        l2cap_sock_init(sk, parent);
 +
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
  
 -      __l2cap_chan_add(conn, sk, parent);
 +      bt_accept_enqueue(parent, sk);
 +
 +      __l2cap_chan_add(conn, chan);
 +
 +      l2cap_pi(sk)->chan = chan;
  
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
  
        sk->sk_state = BT_CONNECTED;
        parent->sk_data_ready(parent, 0);
  
 -      write_unlock_bh(&list->lock);
 +      write_unlock_bh(&conn->chan_lock);
  
  clean:
        bh_unlock_sock(parent);
  
  static void l2cap_conn_ready(struct l2cap_conn *conn)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
 -      struct sock *sk;
 +      struct l2cap_chan *chan;
  
        BT_DBG("conn %p", conn);
  
        if (!conn->hcon->out && conn->hcon->type == LE_LINK)
                l2cap_le_conn_ready(conn);
  
 -      read_lock(&l->lock);
 +      read_lock(&conn->chan_lock);
 +
 +      list_for_each_entry(chan, &conn->chan_l, list) {
 +              struct sock *sk = chan->sk;
  
 -      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
  
                if (conn->hcon->type == LE_LINK) {
                        sk->sk_state = BT_CONNECTED;
                        sk->sk_state_change(sk);
                } else if (sk->sk_state == BT_CONNECT)
 -                      l2cap_do_start(sk);
 +                      l2cap_do_start(chan);
  
                bh_unlock_sock(sk);
        }
  
 -      read_unlock(&l->lock);
 +      read_unlock(&conn->chan_lock);
  }
  
  /* Notify sockets that we cannot guaranty reliability anymore */
  static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
 -      struct sock *sk;
 +      struct l2cap_chan *chan;
  
        BT_DBG("conn %p", conn);
  
 -      read_lock(&l->lock);
 +      read_lock(&conn->chan_lock);
 +
 +      list_for_each_entry(chan, &conn->chan_l, list) {
 +              struct sock *sk = chan->sk;
  
 -      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                if (l2cap_pi(sk)->force_reliable)
                        sk->sk_err = err;
        }
  
 -      read_unlock(&l->lock);
 +      read_unlock(&conn->chan_lock);
  }
  
  static void l2cap_info_timeout(unsigned long arg)
@@@ -766,9 -755,7 +766,9 @@@ static struct l2cap_conn *l2cap_conn_ad
        conn->feat_mask = 0;
  
        spin_lock_init(&conn->lock);
 -      rwlock_init(&conn->chan_list.lock);
 +      rwlock_init(&conn->chan_lock);
 +
 +      INIT_LIST_HEAD(&conn->chan_l);
  
        if (hcon->type != LE_LINK)
                setup_timer(&conn->info_timer, l2cap_info_timeout,
  static void l2cap_conn_del(struct hci_conn *hcon, int err)
  {
        struct l2cap_conn *conn = hcon->l2cap_data;
 +      struct l2cap_chan *chan, *l;
        struct sock *sk;
  
        if (!conn)
        kfree_skb(conn->rx_skb);
  
        /* Kill channels */
 -      while ((sk = conn->chan_list.head)) {
 +      list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
 +              sk = chan->sk;
                bh_lock_sock(sk);
 -              l2cap_chan_del(sk, err);
 +              l2cap_chan_del(chan, err);
                bh_unlock_sock(sk);
                l2cap_sock_kill(sk);
        }
        kfree(conn);
  }
  
 -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
 +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
 -      write_lock_bh(&l->lock);
 -      __l2cap_chan_add(conn, sk, parent);
 -      write_unlock_bh(&l->lock);
 +      write_lock_bh(&conn->chan_lock);
 +      __l2cap_chan_add(conn, chan);
 +      write_unlock_bh(&conn->chan_lock);
  }
  
  /* ---- Socket interface ---- */
@@@ -852,7 -838,6 +852,7 @@@ int l2cap_do_connect(struct sock *sk
        bdaddr_t *src = &bt_sk(sk)->src;
        bdaddr_t *dst = &bt_sk(sk)->dst;
        struct l2cap_conn *conn;
 +      struct l2cap_chan *chan;
        struct hci_conn *hcon;
        struct hci_dev *hdev;
        __u8 auth_type;
                goto done;
        }
  
 +      chan = l2cap_chan_alloc(sk);
 +      if (!chan) {
 +              hci_conn_put(hcon);
 +              err = -ENOMEM;
 +              goto done;
 +      }
 +
        /* Update source addr of the socket */
        bacpy(src, conn->src);
  
 -      l2cap_chan_add(conn, sk, NULL);
 +      l2cap_chan_add(conn, chan);
 +
 +      l2cap_pi(sk)->chan = chan;
  
        sk->sk_state = BT_CONNECT;
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
                        if (l2cap_check_security(sk))
                                sk->sk_state = BT_CONNECTED;
                } else
 -                      l2cap_do_start(sk);
 +                      l2cap_do_start(chan);
        }
  
        err = 0;
@@@ -930,7 -906,7 +930,7 @@@ int __l2cap_wait_ack(struct sock *sk
        int timeo = HZ/5;
  
        add_wait_queue(sk_sleep(sk), &wait);
 -      while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
 +      while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
                set_current_state(TASK_INTERRUPTIBLE);
  
                if (!timeo)
  
  static void l2cap_monitor_timeout(unsigned long arg)
  {
 -      struct sock *sk = (void *) arg;
 +      struct l2cap_chan *chan = (void *) arg;
 +      struct sock *sk = chan->sk;
  
 -      BT_DBG("sk %p", sk);
 +      BT_DBG("chan %p", chan);
  
        bh_lock_sock(sk);
 -      if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
 -              l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
 +      if (chan->retry_count >= chan->remote_max_tx) {
 +              l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED);
                bh_unlock_sock(sk);
                return;
        }
  
 -      l2cap_pi(sk)->retry_count++;
 +      chan->retry_count++;
        __mod_monitor_timer();
  
 -      l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
 +      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
  }
  
  static void l2cap_retrans_timeout(unsigned long arg)
  {
 -      struct sock *sk = (void *) arg;
 +      struct l2cap_chan *chan = (void *) arg;
 +      struct sock *sk = chan->sk;
  
 -      BT_DBG("sk %p", sk);
 +      BT_DBG("chan %p", chan);
  
        bh_lock_sock(sk);
 -      l2cap_pi(sk)->retry_count = 1;
 +      chan->retry_count = 1;
        __mod_monitor_timer();
  
 -      l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
 +      chan->conn_state |= L2CAP_CONN_WAIT_F;
  
 -      l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
 +      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
  }
  
 -static void l2cap_drop_acked_frames(struct sock *sk)
 +static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
  {
        struct sk_buff *skb;
  
 -      while ((skb = skb_peek(TX_QUEUE(sk))) &&
 -                      l2cap_pi(sk)->unacked_frames) {
 -              if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
 +      while ((skb = skb_peek(&chan->tx_q)) &&
 +                      chan->unacked_frames) {
 +              if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
                        break;
  
 -              skb = skb_dequeue(TX_QUEUE(sk));
 +              skb = skb_dequeue(&chan->tx_q);
                kfree_skb(skb);
  
 -              l2cap_pi(sk)->unacked_frames--;
 +              chan->unacked_frames--;
        }
  
 -      if (!l2cap_pi(sk)->unacked_frames)
 -              del_timer(&l2cap_pi(sk)->retrans_timer);
 +      if (!chan->unacked_frames)
 +              del_timer(&chan->retrans_timer);
  }
  
  void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
        hci_send_acl(hcon, skb, flags);
  }
  
 -void l2cap_streaming_send(struct sock *sk)
 +void l2cap_streaming_send(struct l2cap_chan *chan)
  {
 +      struct sock *sk = chan->sk;
        struct sk_buff *skb;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control, fcs;
  
 -      while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
 +      while ((skb = skb_dequeue(&chan->tx_q))) {
                control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
 -              control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
 +              control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
                put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
  
                if (pi->fcs == L2CAP_FCS_CRC16) {
  
                l2cap_do_send(sk, skb);
  
 -              pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
 +              chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
        }
  }
  
 -static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
 +static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
  {
 +      struct sock *sk = chan->sk;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct sk_buff *skb, *tx_skb;
        u16 control, fcs;
  
 -      skb = skb_peek(TX_QUEUE(sk));
 +      skb = skb_peek(&chan->tx_q);
        if (!skb)
                return;
  
                if (bt_cb(skb)->tx_seq == tx_seq)
                        break;
  
 -              if (skb_queue_is_last(TX_QUEUE(sk), skb))
 +              if (skb_queue_is_last(&chan->tx_q, skb))
                        return;
  
 -      } while ((skb = skb_queue_next(TX_QUEUE(sk), skb)));
 +      } while ((skb = skb_queue_next(&chan->tx_q, skb)));
  
 -      if (pi->remote_max_tx &&
 -                      bt_cb(skb)->retries == pi->remote_max_tx) {
 -              l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
 +      if (chan->remote_max_tx &&
 +                      bt_cb(skb)->retries == chan->remote_max_tx) {
 +              l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
                return;
        }
  
        tx_skb = skb_clone(skb, GFP_ATOMIC);
        bt_cb(skb)->retries++;
        control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+       control &= L2CAP_CTRL_SAR;
  
 -      if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
 +      if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
                control |= L2CAP_CTRL_FINAL;
 -              pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 +              chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
        }
  
 -      control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
 +      control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
                        | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
  
        put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
        l2cap_do_send(sk, tx_skb);
  }
  
 -int l2cap_ertm_send(struct sock *sk)
 +int l2cap_ertm_send(struct l2cap_chan *chan)
  {
        struct sk_buff *skb, *tx_skb;
 +      struct sock *sk = chan->sk;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control, fcs;
        int nsent = 0;
        if (sk->sk_state != BT_CONNECTED)
                return -ENOTCONN;
  
 -      while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
 +      while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
  
 -              if (pi->remote_max_tx &&
 -                              bt_cb(skb)->retries == pi->remote_max_tx) {
 -                      l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
 +              if (chan->remote_max_tx &&
 +                              bt_cb(skb)->retries == chan->remote_max_tx) {
 +                      l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED);
                        break;
                }
  
                control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
                control &= L2CAP_CTRL_SAR;
  
 -              if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
 +              if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
                        control |= L2CAP_CTRL_FINAL;
 -                      pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 +                      chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
                }
 -              control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
 -                              | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
 +              control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
 +                              | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
  
  
  
                __mod_retrans_timer();
  
 -              bt_cb(skb)->tx_seq = pi->next_tx_seq;
 -              pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
 +              bt_cb(skb)->tx_seq = chan->next_tx_seq;
 +              chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
  
                if (bt_cb(skb)->retries == 1)
 -                      pi->unacked_frames++;
 +                      chan->unacked_frames++;
  
 -              pi->frames_sent++;
 +              chan->frames_sent++;
  
 -              if (skb_queue_is_last(TX_QUEUE(sk), skb))
 -                      sk->sk_send_head = NULL;
 +              if (skb_queue_is_last(&chan->tx_q, skb))
 +                      chan->tx_send_head = NULL;
                else
 -                      sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
 +                      chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
  
                nsent++;
        }
        return nsent;
  }
  
 -static int l2cap_retransmit_frames(struct sock *sk)
 +static int l2cap_retransmit_frames(struct l2cap_chan *chan)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        int ret;
  
 -      if (!skb_queue_empty(TX_QUEUE(sk)))
 -              sk->sk_send_head = TX_QUEUE(sk)->next;
 +      if (!skb_queue_empty(&chan->tx_q))
 +              chan->tx_send_head = chan->tx_q.next;
  
 -      pi->next_tx_seq = pi->expected_ack_seq;
 -      ret = l2cap_ertm_send(sk);
 +      chan->next_tx_seq = chan->expected_ack_seq;
 +      ret = l2cap_ertm_send(chan);
        return ret;
  }
  
 -static void l2cap_send_ack(struct l2cap_pinfo *pi)
 +static void l2cap_send_ack(struct l2cap_chan *chan)
  {
 -      struct sock *sk = (struct sock *)pi;
        u16 control = 0;
  
 -      control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +      control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
 -              pi->conn_state |= L2CAP_CONN_RNR_SENT;
 -              l2cap_send_sframe(pi, control);
 +              chan->conn_state |= L2CAP_CONN_RNR_SENT;
 +              l2cap_send_sframe(chan, control);
                return;
        }
  
 -      if (l2cap_ertm_send(sk) > 0)
 +      if (l2cap_ertm_send(chan) > 0)
                return;
  
        control |= L2CAP_SUPER_RCV_READY;
 -      l2cap_send_sframe(pi, control);
 +      l2cap_send_sframe(chan, control);
  }
  
 -static void l2cap_send_srejtail(struct sock *sk)
 +static void l2cap_send_srejtail(struct l2cap_chan *chan)
  {
        struct srej_list *tail;
        u16 control;
        control = L2CAP_SUPER_SELECT_REJECT;
        control |= L2CAP_CTRL_FINAL;
  
 -      tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
 +      tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
        control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      l2cap_send_sframe(l2cap_pi(sk), control);
 +      l2cap_send_sframe(chan, control);
  }
  
  static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
@@@ -1341,9 -1315,9 +1342,9 @@@ struct sk_buff *l2cap_create_iframe_pdu
        return skb;
  }
  
 -int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
 +int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct sock *sk = chan->sk;
        struct sk_buff *skb;
        struct sk_buff_head sar_queue;
        u16 control;
  
        skb_queue_head_init(&sar_queue);
        control = L2CAP_SDU_START;
 -      skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
 +      skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
  
        __skb_queue_tail(&sar_queue, skb);
 -      len -= pi->remote_mps;
 -      size += pi->remote_mps;
 +      len -= chan->remote_mps;
 +      size += chan->remote_mps;
  
        while (len > 0) {
                size_t buflen;
  
 -              if (len > pi->remote_mps) {
 +              if (len > chan->remote_mps) {
                        control = L2CAP_SDU_CONTINUE;
 -                      buflen = pi->remote_mps;
 +                      buflen = chan->remote_mps;
                } else {
                        control = L2CAP_SDU_END;
                        buflen = len;
                len -= buflen;
                size += buflen;
        }
 -      skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
 -      if (sk->sk_send_head == NULL)
 -              sk->sk_send_head = sar_queue.next;
 +      skb_queue_splice_tail(&sar_queue, &chan->tx_q);
 +      if (chan->tx_send_head == NULL)
 +              chan->tx_send_head = sar_queue.next;
  
        return size;
  }
@@@ -1413,14 -1387,14 +1414,14 @@@ static void l2cap_chan_ready(struct soc
  /* Copy frame to all raw sockets on that connection */
  static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
  {
 -      struct l2cap_chan_list *l = &conn->chan_list;
        struct sk_buff *nskb;
 -      struct sock *sk;
 +      struct l2cap_chan *chan;
  
        BT_DBG("conn %p", conn);
  
 -      read_lock(&l->lock);
 -      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 +      read_lock(&conn->chan_lock);
 +      list_for_each_entry(chan, &conn->chan_l, list) {
 +              struct sock *sk = chan->sk;
                if (sk->sk_type != SOCK_RAW)
                        continue;
  
                if (sock_queue_rcv_skb(sk, nskb))
                        kfree_skb(nskb);
        }
 -      read_unlock(&l->lock);
 +      read_unlock(&conn->chan_lock);
  }
  
  /* ---- L2CAP signalling commands ---- */
@@@ -1566,35 -1540,32 +1567,35 @@@ static void l2cap_add_conf_opt(void **p
  
  static void l2cap_ack_timeout(unsigned long arg)
  {
 -      struct sock *sk = (void *) arg;
 +      struct l2cap_chan *chan = (void *) arg;
  
 -      bh_lock_sock(sk);
 -      l2cap_send_ack(l2cap_pi(sk));
 -      bh_unlock_sock(sk);
 +      bh_lock_sock(chan->sk);
 +      l2cap_send_ack(chan);
 +      bh_unlock_sock(chan->sk);
  }
  
 -static inline void l2cap_ertm_init(struct sock *sk)
 +static inline void l2cap_ertm_init(struct l2cap_chan *chan)
  {
 -      l2cap_pi(sk)->expected_ack_seq = 0;
 -      l2cap_pi(sk)->unacked_frames = 0;
 -      l2cap_pi(sk)->buffer_seq = 0;
 -      l2cap_pi(sk)->num_acked = 0;
 -      l2cap_pi(sk)->frames_sent = 0;
 +      struct sock *sk = chan->sk;
 +
 +      chan->expected_ack_seq = 0;
 +      chan->unacked_frames = 0;
 +      chan->buffer_seq = 0;
 +      chan->num_acked = 0;
 +      chan->frames_sent = 0;
  
 -      setup_timer(&l2cap_pi(sk)->retrans_timer,
 -                      l2cap_retrans_timeout, (unsigned long) sk);
 -      setup_timer(&l2cap_pi(sk)->monitor_timer,
 -                      l2cap_monitor_timeout, (unsigned long) sk);
 -      setup_timer(&l2cap_pi(sk)->ack_timer,
 -                      l2cap_ack_timeout, (unsigned long) sk);
 +      setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
 +                                                      (unsigned long) chan);
 +      setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
 +                                                      (unsigned long) chan);
 +      setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
  
 -      __skb_queue_head_init(SREJ_QUEUE(sk));
 -      __skb_queue_head_init(BUSY_QUEUE(sk));
 +      skb_queue_head_init(&chan->srej_q);
 +      skb_queue_head_init(&chan->busy_q);
  
 -      INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
 +      INIT_LIST_HEAD(&chan->srej_l);
 +
 +      INIT_WORK(&chan->busy_work, l2cap_busy_work);
  
        sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
  }
@@@ -1612,16 -1583,16 +1613,16 @@@ static inline __u8 l2cap_select_mode(__
        }
  }
  
 -int l2cap_build_conf_req(struct sock *sk, void *data)
 +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct l2cap_conf_req *req = data;
        struct l2cap_conf_rfc rfc = { .mode = pi->mode };
        void *ptr = req->data;
  
 -      BT_DBG("sk %p", sk);
 +      BT_DBG("chan %p", chan);
  
 -      if (pi->num_conf_req || pi->num_conf_rsp)
 +      if (chan->num_conf_req || chan->num_conf_rsp)
                goto done;
  
        switch (pi->mode) {
@@@ -1710,20 -1681,20 +1711,20 @@@ done
        return ptr - data;
  }
  
 -static int l2cap_parse_conf_req(struct sock *sk, void *data)
 +static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct l2cap_conf_rsp *rsp = data;
        void *ptr = rsp->data;
 -      void *req = pi->conf_req;
 -      int len = pi->conf_len;
 +      void *req = chan->conf_req;
 +      int len = chan->conf_len;
        int type, hint, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
        u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
  
 -      BT_DBG("sk %p", sk);
 +      BT_DBG("chan %p", chan);
  
        while (len >= L2CAP_CONF_OPT_SIZE) {
                len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
                }
        }
  
 -      if (pi->num_conf_rsp || pi->num_conf_req > 1)
 +      if (chan->num_conf_rsp || chan->num_conf_req > 1)
                goto done;
  
        switch (pi->mode) {
@@@ -1787,7 -1758,7 +1788,7 @@@ done
                result = L2CAP_CONF_UNACCEPT;
                rfc.mode = pi->mode;
  
 -              if (pi->num_conf_rsp == 1)
 +              if (chan->num_conf_rsp == 1)
                        return -ECONNREFUSED;
  
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                        break;
  
                case L2CAP_MODE_ERTM:
 -                      pi->remote_tx_win = rfc.txwin_size;
 -                      pi->remote_max_tx = rfc.max_transmit;
 +                      chan->remote_tx_win = rfc.txwin_size;
 +                      chan->remote_max_tx = rfc.max_transmit;
  
                        if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
                                rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
  
 -                      pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 +                      chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
  
                        rfc.retrans_timeout =
                                le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
                        if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
                                rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
  
 -                      pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 +                      chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
  
                        pi->conf_state |= L2CAP_CONF_MODE_DONE;
  
@@@ -1947,31 -1918,6 +1948,31 @@@ static int l2cap_build_conf_rsp(struct 
        return ptr - data;
  }
  
 +void __l2cap_connect_rsp_defer(struct sock *sk)
 +{
 +      struct l2cap_conn_rsp rsp;
 +      struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 +      struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 +      u8 buf[128];
 +
 +      sk->sk_state = BT_CONFIG;
 +
 +      rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
 +      rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
 +      rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 +      rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 +      l2cap_send_cmd(conn, chan->ident,
 +                              L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 +
 +      if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
 +              return;
 +
 +      l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 +      l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 +                      l2cap_build_conf_req(chan, buf), buf);
 +      chan->num_conf_req++;
 +}
 +
  static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
  {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
@@@ -2029,9 -1975,9 +2030,9 @@@ static inline int l2cap_command_rej(str
  
  static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
  {
 -      struct l2cap_chan_list *list = &conn->chan_list;
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
 +      struct l2cap_chan *chan = NULL;
        struct sock *parent, *sk = NULL;
        int result, status = L2CAP_CS_NO_INFO;
  
        if (!sk)
                goto response;
  
 -      write_lock_bh(&list->lock);
 +      chan = l2cap_chan_alloc(sk);
 +      if (!chan) {
 +              l2cap_sock_kill(sk);
 +              goto response;
 +      }
 +
 +      write_lock_bh(&conn->chan_lock);
  
        /* Check if we already have channel with that dcid */
 -      if (__l2cap_get_chan_by_dcid(list, scid)) {
 -              write_unlock_bh(&list->lock);
 +      if (__l2cap_get_chan_by_dcid(conn, scid)) {
 +              write_unlock_bh(&conn->chan_lock);
                sock_set_flag(sk, SOCK_ZAPPED);
                l2cap_sock_kill(sk);
                goto response;
        l2cap_pi(sk)->psm  = psm;
        l2cap_pi(sk)->dcid = scid;
  
 -      __l2cap_chan_add(conn, sk, parent);
 +      bt_accept_enqueue(parent, sk);
 +
 +      __l2cap_chan_add(conn, chan);
 +
 +      l2cap_pi(sk)->chan = chan;
 +
        dcid = l2cap_pi(sk)->scid;
  
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
  
 -      l2cap_pi(sk)->ident = cmd->ident;
 +      chan->ident = cmd->ident;
  
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
                if (l2cap_check_security(sk)) {
                status = L2CAP_CS_NO_INFO;
        }
  
 -      write_unlock_bh(&list->lock);
 +      write_unlock_bh(&conn->chan_lock);
  
  response:
        bh_unlock_sock(parent);
@@@ -2154,13 -2089,13 +2155,13 @@@ sendresp
                                        L2CAP_INFO_REQ, sizeof(info), &info);
        }
  
 -      if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
 +      if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
                                result == L2CAP_CR_SUCCESS) {
                u8 buf[128];
                l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 -                                      l2cap_build_conf_req(sk, buf), buf);
 -              l2cap_pi(sk)->num_conf_req++;
 +                                      l2cap_build_conf_req(chan, buf), buf);
 +              chan->num_conf_req++;
        }
  
        return 0;
@@@ -2170,7 -2105,6 +2171,7 @@@ static inline int l2cap_connect_rsp(str
  {
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
 +      struct l2cap_chan *chan;
        struct sock *sk;
        u8 req[128];
  
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
  
        if (scid) {
 -              sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
 -              if (!sk)
 +              chan = l2cap_get_chan_by_scid(conn, scid);
 +              if (!chan)
                        return -EFAULT;
        } else {
 -              sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
 -              if (!sk)
 +              chan = l2cap_get_chan_by_ident(conn, cmd->ident);
 +              if (!chan)
                        return -EFAULT;
        }
  
 +      sk = chan->sk;
 +
        switch (result) {
        case L2CAP_CR_SUCCESS:
                sk->sk_state = BT_CONFIG;
 -              l2cap_pi(sk)->ident = 0;
 +              chan->ident = 0;
                l2cap_pi(sk)->dcid = dcid;
                l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
  
                l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
  
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 -                                      l2cap_build_conf_req(sk, req), req);
 -              l2cap_pi(sk)->num_conf_req++;
 +                                      l2cap_build_conf_req(chan, req), req);
 +              chan->num_conf_req++;
                break;
  
        case L2CAP_CR_PEND:
                        break;
                }
  
 -              l2cap_chan_del(sk, ECONNREFUSED);
 +              l2cap_chan_del(chan, ECONNREFUSED);
                break;
        }
  
@@@ -2247,7 -2179,6 +2248,7 @@@ static inline int l2cap_config_req(stru
        struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
        u16 dcid, flags;
        u8 rsp[64];
 +      struct l2cap_chan *chan;
        struct sock *sk;
        int len;
  
  
        BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
  
 -      sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
 -      if (!sk)
 +      chan = l2cap_get_chan_by_scid(conn, dcid);
 +      if (!chan)
                return -ENOENT;
  
 +      sk = chan->sk;
 +
        if (sk->sk_state != BT_CONFIG) {
                struct l2cap_cmd_rej rej;
  
  
        /* Reject if config buffer is too small. */
        len = cmd_len - sizeof(*req);
 -      if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
 +      if (chan->conf_len + len > sizeof(chan->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                l2cap_build_conf_rsp(sk, rsp,
                                        L2CAP_CONF_REJECT, flags), rsp);
        }
  
        /* Store config. */
 -      memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len);
 -      l2cap_pi(sk)->conf_len += len;
 +      memcpy(chan->conf_req + chan->conf_len, req->data, len);
 +      chan->conf_len += len;
  
        if (flags & 0x0001) {
                /* Incomplete config. Send empty response. */
        }
  
        /* Complete config. */
 -      len = l2cap_parse_conf_req(sk, rsp);
 +      len = l2cap_parse_conf_req(chan, rsp);
        if (len < 0) {
 -              l2cap_send_disconn_req(conn, sk, ECONNRESET);
 +              l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto unlock;
        }
  
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
 -      l2cap_pi(sk)->num_conf_rsp++;
 +      chan->num_conf_rsp++;
  
        /* Reset config buffer. */
 -      l2cap_pi(sk)->conf_len = 0;
 +      chan->conf_len = 0;
  
        if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
                goto unlock;
  
                sk->sk_state = BT_CONNECTED;
  
 -              l2cap_pi(sk)->next_tx_seq = 0;
 -              l2cap_pi(sk)->expected_tx_seq = 0;
 -              __skb_queue_head_init(TX_QUEUE(sk));
 +              chan->next_tx_seq = 0;
 +              chan->expected_tx_seq = 0;
 +              skb_queue_head_init(&chan->tx_q);
                if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
 -                      l2cap_ertm_init(sk);
 +                      l2cap_ertm_init(chan);
  
                l2cap_chan_ready(sk);
                goto unlock;
                u8 buf[64];
                l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
 -                                      l2cap_build_conf_req(sk, buf), buf);
 -              l2cap_pi(sk)->num_conf_req++;
 +                                      l2cap_build_conf_req(chan, buf), buf);
 +              chan->num_conf_req++;
        }
  
  unlock:
@@@ -2340,7 -2269,6 +2341,7 @@@ static inline int l2cap_config_rsp(stru
  {
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
 +      struct l2cap_chan *chan;
        struct sock *sk;
        int len = cmd->len - sizeof(*rsp);
  
        BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
                        scid, flags, result);
  
 -      sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
 -      if (!sk)
 +      chan = l2cap_get_chan_by_scid(conn, scid);
 +      if (!chan)
                return 0;
  
 +      sk = chan->sk;
 +
        switch (result) {
        case L2CAP_CONF_SUCCESS:
                l2cap_conf_rfc_get(sk, rsp->data, len);
                break;
  
        case L2CAP_CONF_UNACCEPT:
 -              if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
 +              if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
                        char req[64];
  
                        if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
 -                              l2cap_send_disconn_req(conn, sk, ECONNRESET);
 +                              l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
                        }
  
                        len = l2cap_parse_conf_rsp(sk, rsp->data,
                                                        len, req, &result);
                        if (len < 0) {
 -                              l2cap_send_disconn_req(conn, sk, ECONNRESET);
 +                              l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
                        }
  
                        l2cap_send_cmd(conn, l2cap_get_ident(conn),
                                                L2CAP_CONF_REQ, len, req);
 -                      l2cap_pi(sk)->num_conf_req++;
 +                      chan->num_conf_req++;
                        if (result != L2CAP_CONF_SUCCESS)
                                goto done;
                        break;
        default:
                sk->sk_err = ECONNRESET;
                l2cap_sock_set_timer(sk, HZ * 5);
 -              l2cap_send_disconn_req(conn, sk, ECONNRESET);
 +              l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
  
                set_default_fcs(l2cap_pi(sk));
  
                sk->sk_state = BT_CONNECTED;
 -              l2cap_pi(sk)->next_tx_seq = 0;
 -              l2cap_pi(sk)->expected_tx_seq = 0;
 -              __skb_queue_head_init(TX_QUEUE(sk));
 +              chan->next_tx_seq = 0;
 +              chan->expected_tx_seq = 0;
 +              skb_queue_head_init(&chan->tx_q);
                if (l2cap_pi(sk)->mode ==  L2CAP_MODE_ERTM)
 -                      l2cap_ertm_init(sk);
 +                      l2cap_ertm_init(chan);
  
                l2cap_chan_ready(sk);
        }
@@@ -2423,7 -2349,6 +2424,7 @@@ static inline int l2cap_disconnect_req(
        struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
        struct l2cap_disconn_rsp rsp;
        u16 dcid, scid;
 +      struct l2cap_chan *chan;
        struct sock *sk;
  
        scid = __le16_to_cpu(req->scid);
  
        BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
  
 -      sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
 -      if (!sk)
 +      chan = l2cap_get_chan_by_scid(conn, dcid);
 +      if (!chan)
                return 0;
  
 +      sk = chan->sk;
 +
        rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
        rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
        l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
                return 0;
        }
  
 -      l2cap_chan_del(sk, ECONNRESET);
 +      l2cap_chan_del(chan, ECONNRESET);
        bh_unlock_sock(sk);
  
        l2cap_sock_kill(sk);
@@@ -2463,7 -2386,6 +2464,7 @@@ static inline int l2cap_disconnect_rsp(
  {
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
 +      struct l2cap_chan *chan;
        struct sock *sk;
  
        scid = __le16_to_cpu(rsp->scid);
  
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
  
 -      sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
 -      if (!sk)
 +      chan = l2cap_get_chan_by_scid(conn, scid);
 +      if (!chan)
                return 0;
  
 +      sk = chan->sk;
 +
        /* don't delete l2cap channel if sk is owned by user */
        if (sock_owned_by_user(sk)) {
                sk->sk_state = BT_DISCONN;
                return 0;
        }
  
 -      l2cap_chan_del(sk, 0);
 +      l2cap_chan_del(chan, 0);
        bh_unlock_sock(sk);
  
        l2cap_sock_kill(sk);
@@@ -2543,11 -2463,6 +2544,11 @@@ static inline int l2cap_information_rsp
  
        BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
  
 +      /* L2CAP Info req/rsp are unbound to channels, add extra checks */
 +      if (cmd->ident != conn->info_ident ||
 +                      conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
 +              return 0;
 +
        del_timer(&conn->info_timer);
  
        if (result != L2CAP_IR_SUCCESS) {
@@@ -2758,8 -2673,7 +2759,8 @@@ static inline void l2cap_sig_channel(st
  
                if (err) {
                        struct l2cap_cmd_rej rej;
 -                      BT_DBG("error %d", err);
 +
 +                      BT_ERR("Wrong link type (%d)", err);
  
                        /* FIXME: Map err to a valid reason */
                        rej.reason = cpu_to_le16(0);
@@@ -2789,47 -2703,49 +2790,47 @@@ static int l2cap_check_fcs(struct l2cap
        return 0;
  }
  
 -static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
 +static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control = 0;
  
 -      pi->frames_sent = 0;
 +      chan->frames_sent = 0;
  
 -      control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +      control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
 -              l2cap_send_sframe(pi, control);
 -              pi->conn_state |= L2CAP_CONN_RNR_SENT;
 +              l2cap_send_sframe(chan, control);
 +              chan->conn_state |= L2CAP_CONN_RNR_SENT;
        }
  
 -      if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
 -              l2cap_retransmit_frames(sk);
 +      if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
 +              l2cap_retransmit_frames(chan);
  
 -      l2cap_ertm_send(sk);
 +      l2cap_ertm_send(chan);
  
 -      if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
 -                      pi->frames_sent == 0) {
 +      if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
 +                      chan->frames_sent == 0) {
                control |= L2CAP_SUPER_RCV_READY;
 -              l2cap_send_sframe(pi, control);
 +              l2cap_send_sframe(chan, control);
        }
  }
  
 -static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
 +static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
  {
        struct sk_buff *next_skb;
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        int tx_seq_offset, next_tx_seq_offset;
  
        bt_cb(skb)->tx_seq = tx_seq;
        bt_cb(skb)->sar = sar;
  
 -      next_skb = skb_peek(SREJ_QUEUE(sk));
 +      next_skb = skb_peek(&chan->srej_q);
        if (!next_skb) {
 -              __skb_queue_tail(SREJ_QUEUE(sk), skb);
 +              __skb_queue_tail(&chan->srej_q, skb);
                return 0;
        }
  
 -      tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
 +      tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
        if (tx_seq_offset < 0)
                tx_seq_offset += 64;
  
                        return -EINVAL;
  
                next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
 -                                              pi->buffer_seq) % 64;
 +                                              chan->buffer_seq) % 64;
                if (next_tx_seq_offset < 0)
                        next_tx_seq_offset += 64;
  
                if (next_tx_seq_offset > tx_seq_offset) {
 -                      __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
 +                      __skb_queue_before(&chan->srej_q, next_skb, skb);
                        return 0;
                }
  
 -              if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb))
 +              if (skb_queue_is_last(&chan->srej_q, next_skb))
                        break;
  
 -      } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
 +      } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
  
 -      __skb_queue_tail(SREJ_QUEUE(sk), skb);
 +      __skb_queue_tail(&chan->srej_q, skb);
  
        return 0;
  }
  
 -static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
 +static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct sk_buff *_skb;
        int err;
  
        switch (control & L2CAP_CTRL_SAR) {
        case L2CAP_SDU_UNSEGMENTED:
 -              if (pi->conn_state & L2CAP_CONN_SAR_SDU)
 +              if (chan->conn_state & L2CAP_CONN_SAR_SDU)
                        goto drop;
  
 -              err = sock_queue_rcv_skb(sk, skb);
 +              err = sock_queue_rcv_skb(chan->sk, skb);
                if (!err)
                        return err;
  
                break;
  
        case L2CAP_SDU_START:
 -              if (pi->conn_state & L2CAP_CONN_SAR_SDU)
 +              if (chan->conn_state & L2CAP_CONN_SAR_SDU)
                        goto drop;
  
 -              pi->sdu_len = get_unaligned_le16(skb->data);
 +              chan->sdu_len = get_unaligned_le16(skb->data);
  
 -              if (pi->sdu_len > pi->imtu)
 +              if (chan->sdu_len > pi->imtu)
                        goto disconnect;
  
 -              pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
 -              if (!pi->sdu)
 +              chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
 +              if (!chan->sdu)
                        return -ENOMEM;
  
                /* pull sdu_len bytes only after alloc, because of Local Busy
                 * only once, i.e., when alloc does not fail */
                skb_pull(skb, 2);
  
 -              memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +              memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              pi->conn_state |= L2CAP_CONN_SAR_SDU;
 -              pi->partial_sdu_len = skb->len;
 +              chan->conn_state |= L2CAP_CONN_SAR_SDU;
 +              chan->partial_sdu_len = skb->len;
                break;
  
        case L2CAP_SDU_CONTINUE:
 -              if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
                        goto disconnect;
  
 -              if (!pi->sdu)
 +              if (!chan->sdu)
                        goto disconnect;
  
 -              pi->partial_sdu_len += skb->len;
 -              if (pi->partial_sdu_len > pi->sdu_len)
 +              chan->partial_sdu_len += skb->len;
 +              if (chan->partial_sdu_len > chan->sdu_len)
                        goto drop;
  
 -              memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +              memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
                break;
  
        case L2CAP_SDU_END:
 -              if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
                        goto disconnect;
  
 -              if (!pi->sdu)
 +              if (!chan->sdu)
                        goto disconnect;
  
 -              if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
 -                      pi->partial_sdu_len += skb->len;
 +              if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
 +                      chan->partial_sdu_len += skb->len;
  
 -                      if (pi->partial_sdu_len > pi->imtu)
 +                      if (chan->partial_sdu_len > pi->imtu)
                                goto drop;
  
 -                      if (pi->partial_sdu_len != pi->sdu_len)
 +                      if (chan->partial_sdu_len != chan->sdu_len)
                                goto drop;
  
 -                      memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +                      memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
                }
  
 -              _skb = skb_clone(pi->sdu, GFP_ATOMIC);
 +              _skb = skb_clone(chan->sdu, GFP_ATOMIC);
                if (!_skb) {
 -                      pi->conn_state |= L2CAP_CONN_SAR_RETRY;
 +                      chan->conn_state |= L2CAP_CONN_SAR_RETRY;
                        return -ENOMEM;
                }
  
 -              err = sock_queue_rcv_skb(sk, _skb);
 +              err = sock_queue_rcv_skb(chan->sk, _skb);
                if (err < 0) {
                        kfree_skb(_skb);
 -                      pi->conn_state |= L2CAP_CONN_SAR_RETRY;
 +                      chan->conn_state |= L2CAP_CONN_SAR_RETRY;
                        return err;
                }
  
 -              pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
 -              pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
 +              chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
 +              chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
  
 -              kfree_skb(pi->sdu);
 +              kfree_skb(chan->sdu);
                break;
        }
  
        return 0;
  
  drop:
 -      kfree_skb(pi->sdu);
 -      pi->sdu = NULL;
 +      kfree_skb(chan->sdu);
 +      chan->sdu = NULL;
  
  disconnect:
 -      l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +      l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
        kfree_skb(skb);
        return 0;
  }
  
 -static int l2cap_try_push_rx_skb(struct sock *sk)
 +static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct sk_buff *skb;
        u16 control;
        int err;
  
 -      while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
 +      while ((skb = skb_dequeue(&chan->busy_q))) {
                control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
 -              err = l2cap_ertm_reassembly_sdu(sk, skb, control);
 +              err = l2cap_ertm_reassembly_sdu(chan, skb, control);
                if (err < 0) {
 -                      skb_queue_head(BUSY_QUEUE(sk), skb);
 +                      skb_queue_head(&chan->busy_q, skb);
                        return -EBUSY;
                }
  
 -              pi->buffer_seq = (pi->buffer_seq + 1) % 64;
 +              chan->buffer_seq = (chan->buffer_seq + 1) % 64;
        }
  
 -      if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
 +      if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
                goto done;
  
 -      control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +      control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
        control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
 -      l2cap_send_sframe(pi, control);
 -      l2cap_pi(sk)->retry_count = 1;
 +      l2cap_send_sframe(chan, control);
 +      chan->retry_count = 1;
  
 -      del_timer(&pi->retrans_timer);
 +      del_timer(&chan->retrans_timer);
        __mod_monitor_timer();
  
 -      l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
 +      chan->conn_state |= L2CAP_CONN_WAIT_F;
  
  done:
 -      pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
 -      pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
 +      chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
 +      chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
  
 -      BT_DBG("sk %p, Exit local busy", sk);
 +      BT_DBG("chan %p, Exit local busy", chan);
  
        return 0;
  }
  static void l2cap_busy_work(struct work_struct *work)
  {
        DECLARE_WAITQUEUE(wait, current);
 -      struct l2cap_pinfo *pi =
 -              container_of(work, struct l2cap_pinfo, busy_work);
 -      struct sock *sk = (struct sock *)pi;
 +      struct l2cap_chan *chan =
 +              container_of(work, struct l2cap_chan, busy_work);
 +      struct sock *sk = chan->sk;
        int n_tries = 0, timeo = HZ/5, err;
        struct sk_buff *skb;
  
        lock_sock(sk);
  
        add_wait_queue(sk_sleep(sk), &wait);
 -      while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
 +      while ((skb = skb_peek(&chan->busy_q))) {
                set_current_state(TASK_INTERRUPTIBLE);
  
                if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
                        err = -EBUSY;
 -                      l2cap_send_disconn_req(pi->conn, sk, EBUSY);
 +                      l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY);
                        break;
                }
  
                if (err)
                        break;
  
 -              if (l2cap_try_push_rx_skb(sk) == 0)
 +              if (l2cap_try_push_rx_skb(chan) == 0)
                        break;
        }
  
        release_sock(sk);
  }
  
 -static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
 +static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        int sctrl, err;
  
 -      if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
                bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
 -              __skb_queue_tail(BUSY_QUEUE(sk), skb);
 -              return l2cap_try_push_rx_skb(sk);
 +              __skb_queue_tail(&chan->busy_q, skb);
 +              return l2cap_try_push_rx_skb(chan);
  
  
        }
  
 -      err = l2cap_ertm_reassembly_sdu(sk, skb, control);
 +      err = l2cap_ertm_reassembly_sdu(chan, skb, control);
        if (err >= 0) {
 -              pi->buffer_seq = (pi->buffer_seq + 1) % 64;
 +              chan->buffer_seq = (chan->buffer_seq + 1) % 64;
                return err;
        }
  
        /* Busy Condition */
 -      BT_DBG("sk %p, Enter local busy", sk);
 +      BT_DBG("chan %p, Enter local busy", chan);
  
 -      pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
 +      chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
        bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
 -      __skb_queue_tail(BUSY_QUEUE(sk), skb);
 +      __skb_queue_tail(&chan->busy_q, skb);
  
 -      sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +      sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
        sctrl |= L2CAP_SUPER_RCV_NOT_READY;
 -      l2cap_send_sframe(pi, sctrl);
 +      l2cap_send_sframe(chan, sctrl);
  
 -      pi->conn_state |= L2CAP_CONN_RNR_SENT;
 +      chan->conn_state |= L2CAP_CONN_RNR_SENT;
  
 -      del_timer(&pi->ack_timer);
 +      del_timer(&chan->ack_timer);
  
 -      queue_work(_busy_wq, &pi->busy_work);
 +      queue_work(_busy_wq, &chan->busy_work);
  
        return err;
  }
  
 -static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
 +static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct sk_buff *_skb;
        int err = -EINVAL;
  
  
        switch (control & L2CAP_CTRL_SAR) {
        case L2CAP_SDU_UNSEGMENTED:
 -              if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
 -                      kfree_skb(pi->sdu);
 +              if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
 +                      kfree_skb(chan->sdu);
                        break;
                }
  
 -              err = sock_queue_rcv_skb(sk, skb);
 +              err = sock_queue_rcv_skb(chan->sk, skb);
                if (!err)
                        return 0;
  
                break;
  
        case L2CAP_SDU_START:
 -              if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
 -                      kfree_skb(pi->sdu);
 +              if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
 +                      kfree_skb(chan->sdu);
                        break;
                }
  
 -              pi->sdu_len = get_unaligned_le16(skb->data);
 +              chan->sdu_len = get_unaligned_le16(skb->data);
                skb_pull(skb, 2);
  
 -              if (pi->sdu_len > pi->imtu) {
 +              if (chan->sdu_len > pi->imtu) {
                        err = -EMSGSIZE;
                        break;
                }
  
 -              pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
 -              if (!pi->sdu) {
 +              chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
 +              if (!chan->sdu) {
                        err = -ENOMEM;
                        break;
                }
  
 -              memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +              memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              pi->conn_state |= L2CAP_CONN_SAR_SDU;
 -              pi->partial_sdu_len = skb->len;
 +              chan->conn_state |= L2CAP_CONN_SAR_SDU;
 +              chan->partial_sdu_len = skb->len;
                err = 0;
                break;
  
        case L2CAP_SDU_CONTINUE:
 -              if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
                        break;
  
 -              memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +              memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              pi->partial_sdu_len += skb->len;
 -              if (pi->partial_sdu_len > pi->sdu_len)
 -                      kfree_skb(pi->sdu);
 +              chan->partial_sdu_len += skb->len;
 +              if (chan->partial_sdu_len > chan->sdu_len)
 +                      kfree_skb(chan->sdu);
                else
                        err = 0;
  
                break;
  
        case L2CAP_SDU_END:
 -              if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
                        break;
  
 -              memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 +              memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
 -              pi->partial_sdu_len += skb->len;
 +              chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
 +              chan->partial_sdu_len += skb->len;
  
 -              if (pi->partial_sdu_len > pi->imtu)
 +              if (chan->partial_sdu_len > pi->imtu)
                        goto drop;
  
 -              if (pi->partial_sdu_len == pi->sdu_len) {
 -                      _skb = skb_clone(pi->sdu, GFP_ATOMIC);
 -                      err = sock_queue_rcv_skb(sk, _skb);
 +              if (chan->partial_sdu_len == chan->sdu_len) {
 +                      _skb = skb_clone(chan->sdu, GFP_ATOMIC);
 +                      err = sock_queue_rcv_skb(chan->sk, _skb);
                        if (err < 0)
                                kfree_skb(_skb);
                }
                err = 0;
  
  drop:
 -              kfree_skb(pi->sdu);
 +              kfree_skb(chan->sdu);
                break;
        }
  
        return err;
  }
  
 -static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
 +static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
  {
        struct sk_buff *skb;
        u16 control;
  
 -      while ((skb = skb_peek(SREJ_QUEUE(sk)))) {
 +      while ((skb = skb_peek(&chan->srej_q))) {
                if (bt_cb(skb)->tx_seq != tx_seq)
                        break;
  
 -              skb = skb_dequeue(SREJ_QUEUE(sk));
 +              skb = skb_dequeue(&chan->srej_q);
                control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
 -              l2cap_ertm_reassembly_sdu(sk, skb, control);
 -              l2cap_pi(sk)->buffer_seq_srej =
 -                      (l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
 +              l2cap_ertm_reassembly_sdu(chan, skb, control);
 +              chan->buffer_seq_srej =
 +                      (chan->buffer_seq_srej + 1) % 64;
                tx_seq = (tx_seq + 1) % 64;
        }
  }
  
 -static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq)
 +static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct srej_list *l, *tmp;
        u16 control;
  
 -      list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
 +      list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                if (l->tx_seq == tx_seq) {
                        list_del(&l->list);
                        kfree(l);
                }
                control = L2CAP_SUPER_SELECT_REJECT;
                control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 -              l2cap_send_sframe(pi, control);
 +              l2cap_send_sframe(chan, control);
                list_del(&l->list);
 -              list_add_tail(&l->list, SREJ_LIST(sk));
 +              list_add_tail(&l->list, &chan->srej_l);
        }
  }
  
 -static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq)
 +static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct srej_list *new;
        u16 control;
  
 -      while (tx_seq != pi->expected_tx_seq) {
 +      while (tx_seq != chan->expected_tx_seq) {
                control = L2CAP_SUPER_SELECT_REJECT;
 -              control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 -              l2cap_send_sframe(pi, control);
 +              control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 +              l2cap_send_sframe(chan, control);
  
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
 -              new->tx_seq = pi->expected_tx_seq;
 -              pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 -              list_add_tail(&new->list, SREJ_LIST(sk));
 +              new->tx_seq = chan->expected_tx_seq;
 +              chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
 +              list_add_tail(&new->list, &chan->srej_l);
        }
 -      pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 +      chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
  }
  
 -static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
 +static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 +      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        u8 tx_seq = __get_txseq(rx_control);
        u8 req_seq = __get_reqseq(rx_control);
        u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
        int num_to_ack = (pi->tx_win/6) + 1;
        int err = 0;
  
 -      BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
 -                                                              rx_control);
 +      BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
 +                                                      tx_seq, rx_control);
  
        if (L2CAP_CTRL_FINAL & rx_control &&
 -                      l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
 -              del_timer(&pi->monitor_timer);
 -              if (pi->unacked_frames > 0)
 +                      chan->conn_state & L2CAP_CONN_WAIT_F) {
 +              del_timer(&chan->monitor_timer);
 +              if (chan->unacked_frames > 0)
                        __mod_retrans_timer();
 -              pi->conn_state &= ~L2CAP_CONN_WAIT_F;
 +              chan->conn_state &= ~L2CAP_CONN_WAIT_F;
        }
  
 -      pi->expected_ack_seq = req_seq;
 -      l2cap_drop_acked_frames(sk);
 +      chan->expected_ack_seq = req_seq;
 +      l2cap_drop_acked_frames(chan);
  
 -      if (tx_seq == pi->expected_tx_seq)
 +      if (tx_seq == chan->expected_tx_seq)
                goto expected;
  
 -      tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
 +      tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
        if (tx_seq_offset < 0)
                tx_seq_offset += 64;
  
        /* invalid tx_seq */
        if (tx_seq_offset >= pi->tx_win) {
 -              l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +              l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
                goto drop;
        }
  
 -      if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY)
 +      if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
                goto drop;
  
 -      if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
 +      if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
                struct srej_list *first;
  
 -              first = list_first_entry(SREJ_LIST(sk),
 +              first = list_first_entry(&chan->srej_l,
                                struct srej_list, list);
                if (tx_seq == first->tx_seq) {
 -                      l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
 -                      l2cap_check_srej_gap(sk, tx_seq);
 +                      l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 +                      l2cap_check_srej_gap(chan, tx_seq);
  
                        list_del(&first->list);
                        kfree(first);
  
 -                      if (list_empty(SREJ_LIST(sk))) {
 -                              pi->buffer_seq = pi->buffer_seq_srej;
 -                              pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
 -                              l2cap_send_ack(pi);
 -                              BT_DBG("sk %p, Exit SREJ_SENT", sk);
 +                      if (list_empty(&chan->srej_l)) {
 +                              chan->buffer_seq = chan->buffer_seq_srej;
 +                              chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
 +                              l2cap_send_ack(chan);
 +                              BT_DBG("chan %p, Exit SREJ_SENT", chan);
                        }
                } else {
                        struct srej_list *l;
  
                        /* duplicated tx_seq */
 -                      if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0)
 +                      if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
                                goto drop;
  
 -                      list_for_each_entry(l, SREJ_LIST(sk), list) {
 +                      list_for_each_entry(l, &chan->srej_l, list) {
                                if (l->tx_seq == tx_seq) {
 -                                      l2cap_resend_srejframe(sk, tx_seq);
 +                                      l2cap_resend_srejframe(chan, tx_seq);
                                        return 0;
                                }
                        }
 -                      l2cap_send_srejframe(sk, tx_seq);
 +                      l2cap_send_srejframe(chan, tx_seq);
                }
        } else {
                expected_tx_seq_offset =
 -                      (pi->expected_tx_seq - pi->buffer_seq) % 64;
 +                      (chan->expected_tx_seq - chan->buffer_seq) % 64;
                if (expected_tx_seq_offset < 0)
                        expected_tx_seq_offset += 64;
  
                if (tx_seq_offset < expected_tx_seq_offset)
                        goto drop;
  
 -              pi->conn_state |= L2CAP_CONN_SREJ_SENT;
 +              chan->conn_state |= L2CAP_CONN_SREJ_SENT;
  
 -              BT_DBG("sk %p, Enter SREJ", sk);
 +              BT_DBG("chan %p, Enter SREJ", chan);
  
 -              INIT_LIST_HEAD(SREJ_LIST(sk));
 -              pi->buffer_seq_srej = pi->buffer_seq;
 +              INIT_LIST_HEAD(&chan->srej_l);
 +              chan->buffer_seq_srej = chan->buffer_seq;
  
 -              __skb_queue_head_init(SREJ_QUEUE(sk));
 -              __skb_queue_head_init(BUSY_QUEUE(sk));
 -              l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
 +              __skb_queue_head_init(&chan->srej_q);
 +              __skb_queue_head_init(&chan->busy_q);
 +              l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
  
 -              pi->conn_state |= L2CAP_CONN_SEND_PBIT;
 +              chan->conn_state |= L2CAP_CONN_SEND_PBIT;
  
 -              l2cap_send_srejframe(sk, tx_seq);
 +              l2cap_send_srejframe(chan, tx_seq);
  
 -              del_timer(&pi->ack_timer);
 +              del_timer(&chan->ack_timer);
        }
        return 0;
  
  expected:
 -      pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 +      chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
  
 -      if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
 +      if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
                bt_cb(skb)->tx_seq = tx_seq;
                bt_cb(skb)->sar = sar;
 -              __skb_queue_tail(SREJ_QUEUE(sk), skb);
 +              __skb_queue_tail(&chan->srej_q, skb);
                return 0;
        }
  
 -      err = l2cap_push_rx_skb(sk, skb, rx_control);
 +      err = l2cap_push_rx_skb(chan, skb, rx_control);
        if (err < 0)
                return 0;
  
        if (rx_control & L2CAP_CTRL_FINAL) {
 -              if (pi->conn_state & L2CAP_CONN_REJ_ACT)
 -                      pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
 +              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 +                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
                else
 -                      l2cap_retransmit_frames(sk);
 +                      l2cap_retransmit_frames(chan);
        }
  
        __mod_ack_timer();
  
 -      pi->num_acked = (pi->num_acked + 1) % num_to_ack;
 -      if (pi->num_acked == num_to_ack - 1)
 -              l2cap_send_ack(pi);
 +      chan->num_acked = (chan->num_acked + 1) % num_to_ack;
 +      if (chan->num_acked == num_to_ack - 1)
 +              l2cap_send_ack(chan);
  
        return 0;
  
        return 0;
  }
  
 -static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
 +static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
 -
 -      BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
 +      BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
                                                rx_control);
  
 -      pi->expected_ack_seq = __get_reqseq(rx_control);
 -      l2cap_drop_acked_frames(sk);
 +      chan->expected_ack_seq = __get_reqseq(rx_control);
 +      l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_POLL) {
 -              pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 -              if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
 -                      if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 -                                      (pi->unacked_frames > 0))
 +              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 +              if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 +                      if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 +                                      (chan->unacked_frames > 0))
                                __mod_retrans_timer();
  
 -                      pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 -                      l2cap_send_srejtail(sk);
 +                      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +                      l2cap_send_srejtail(chan);
                } else {
 -                      l2cap_send_i_or_rr_or_rnr(sk);
 +                      l2cap_send_i_or_rr_or_rnr(chan);
                }
  
        } else if (rx_control & L2CAP_CTRL_FINAL) {
 -              pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +              chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
  
 -              if (pi->conn_state & L2CAP_CONN_REJ_ACT)
 -                      pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
 +              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 +                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
                else
 -                      l2cap_retransmit_frames(sk);
 +                      l2cap_retransmit_frames(chan);
  
        } else {
 -              if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 -                              (pi->unacked_frames > 0))
 +              if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 +                              (chan->unacked_frames > 0))
                        __mod_retrans_timer();
  
 -              pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 -              if (pi->conn_state & L2CAP_CONN_SREJ_SENT)
 -                      l2cap_send_ack(pi);
 +              chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +              if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
 +                      l2cap_send_ack(chan);
                else
 -                      l2cap_ertm_send(sk);
 +                      l2cap_ertm_send(chan);
        }
  }
  
 -static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
 +static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        u8 tx_seq = __get_reqseq(rx_control);
  
 -      BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
 +      BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
  
 -      pi->expected_ack_seq = tx_seq;
 -      l2cap_drop_acked_frames(sk);
 +      chan->expected_ack_seq = tx_seq;
 +      l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_FINAL) {
 -              if (pi->conn_state & L2CAP_CONN_REJ_ACT)
 -                      pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
 +              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 +                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
                else
 -                      l2cap_retransmit_frames(sk);
 +                      l2cap_retransmit_frames(chan);
        } else {
 -              l2cap_retransmit_frames(sk);
 +              l2cap_retransmit_frames(chan);
  
 -              if (pi->conn_state & L2CAP_CONN_WAIT_F)
 -                      pi->conn_state |= L2CAP_CONN_REJ_ACT;
 +              if (chan->conn_state & L2CAP_CONN_WAIT_F)
 +                      chan->conn_state |= L2CAP_CONN_REJ_ACT;
        }
  }
 -static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
 +static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        u8 tx_seq = __get_reqseq(rx_control);
  
 -      BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
 +      BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
  
        if (rx_control & L2CAP_CTRL_POLL) {
 -              pi->expected_ack_seq = tx_seq;
 -              l2cap_drop_acked_frames(sk);
 +              chan->expected_ack_seq = tx_seq;
 +              l2cap_drop_acked_frames(chan);
  
 -              pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 -              l2cap_retransmit_one_frame(sk, tx_seq);
 +              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 +              l2cap_retransmit_one_frame(chan, tx_seq);
  
 -              l2cap_ertm_send(sk);
 +              l2cap_ertm_send(chan);
  
 -              if (pi->conn_state & L2CAP_CONN_WAIT_F) {
 -                      pi->srej_save_reqseq = tx_seq;
 -                      pi->conn_state |= L2CAP_CONN_SREJ_ACT;
 +              if (chan->conn_state & L2CAP_CONN_WAIT_F) {
 +                      chan->srej_save_reqseq = tx_seq;
 +                      chan->conn_state |= L2CAP_CONN_SREJ_ACT;
                }
        } else if (rx_control & L2CAP_CTRL_FINAL) {
 -              if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
 -                              pi->srej_save_reqseq == tx_seq)
 -                      pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
 +              if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
 +                              chan->srej_save_reqseq == tx_seq)
 +                      chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
                else
 -                      l2cap_retransmit_one_frame(sk, tx_seq);
 +                      l2cap_retransmit_one_frame(chan, tx_seq);
        } else {
 -              l2cap_retransmit_one_frame(sk, tx_seq);
 -              if (pi->conn_state & L2CAP_CONN_WAIT_F) {
 -                      pi->srej_save_reqseq = tx_seq;
 -                      pi->conn_state |= L2CAP_CONN_SREJ_ACT;
 +              l2cap_retransmit_one_frame(chan, tx_seq);
 +              if (chan->conn_state & L2CAP_CONN_WAIT_F) {
 +                      chan->srej_save_reqseq = tx_seq;
 +                      chan->conn_state |= L2CAP_CONN_SREJ_ACT;
                }
        }
  }
  
 -static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
 +static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(sk);
        u8 tx_seq = __get_reqseq(rx_control);
  
 -      BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
 +      BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
 -      pi->expected_ack_seq = tx_seq;
 -      l2cap_drop_acked_frames(sk);
 +      chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
 +      chan->expected_ack_seq = tx_seq;
 +      l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_POLL)
 -              pi->conn_state |= L2CAP_CONN_SEND_FBIT;
 +              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
  
 -      if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
 -              del_timer(&pi->retrans_timer);
 +      if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
 +              del_timer(&chan->retrans_timer);
                if (rx_control & L2CAP_CTRL_POLL)
 -                      l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL);
 +                      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
                return;
        }
  
        if (rx_control & L2CAP_CTRL_POLL)
 -              l2cap_send_srejtail(sk);
 +              l2cap_send_srejtail(chan);
        else
 -              l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY);
 +              l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
  }
  
 -static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
 +static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
  {
 -      BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
 +      BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
  
        if (L2CAP_CTRL_FINAL & rx_control &&
 -                      l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
 -              del_timer(&l2cap_pi(sk)->monitor_timer);
 -              if (l2cap_pi(sk)->unacked_frames > 0)
 +                      chan->conn_state & L2CAP_CONN_WAIT_F) {
 +              del_timer(&chan->monitor_timer);
 +              if (chan->unacked_frames > 0)
                        __mod_retrans_timer();
 -              l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F;
 +              chan->conn_state &= ~L2CAP_CONN_WAIT_F;
        }
  
        switch (rx_control & L2CAP_CTRL_SUPERVISE) {
        case L2CAP_SUPER_RCV_READY:
 -              l2cap_data_channel_rrframe(sk, rx_control);
 +              l2cap_data_channel_rrframe(chan, rx_control);
                break;
  
        case L2CAP_SUPER_REJECT:
 -              l2cap_data_channel_rejframe(sk, rx_control);
 +              l2cap_data_channel_rejframe(chan, rx_control);
                break;
  
        case L2CAP_SUPER_SELECT_REJECT:
 -              l2cap_data_channel_srejframe(sk, rx_control);
 +              l2cap_data_channel_srejframe(chan, rx_control);
                break;
  
        case L2CAP_SUPER_RCV_NOT_READY:
 -              l2cap_data_channel_rnrframe(sk, rx_control);
 +              l2cap_data_channel_rnrframe(chan, rx_control);
                break;
        }
  
  
  static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
  {
 +      struct l2cap_chan *chan = l2cap_pi(sk)->chan;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control;
        u8 req_seq;
                len -= 2;
  
        if (len > pi->mps) {
 -              l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +              l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
                goto drop;
        }
  
        req_seq = __get_reqseq(control);
 -      req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
 +      req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
        if (req_seq_offset < 0)
                req_seq_offset += 64;
  
        next_tx_seq_offset =
 -              (pi->next_tx_seq - pi->expected_ack_seq) % 64;
 +              (chan->next_tx_seq - chan->expected_ack_seq) % 64;
        if (next_tx_seq_offset < 0)
                next_tx_seq_offset += 64;
  
        /* check for invalid req-seq */
        if (req_seq_offset > next_tx_seq_offset) {
 -              l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +              l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
                goto drop;
        }
  
        if (__is_iframe(control)) {
                if (len < 0) {
 -                      l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +                      l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
                        goto drop;
                }
  
 -              l2cap_data_channel_iframe(sk, control, skb);
 +              l2cap_data_channel_iframe(chan, control, skb);
        } else {
                if (len != 0) {
                        BT_ERR("%d", len);
 -                      l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
 +                      l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
                        goto drop;
                }
  
 -              l2cap_data_channel_sframe(sk, control, skb);
 +              l2cap_data_channel_sframe(chan, control, skb);
        }
  
        return 0;
@@@ -3608,23 -3532,21 +3609,23 @@@ drop
  
  static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
  {
 +      struct l2cap_chan *chan;
        struct sock *sk;
        struct l2cap_pinfo *pi;
        u16 control;
        u8 tx_seq;
        int len;
  
 -      sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
 -      if (!sk) {
 +      chan = l2cap_get_chan_by_scid(conn, cid);
 +      if (!chan) {
                BT_DBG("unknown cid 0x%4.4x", cid);
                goto drop;
        }
  
 +      sk = chan->sk;
        pi = l2cap_pi(sk);
  
 -      BT_DBG("sk %p, len %d", sk, skb->len);
 +      BT_DBG("chan %p, len %d", chan, skb->len);
  
        if (sk->sk_state != BT_CONNECTED)
                goto drop;
  
                tx_seq = __get_txseq(control);
  
 -              if (pi->expected_tx_seq == tx_seq)
 -                      pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 +              if (chan->expected_tx_seq == tx_seq)
 +                      chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
                else
 -                      pi->expected_tx_seq = (tx_seq + 1) % 64;
 +                      chan->expected_tx_seq = (tx_seq + 1) % 64;
  
 -              l2cap_streaming_reassembly_sdu(sk, skb, control);
 +              l2cap_streaming_reassembly_sdu(chan, skb, control);
  
                goto done;
  
        default:
 -              BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode);
 +              BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode);
                break;
        }
  
@@@ -3726,36 -3648,6 +3727,36 @@@ done
        return 0;
  }
  
 +static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 +{
 +      struct sock *sk;
 +
 +      sk = l2cap_get_sock_by_scid(0, cid, conn->src);
 +      if (!sk)
 +              goto drop;
 +
 +      bh_lock_sock(sk);
 +
 +      BT_DBG("sk %p, len %d", sk, skb->len);
 +
 +      if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
 +              goto drop;
 +
 +      if (l2cap_pi(sk)->imtu < skb->len)
 +              goto drop;
 +
 +      if (!sock_queue_rcv_skb(sk, skb))
 +              goto done;
 +
 +drop:
 +      kfree_skb(skb);
 +
 +done:
 +      if (sk)
 +              bh_unlock_sock(sk);
 +      return 0;
 +}
 +
  static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
  {
        struct l2cap_hdr *lh = (void *) skb->data;
                l2cap_conless_channel(conn, psm, skb);
                break;
  
 +      case L2CAP_CID_LE_DATA:
 +              l2cap_att_channel(conn, cid, skb);
 +              break;
 +
        default:
                l2cap_data_channel(conn, cid, skb);
                break;
@@@ -3892,19 -3780,20 +3893,19 @@@ static inline void l2cap_check_encrypti
  
  static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
  {
 -      struct l2cap_chan_list *l;
        struct l2cap_conn *conn = hcon->l2cap_data;
 -      struct sock *sk;
 +      struct l2cap_chan *chan;
  
        if (!conn)
                return 0;
  
 -      l = &conn->chan_list;
 -
        BT_DBG("conn %p", conn);
  
 -      read_lock(&l->lock);
 +      read_lock(&conn->chan_lock);
 +
 +      list_for_each_entry(chan, &conn->chan_l, list) {
 +              struct sock *sk = chan->sk;
  
 -      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
  
                if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
                                req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                                req.psm  = l2cap_pi(sk)->psm;
  
 -                              l2cap_pi(sk)->ident = l2cap_get_ident(conn);
 +                              chan->ident = l2cap_get_ident(conn);
                                l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
  
 -                              l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 +                              l2cap_send_cmd(conn, chan->ident,
                                        L2CAP_CONN_REQ, sizeof(req), &req);
                        } else {
                                l2cap_sock_clear_timer(sk);
                        rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
                        rsp.result = cpu_to_le16(result);
                        rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 -                      l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 -                                      L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 +                      l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 +                                                      sizeof(rsp), &rsp);
                }
  
                bh_unlock_sock(sk);
        }
  
 -      read_unlock(&l->lock);
 +      read_unlock(&conn->chan_lock);
  
        return 0;
  }
@@@ -3977,7 -3866,7 +3978,7 @@@ static int l2cap_recv_acldata(struct hc
  
        if (!(flags & ACL_CONT)) {
                struct l2cap_hdr *hdr;
 -              struct sock *sk;
 +              struct l2cap_chan *chan;
                u16 cid;
                int len;
  
                        goto drop;
                }
  
 -              sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
 +              chan = l2cap_get_chan_by_scid(conn, cid);
  
 -              if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
 -                      BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)",
 -                                      len, l2cap_pi(sk)->imtu);
 -                      bh_unlock_sock(sk);
 -                      l2cap_conn_unreliable(conn, ECOMM);
 -                      goto drop;
 -              }
 +              if (chan && chan->sk) {
 +                      struct sock *sk = chan->sk;
  
 -              if (sk)
 +                      if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) {
 +                              BT_ERR("Frame exceeding recv MTU (len %d, "
 +                                                      "MTU %d)", len,
 +                                                      l2cap_pi(sk)->imtu);
 +                              bh_unlock_sock(sk);
 +                              l2cap_conn_unreliable(conn, ECOMM);
 +                              goto drop;
 +                      }
                        bh_unlock_sock(sk);
 +              }
  
                /* Allocate skb for the complete frame (with header) */
                conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
diff --combined net/mac80211/cfg.c
@@@ -330,7 -330,6 +330,7 @@@ static void rate_idx_to_bitrate(struct 
  static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
  {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
 +      struct timespec uptime;
  
        sinfo->generation = sdata->local->sta_generation;
  
                        STATION_INFO_TX_FAILED |
                        STATION_INFO_TX_BITRATE |
                        STATION_INFO_RX_BITRATE |
 -                      STATION_INFO_RX_DROP_MISC;
 +                      STATION_INFO_RX_DROP_MISC |
 +                      STATION_INFO_BSS_PARAM |
 +                      STATION_INFO_CONNECTED_TIME;
 +
 +      do_posix_clock_monotonic_gettime(&uptime);
 +      sinfo->connected_time = uptime.tv_sec - sta->last_connected;
  
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
        sinfo->rx_bytes = sta->rx_bytes;
                sinfo->plink_state = sta->plink_state;
  #endif
        }
 +
 +      sinfo->bss_param.flags = 0;
 +      if (sdata->vif.bss_conf.use_cts_prot)
 +              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
 +      if (sdata->vif.bss_conf.use_short_preamble)
 +              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
 +      if (sdata->vif.bss_conf.use_short_slot)
 +              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
 +      sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
 +      sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
  }
  
  
@@@ -691,12 -675,6 +691,12 @@@ static void sta_apply_parameters(struc
                if (set & BIT(NL80211_STA_FLAG_MFP))
                        sta->flags |= WLAN_STA_MFP;
        }
 +
 +      if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
 +              sta->flags &= ~WLAN_STA_AUTH;
 +              if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
 +                      sta->flags |= WLAN_STA_AUTH;
 +      }
        spin_unlock_irqrestore(&sta->flaglock, flags);
  
        /*
@@@ -1045,26 -1023,26 +1045,26 @@@ static int copy_mesh_setup(struct ieee8
        u8 *new_ie;
        const u8 *old_ie;
  
 -      /* first allocate the new vendor information element */
 +      /* allocate information elements */
        new_ie = NULL;
 -      old_ie = ifmsh->vendor_ie;
 +      old_ie = ifmsh->ie;
  
 -      ifmsh->vendor_ie_len = setup->vendor_ie_len;
 -      if (setup->vendor_ie_len) {
 -              new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
 +      if (setup->ie_len) {
 +              new_ie = kmemdup(setup->ie, setup->ie_len,
                                GFP_KERNEL);
                if (!new_ie)
                        return -ENOMEM;
        }
 +      ifmsh->ie_len = setup->ie_len;
 +      ifmsh->ie = new_ie;
 +      kfree(old_ie);
  
        /* now copy the rest of the setup parameters */
        ifmsh->mesh_id_len = setup->mesh_id_len;
        memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
        ifmsh->mesh_pp_id = setup->path_sel_proto;
        ifmsh->mesh_pm_id = setup->path_metric;
 -      ifmsh->vendor_ie = new_ie;
 -
 -      kfree(old_ie);
 +      ifmsh->is_secure = setup->is_secure;
  
        return 0;
  }
@@@ -1526,6 -1504,8 +1526,8 @@@ int __ieee80211_request_smps(struct iee
        enum ieee80211_smps_mode old_req;
        int err;
  
+       lockdep_assert_held(&sdata->u.mgd.mtx);
        old_req = sdata->u.mgd.req_smps;
        sdata->u.mgd.req_smps = smps_mode;