Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
John W. Linville [Mon, 11 Jul 2011 18:46:59 +0000 (14:46 -0400)]
Conflicts:
drivers/net/wireless/ath/ath5k/sysfs.c
net/bluetooth/l2cap_core.c
net/mac80211/wpa.c

1  2 
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/pci.c
drivers/net/wireless/ath/ath5k/sysfs.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/ssb/driver_pcicore.c
net/bluetooth/hci_conn.c
net/bluetooth/l2cap_core.c
net/mac80211/scan.c
net/wireless/nl80211.c
net/wireless/scan.c

@@@ -223,14 -223,14 +223,14 @@@ static int ath5k_eeprom_read_ants(struc
        ah->ah_ant_ctl[mode][AR5K_ANT_CTL] =
            (ee->ee_ant_control[mode][0] << 4);
        ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] =
 -           ee->ee_ant_control[mode][1]        |
 -          (ee->ee_ant_control[mode][2] << 6)  |
 +           ee->ee_ant_control[mode][1]        |
 +          (ee->ee_ant_control[mode][2] << 6)  |
            (ee->ee_ant_control[mode][3] << 12) |
            (ee->ee_ant_control[mode][4] << 18) |
            (ee->ee_ant_control[mode][5] << 24);
        ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] =
 -           ee->ee_ant_control[mode][6]        |
 -          (ee->ee_ant_control[mode][7] << 6)  |
 +           ee->ee_ant_control[mode][6]        |
 +          (ee->ee_ant_control[mode][7] << 6)  |
            (ee->ee_ant_control[mode][8] << 12) |
            (ee->ee_ant_control[mode][9] << 18) |
            (ee->ee_ant_control[mode][10] << 24);
@@@ -255,7 -255,7 +255,7 @@@ static int ath5k_eeprom_read_modes(stru
        ee->ee_n_piers[mode] = 0;
        AR5K_EEPROM_READ(o++, val);
        ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
 -      switch(mode) {
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                ee->ee_ob[mode][3]      = (val >> 5) & 0x7;
                ee->ee_db[mode][3]      = (val >> 2) & 0x7;
        /* Note: >= v5 have bg freq piers on another location
         * so these freq piers are ignored for >= v5 (should be 0xff
         * anyway) */
 -      switch(mode) {
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
                        break;
        if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
                goto done;
  
 -      switch (mode){
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
  
                ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
                ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
  
 -              if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
 +              if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >= 2)
                        ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
                break;
        case AR5K_EEPROM_MODE_11G:
@@@ -516,7 -516,7 +516,7 @@@ ath5k_eeprom_read_freq_list(struct ath5
        u16 val;
  
        ee->ee_n_piers[mode] = 0;
 -      while(i < max) {
 +      while (i < max) {
                AR5K_EEPROM_READ(o++, val);
  
                freq1 = val & 0xff;
@@@ -602,7 -602,7 +602,7 @@@ ath5k_eeprom_init_11bg_2413(struct ath5
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        struct ath5k_chan_pcal_info *pcal;
  
 -      switch(mode) {
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11B:
                pcal = ee->ee_pwr_cal_b;
                break;
  static inline void
  ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
  {
 -      static const u16 intercepts3[] =
 -              { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
 -      static const u16 intercepts3_2[] =
 -              { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
 +      static const u16 intercepts3[] = {
 +              0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100
 +      };
 +      static const u16 intercepts3_2[] = {
 +              0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
 +      };
        const u16 *ip;
        int i;
  
@@@ -693,14 -691,12 +693,12 @@@ ath5k_eeprom_free_pcal_info(struct ath5
                if (!chinfo[pier].pd_curves)
                        continue;
  
-               for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+               for (pdg = 0; pdg < AR5K_EEPROM_N_PD_CURVES; pdg++) {
                        struct ath5k_pdgain_info *pd =
                                        &chinfo[pier].pd_curves[pdg];
  
-                       if (pd != NULL) {
-                               kfree(pd->pd_step);
-                               kfree(pd->pd_pwr);
-                       }
+                       kfree(pd->pd_step);
+                       kfree(pd->pd_pwr);
                }
  
                kfree(chinfo[pier].pd_curves);
@@@ -800,7 -796,7 +798,7 @@@ ath5k_eeprom_read_pcal_info_5111(struc
        u16 val;
  
        offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
 -      switch(mode) {
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
                        return 0;
@@@ -1167,7 -1163,7 +1165,7 @@@ ath5k_cal_data_offset_2413(struct ath5k
  {
        u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
  
 -      switch(mode) {
 +      switch (mode) {
        case AR5K_EEPROM_MODE_11G:
                if (AR5K_EEPROM_HDR_11B(ee->ee_header))
                        offset += ath5k_pdgains_size_2413(ee,
@@@ -1624,8 -1620,8 +1622,8 @@@ ath5k_eeprom_read_ctl_info(struct ath5k
                offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
  
        rep = ee->ee_ctl_pwr;
 -      for(i = 0; i < ee->ee_ctls; i++) {
 -              switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
 +      for (i = 0; i < ee->ee_ctls; i++) {
 +              switch (ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
                case AR5K_CTL_11A:
                case AR5K_CTL_TURBO:
                        ctl_mode = AR5K_EEPROM_MODE_11A;
@@@ -234,7 -234,7 +234,7 @@@ ath5k_pci_probe(struct pci_dev *pdev
  
        mem = pci_iomap(pdev, 0, 0);
        if (!mem) {
 -              dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
 +              dev_err(&pdev->dev, "cannot remap PCI memory region\n");
                ret = -EIO;
                goto err_reg;
        }
@@@ -297,7 -297,9 +297,9 @@@ ath5k_pci_remove(struct pci_dev *pdev
  #ifdef CONFIG_PM_SLEEP
  static int ath5k_pci_suspend(struct device *dev)
  {
-       struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
  
        ath5k_led_off(sc);
        return 0;
  static int ath5k_pci_resume(struct device *dev)
  {
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct ath5k_softc *sc = pci_get_drvdata(pdev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
  
        /*
         * Suspend/Resume resets the PCI configuration space, so we have to
@@@ -10,20 -10,20 +10,22 @@@ static ssize_t ath5k_attr_show_##name(s
                        struct device_attribute *attr,                  \
                        char *buf)                                      \
  {                                                                     \
-       struct ath5k_softc *sc = dev_get_drvdata(dev);                  \
+       struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
+       struct ath5k_softc *sc = hw->priv;                              \
 -      return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
 +      return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
  }                                                                     \
                                                                        \
  static ssize_t ath5k_attr_store_##name(struct device *dev,            \
                        struct device_attribute *attr,                  \
                        const char *buf, size_t count)                  \
  {                                                                     \
-       struct ath5k_softc *sc = dev_get_drvdata(dev);                  \
+       struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
+       struct ath5k_softc *sc = hw->priv;                              \
 -      int val;                                                        \
 +      int val, ret;                                                   \
                                                                        \
 -      val = (int)simple_strtoul(buf, NULL, 10);                       \
 +      ret = kstrtoint(buf, 10, &val);                                 \
 +      if (ret < 0)                                                    \
 +              return ret;                                             \
        set(sc->ah, val);                                               \
        return count;                                                   \
  }                                                                     \
@@@ -35,8 -35,9 +37,9 @@@ static ssize_t ath5k_attr_show_##name(s
                        struct device_attribute *attr,                  \
                        char *buf)                                      \
  {                                                                     \
-       struct ath5k_softc *sc = dev_get_drvdata(dev);                  \
+       struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
+       struct ath5k_softc *sc = hw->priv;                              \
 -      return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
 +      return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
  }                                                                     \
  static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
  
@@@ -53,7 -53,7 +53,7 @@@ static void ath_tx_complete_buf(struct 
                                struct ath_txq *txq, struct list_head *bf_q,
                                struct ath_tx_status *ts, int txok, int sendbar);
  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 -                           struct list_head *head);
 +                           struct list_head *head, bool internal);
  static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
  static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
                             struct ath_tx_status *ts, int nframes, int nbad,
@@@ -377,7 -377,8 +377,7 @@@ static void ath_tx_complete_aggr(struc
                        bf_next = bf->bf_next;
  
                        bf->bf_state.bf_type |= BUF_XRETRY;
 -                      if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
 -                          !bf->bf_stale || bf_next != NULL)
 +                      if (!bf->bf_stale || bf_next != NULL)
                                list_move_tail(&bf->list, &bf_head);
  
                        ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
                        }
                }
  
 -              if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
 -                  bf_next == NULL) {
 -                      /*
 -                       * Make sure the last desc is reclaimed if it
 -                       * not a holding desc.
 -                       */
 -                      if (!bf_last->bf_stale)
 -                              list_move_tail(&bf->list, &bf_head);
 -                      else
 -                              INIT_LIST_HEAD(&bf_head);
 -              } else {
 -                      BUG_ON(list_empty(bf_q));
 +              /*
 +               * Make sure the last desc is reclaimed if it
 +               * not a holding desc.
 +               */
 +              if (!bf_last->bf_stale || bf_next != NULL)
                        list_move_tail(&bf->list, &bf_head);
 -              }
 +              else
 +                      INIT_LIST_HEAD(&bf_head);
  
                if (!txpending || (tid->state & AGGR_CLEANUP)) {
                        /*
  
        rcu_read_unlock();
  
 -      if (needreset) {
 -              spin_unlock_bh(&sc->sc_pcu_lock);
 +      if (needreset)
                ath_reset(sc, false);
 -              spin_lock_bh(&sc->sc_pcu_lock);
 -      }
  }
  
  static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
@@@ -661,7 -671,8 +661,8 @@@ static int ath_compute_num_delims(struc
         * TODO - this could be improved to be dependent on the rate.
         *      The hardware can keep up at lower rates, but not higher rates
         */
-       if (fi->keyix != ATH9K_TXKEYIX_INVALID)
+       if ((fi->keyix != ATH9K_TXKEYIX_INVALID) &&
+           !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
                ndelim += ATH_AGGR_ENCRYPTDELIM;
  
        /*
@@@ -827,7 -838,7 +828,7 @@@ static void ath_tx_sched_aggr(struct at
                        bf->bf_state.bf_type &= ~BUF_AGGR;
                        ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
                        ath_buf_set_rate(sc, bf, fi->framelen);
 -                      ath_tx_txqaddbuf(sc, txq, &bf_q);
 +                      ath_tx_txqaddbuf(sc, txq, &bf_q, false);
                        continue;
                }
  
                /* anchor last desc of aggregate */
                ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
  
 -              ath_tx_txqaddbuf(sc, txq, &bf_q);
 +              ath_tx_txqaddbuf(sc, txq, &bf_q, false);
                TX_STAT_INC(txq->axq_qnum, a_aggr);
  
        } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
@@@ -1075,6 -1086,7 +1076,6 @@@ struct ath_txq *ath_txq_setup(struct at
                txq->txq_headidx = txq->txq_tailidx = 0;
                for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
                        INIT_LIST_HEAD(&txq->txq_fifo[i]);
 -              INIT_LIST_HEAD(&txq->txq_fifo_pending);
        }
        return &sc->tx.txq[axq_qnum];
  }
@@@ -1144,8 -1156,13 +1145,8 @@@ static bool bf_is_ampdu_not_probing(str
      return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
  }
  
 -/*
 - * Drain a given TX queue (could be Beacon or Data)
 - *
 - * This assumes output has been stopped and
 - * we do not need to block ath_tx_tasklet.
 - */
 -void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 +static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
 +                             struct list_head *list, bool retry_tx)
  {
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
        memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
  
 -      for (;;) {
 -              spin_lock_bh(&txq->axq_lock);
 +      while (!list_empty(list)) {
 +              bf = list_first_entry(list, struct ath_buf, list);
  
 -              if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 -                      if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
 -                              txq->txq_headidx = txq->txq_tailidx = 0;
 -                              spin_unlock_bh(&txq->axq_lock);
 -                              break;
 -                      } else {
 -                              bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
 -                                                    struct ath_buf, list);
 -                      }
 -              } else {
 -                      if (list_empty(&txq->axq_q)) {
 -                              txq->axq_link = NULL;
 -                              spin_unlock_bh(&txq->axq_lock);
 -                              break;
 -                      }
 -                      bf = list_first_entry(&txq->axq_q, struct ath_buf,
 -                                            list);
 -
 -                      if (bf->bf_stale) {
 -                              list_del(&bf->list);
 -                              spin_unlock_bh(&txq->axq_lock);
 +              if (bf->bf_stale) {
 +                      list_del(&bf->list);
  
 -                              ath_tx_return_buffer(sc, bf);
 -                              continue;
 -                      }
 +                      ath_tx_return_buffer(sc, bf);
 +                      continue;
                }
  
                lastbf = bf->bf_lastbf;
 -
 -              if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 -                      list_cut_position(&bf_head,
 -                                        &txq->txq_fifo[txq->txq_tailidx],
 -                                        &lastbf->list);
 -                      INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
 -              } else {
 -                      /* remove ath_buf's of the same mpdu from txq */
 -                      list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
 -              }
 +              list_cut_position(&bf_head, list, &lastbf->list);
  
                txq->axq_depth--;
                if (bf_is_ampdu_not_probing(bf))
                        txq->axq_ampdu_depth--;
 -              spin_unlock_bh(&txq->axq_lock);
  
 +              spin_unlock_bh(&txq->axq_lock);
                if (bf_isampdu(bf))
                        ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
                                             retry_tx);
                else
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
 +              spin_lock_bh(&txq->axq_lock);
        }
 +}
  
 +/*
 + * Drain a given TX queue (could be Beacon or Data)
 + *
 + * This assumes output has been stopped and
 + * we do not need to block ath_tx_tasklet.
 + */
 +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 +{
        spin_lock_bh(&txq->axq_lock);
 -      txq->axq_tx_inprogress = false;
 -      spin_unlock_bh(&txq->axq_lock);
 -
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 -              spin_lock_bh(&txq->axq_lock);
 -              while (!list_empty(&txq->txq_fifo_pending)) {
 -                      bf = list_first_entry(&txq->txq_fifo_pending,
 -                                            struct ath_buf, list);
 -                      list_cut_position(&bf_head,
 -                                        &txq->txq_fifo_pending,
 -                                        &bf->bf_lastbf->list);
 -                      spin_unlock_bh(&txq->axq_lock);
 +              int idx = txq->txq_tailidx;
  
 -                      if (bf_isampdu(bf))
 -                              ath_tx_complete_aggr(sc, txq, bf, &bf_head,
 -                                                   &ts, 0, retry_tx);
 -                      else
 -                              ath_tx_complete_buf(sc, bf, txq, &bf_head,
 -                                                  &ts, 0, 0);
 -                      spin_lock_bh(&txq->axq_lock);
 +              while (!list_empty(&txq->txq_fifo[idx])) {
 +                      ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
 +                                         retry_tx);
 +
 +                      INCR(idx, ATH_TXFIFO_DEPTH);
                }
 -              spin_unlock_bh(&txq->axq_lock);
 +              txq->txq_tailidx = idx;
        }
  
 +      txq->axq_link = NULL;
 +      txq->axq_tx_inprogress = false;
 +      ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
 +
        /* flush any pending frames if aggregation is enabled */
 -      if (sc->sc_flags & SC_OP_TXAGGR) {
 -              if (!retry_tx) {
 -                      spin_lock_bh(&txq->axq_lock);
 -                      ath_txq_drain_pending_buffers(sc, txq);
 -                      spin_unlock_bh(&txq->axq_lock);
 -              }
 -      }
 +      if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
 +              ath_txq_drain_pending_buffers(sc, txq);
 +
 +      spin_unlock_bh(&txq->axq_lock);
  }
  
  bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
@@@ -1324,13 -1371,11 +1325,13 @@@ void ath_txq_schedule(struct ath_softc 
   * assume the descriptors are already chained together by caller.
   */
  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 -                           struct list_head *head)
 +                           struct list_head *head, bool internal)
  {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 -      struct ath_buf *bf;
 +      struct ath_buf *bf, *bf_last;
 +      bool puttxbuf = false;
 +      bool edma;
  
        /*
         * Insert the frame on the outbound list and
        if (list_empty(head))
                return;
  
 +      edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
        bf = list_first_entry(head, struct ath_buf, list);
 +      bf_last = list_entry(head->prev, struct ath_buf, list);
  
        ath_dbg(common, ATH_DBG_QUEUE,
                "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
  
 -      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 -              if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
 -                      list_splice_tail_init(head, &txq->txq_fifo_pending);
 -                      return;
 -              }
 -              if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
 -                      ath_dbg(common, ATH_DBG_XMIT,
 -                              "Initializing tx fifo %d which is non-empty\n",
 -                              txq->txq_headidx);
 -              INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
 -              list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
 +      if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
 +              list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
                INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
 -              TX_STAT_INC(txq->axq_qnum, puttxbuf);
 -              ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 -              ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
 -                      txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
 +              puttxbuf = true;
        } else {
                list_splice_tail_init(head, &txq->axq_q);
  
 -              if (txq->axq_link == NULL) {
 -                      TX_STAT_INC(txq->axq_qnum, puttxbuf);
 -                      ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 -                      ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
 -                              txq->axq_qnum, ito64(bf->bf_daddr),
 -                              bf->bf_desc);
 -              } else {
 -                      *txq->axq_link = bf->bf_daddr;
 +              if (txq->axq_link) {
 +                      ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
                        ath_dbg(common, ATH_DBG_XMIT,
                                "link[%u] (%p)=%llx (%p)\n",
                                txq->axq_qnum, txq->axq_link,
                                ito64(bf->bf_daddr), bf->bf_desc);
 -              }
 -              ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
 -                                     &txq->axq_link);
 +              } else if (!edma)
 +                      puttxbuf = true;
 +
 +              txq->axq_link = bf_last->bf_desc;
 +      }
 +
 +      if (puttxbuf) {
 +              TX_STAT_INC(txq->axq_qnum, puttxbuf);
 +              ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 +              ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
 +                      txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
 +      }
 +
 +      if (!edma) {
                TX_STAT_INC(txq->axq_qnum, txstart);
                ath9k_hw_txstart(ah, txq->axq_qnum);
        }
 -      txq->axq_depth++;
 -      if (bf_is_ampdu_not_probing(bf))
 -              txq->axq_ampdu_depth++;
 +
 +      if (!internal) {
 +              txq->axq_depth++;
 +              if (bf_is_ampdu_not_probing(bf))
 +                      txq->axq_ampdu_depth++;
 +      }
  }
  
  static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
        TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
        bf->bf_lastbf = bf;
        ath_buf_set_rate(sc, bf, fi->framelen);
 -      ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
 +      ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
  }
  
  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
        bf->bf_lastbf = bf;
        fi = get_frame_info(bf->bf_mpdu);
        ath_buf_set_rate(sc, bf, fi->framelen);
 -      ath_tx_txqaddbuf(sc, txq, bf_head);
 +      ath_tx_txqaddbuf(sc, txq, bf_head, false);
        TX_STAT_INC(txq->axq_qnum, queued);
  }
  
@@@ -2031,38 -2078,6 +2032,38 @@@ static void ath_tx_rc_status(struct ath
        tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
  }
  
 +static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
 +                                struct ath_tx_status *ts, struct ath_buf *bf,
 +                                struct list_head *bf_head)
 +{
 +      int txok;
 +
 +      txq->axq_depth--;
 +      txok = !(ts->ts_status & ATH9K_TXERR_MASK);
 +      txq->axq_tx_inprogress = false;
 +      if (bf_is_ampdu_not_probing(bf))
 +              txq->axq_ampdu_depth--;
 +
 +      spin_unlock_bh(&txq->axq_lock);
 +
 +      if (!bf_isampdu(bf)) {
 +              /*
 +               * This frame is sent out as a single frame.
 +               * Use hardware retry status for this frame.
 +               */
 +              if (ts->ts_status & ATH9K_TXERR_XRETRY)
 +                      bf->bf_state.bf_type |= BUF_XRETRY;
 +              ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
 +              ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
 +      } else
 +              ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
 +
 +      spin_lock_bh(&txq->axq_lock);
 +
 +      if (sc->sc_flags & SC_OP_TXAGGR)
 +              ath_txq_schedule(sc, txq);
 +}
 +
  static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
  {
        struct ath_hw *ah = sc->sc_ah;
        struct list_head bf_head;
        struct ath_desc *ds;
        struct ath_tx_status ts;
 -      int txok;
        int status;
  
        ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
                txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
                txq->axq_link);
  
 +      spin_lock_bh(&txq->axq_lock);
        for (;;) {
 -              spin_lock_bh(&txq->axq_lock);
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
                        if (sc->sc_flags & SC_OP_TXAGGR)
                                ath_txq_schedule(sc, txq);
 -                      spin_unlock_bh(&txq->axq_lock);
                        break;
                }
                bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
                bf_held = NULL;
                if (bf->bf_stale) {
                        bf_held = bf;
 -                      if (list_is_last(&bf_held->list, &txq->axq_q)) {
 -                              spin_unlock_bh(&txq->axq_lock);
 +                      if (list_is_last(&bf_held->list, &txq->axq_q))
                                break;
 -                      } else {
 -                              bf = list_entry(bf_held->list.next,
 -                                              struct ath_buf, list);
 -                      }
 +
 +                      bf = list_entry(bf_held->list.next, struct ath_buf,
 +                                      list);
                }
  
                lastbf = bf->bf_lastbf;
  
                memset(&ts, 0, sizeof(ts));
                status = ath9k_hw_txprocdesc(ah, ds, &ts);
 -              if (status == -EINPROGRESS) {
 -                      spin_unlock_bh(&txq->axq_lock);
 +              if (status == -EINPROGRESS)
                        break;
 -              }
 +
                TX_STAT_INC(txq->axq_qnum, txprocdesc);
  
                /*
                        list_cut_position(&bf_head,
                                &txq->axq_q, lastbf->list.prev);
  
 -              txq->axq_depth--;
 -              txok = !(ts.ts_status & ATH9K_TXERR_MASK);
 -              txq->axq_tx_inprogress = false;
 -              if (bf_held)
 +              if (bf_held) {
                        list_del(&bf_held->list);
 -
 -              if (bf_is_ampdu_not_probing(bf))
 -                      txq->axq_ampdu_depth--;
 -
 -              spin_unlock_bh(&txq->axq_lock);
 -
 -              if (bf_held)
                        ath_tx_return_buffer(sc, bf_held);
 -
 -              if (!bf_isampdu(bf)) {
 -                      /*
 -                       * This frame is sent out as a single frame.
 -                       * Use hardware retry status for this frame.
 -                       */
 -                      if (ts.ts_status & ATH9K_TXERR_XRETRY)
 -                              bf->bf_state.bf_type |= BUF_XRETRY;
 -                      ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
                }
  
 -              if (bf_isampdu(bf))
 -                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
 -                                           true);
 -              else
 -                      ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
 -
 -              spin_lock_bh(&txq->axq_lock);
 -
 -              if (sc->sc_flags & SC_OP_TXAGGR)
 -                      ath_txq_schedule(sc, txq);
 -              spin_unlock_bh(&txq->axq_lock);
 +              ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
        }
 +      spin_unlock_bh(&txq->axq_lock);
  }
  
  static void ath_tx_complete_poll_work(struct work_struct *work)
        if (needreset) {
                ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
                        "tx hung, resetting the chip\n");
 +              spin_lock_bh(&sc->sc_pcu_lock);
                ath_reset(sc, true);
 +              spin_unlock_bh(&sc->sc_pcu_lock);
        }
  
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@@ -2192,16 -2238,17 +2193,16 @@@ void ath_tx_tasklet(struct ath_softc *s
  
  void ath_tx_edma_tasklet(struct ath_softc *sc)
  {
 -      struct ath_tx_status txs;
 +      struct ath_tx_status ts;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
        struct ath_txq *txq;
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
        int status;
 -      int txok;
  
        for (;;) {
 -              status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
 +              status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
                if (status == -EINPROGRESS)
                        break;
                if (status == -EIO) {
                }
  
                /* Skip beacon completions */
 -              if (txs.qid == sc->beacon.beaconq)
 +              if (ts.qid == sc->beacon.beaconq)
                        continue;
  
 -              txq = &sc->tx.txq[txs.qid];
 +              txq = &sc->tx.txq[ts.qid];
  
                spin_lock_bh(&txq->axq_lock);
 +
                if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
                        spin_unlock_bh(&txq->axq_lock);
                        return;
                INIT_LIST_HEAD(&bf_head);
                list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
                                  &lastbf->list);
 -              INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
 -              txq->axq_depth--;
 -              txq->axq_tx_inprogress = false;
 -              if (bf_is_ampdu_not_probing(bf))
 -                      txq->axq_ampdu_depth--;
 -              spin_unlock_bh(&txq->axq_lock);
  
 -              txok = !(txs.ts_status & ATH9K_TXERR_MASK);
 -
 -              if (!bf_isampdu(bf)) {
 -                      if (txs.ts_status & ATH9K_TXERR_XRETRY)
 -                              bf->bf_state.bf_type |= BUF_XRETRY;
 -                      ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
 -              }
 -
 -              if (bf_isampdu(bf))
 -                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
 -                                           txok, true);
 -              else
 -                      ath_tx_complete_buf(sc, bf, txq, &bf_head,
 -                                          &txs, txok, 0);
 +              if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
 +                      INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
  
 -              spin_lock_bh(&txq->axq_lock);
 +                      if (!list_empty(&txq->axq_q)) {
 +                              struct list_head bf_q;
  
 -              if (!list_empty(&txq->txq_fifo_pending)) {
 -                      INIT_LIST_HEAD(&bf_head);
 -                      bf = list_first_entry(&txq->txq_fifo_pending,
 -                                            struct ath_buf, list);
 -                      list_cut_position(&bf_head,
 -                                        &txq->txq_fifo_pending,
 -                                        &bf->bf_lastbf->list);
 -                      ath_tx_txqaddbuf(sc, txq, &bf_head);
 -              } else if (sc->sc_flags & SC_OP_TXAGGR)
 -                      ath_txq_schedule(sc, txq);
 +                              INIT_LIST_HEAD(&bf_q);
 +                              txq->axq_link = NULL;
 +                              list_splice_tail_init(&txq->axq_q, &bf_q);
 +                              ath_tx_txqaddbuf(sc, txq, &bf_q, true);
 +                      }
 +              }
  
 +              ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
                spin_unlock_bh(&txq->axq_lock);
        }
  }
@@@ -314,7 -314,7 +314,7 @@@ int ssb_pcicore_pcibios_map_irq(const s
        return ssb_mips_irq(extpci_core->dev) + 2;
  }
  
 -static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
  {
        u32 val;
  
        register_pci_controller(&ssb_pcicore_controller);
  }
  
 -static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
 +static int __devinit pcicore_is_in_hostmode(struct ssb_pcicore *pc)
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
   * Workarounds.
   **************************************************/
  
 -static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
  {
        u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
        if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
@@@ -514,13 -514,22 +514,22 @@@ static void ssb_pcicore_pcie_setup_work
   * Generic and Clientmode operation code.
   **************************************************/
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
+       ssb_pcicore_fix_sprom_core_index(pc);
        /* Disable PCI interrupts. */
        ssb_write32(pc->dev, SSB_INTVEC, 0);
+       /* Additional PCIe always once-executed workarounds */
+       if (pc->dev->id.coreid == SSB_DEV_PCIE) {
+               ssb_pcicore_serdes_workaround(pc);
+               /* TODO: ASPM */
+               /* TODO: Clock Request Update */
+       }
  }
  
 -void ssb_pcicore_init(struct ssb_pcicore *pc)
 +void __devinit ssb_pcicore_init(struct ssb_pcicore *pc)
  {
        struct ssb_device *dev = pc->dev;
  
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-       ssb_pcicore_fix_sprom_core_index(pc);
  #ifdef CONFIG_SSB_PCICORE_HOSTMODE
        pc->hostmode = pcicore_is_in_hostmode(pc);
        if (pc->hostmode)
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
        if (!pc->hostmode)
                ssb_pcicore_init_clientmode(pc);
-       /* Additional PCIe always once-executed workarounds */
-       if (dev->id.coreid == SSB_DEV_PCIE) {
-               ssb_pcicore_serdes_workaround(pc);
-               /* TODO: ASPM */
-               /* TODO: Clock Request Update */
-       }
  }
  
  static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
diff --combined net/bluetooth/hci_conn.c
@@@ -53,13 -53,11 +53,13 @@@ static void hci_le_connect(struct hci_c
        conn->state = BT_CONNECT;
        conn->out = 1;
        conn->link_mode |= HCI_LM_MASTER;
 +      conn->sec_level = BT_SECURITY_LOW;
  
        memset(&cp, 0, sizeof(cp));
        cp.scan_interval = cpu_to_le16(0x0004);
        cp.scan_window = cpu_to_le16(0x0004);
        bacpy(&cp.peer_addr, &conn->dst);
 +      cp.peer_addr_type = conn->dst_type;
        cp.conn_interval_min = cpu_to_le16(0x0008);
        cp.conn_interval_max = cpu_to_le16(0x0100);
        cp.supervision_timeout = cpu_to_le16(0x0064);
@@@ -205,55 -203,6 +205,55 @@@ void hci_le_conn_update(struct hci_con
  }
  EXPORT_SYMBOL(hci_le_conn_update);
  
 +void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 +                                                      __u8 ltk[16])
 +{
 +      struct hci_dev *hdev = conn->hdev;
 +      struct hci_cp_le_start_enc cp;
 +
 +      BT_DBG("%p", conn);
 +
 +      memset(&cp, 0, sizeof(cp));
 +
 +      cp.handle = cpu_to_le16(conn->handle);
 +      memcpy(cp.ltk, ltk, sizeof(cp.ltk));
 +      cp.ediv = ediv;
 +      memcpy(cp.rand, rand, sizeof(rand));
 +
 +      hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 +}
 +EXPORT_SYMBOL(hci_le_start_enc);
 +
 +void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
 +{
 +      struct hci_dev *hdev = conn->hdev;
 +      struct hci_cp_le_ltk_reply cp;
 +
 +      BT_DBG("%p", conn);
 +
 +      memset(&cp, 0, sizeof(cp));
 +
 +      cp.handle = cpu_to_le16(conn->handle);
 +      memcpy(cp.ltk, ltk, sizeof(ltk));
 +
 +      hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 +}
 +EXPORT_SYMBOL(hci_le_ltk_reply);
 +
 +void hci_le_ltk_neg_reply(struct hci_conn *conn)
 +{
 +      struct hci_dev *hdev = conn->hdev;
 +      struct hci_cp_le_ltk_neg_reply cp;
 +
 +      BT_DBG("%p", conn);
 +
 +      memset(&cp, 0, sizeof(cp));
 +
 +      cp.handle = cpu_to_le16(conn->handle);
 +
 +      hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
 +}
 +
  /* Device _must_ be locked */
  void hci_sco_setup(struct hci_conn *conn, __u8 status)
  {
@@@ -444,6 -393,9 +444,9 @@@ int hci_conn_del(struct hci_conn *conn
  
        hci_dev_put(hdev);
  
+       if (conn->handle == 0)
+               kfree(conn);
        return 0;
  }
  
@@@ -498,23 -450,14 +501,23 @@@ struct hci_conn *hci_connect(struct hci
        BT_DBG("%s dst %s", hdev->name, batostr(dst));
  
        if (type == LE_LINK) {
 +              struct adv_entry *entry;
 +
                le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
                if (le)
                        return ERR_PTR(-EBUSY);
 +
 +              entry = hci_find_adv_entry(hdev, dst);
 +              if (!entry)
 +                      return ERR_PTR(-EHOSTUNREACH);
 +
                le = hci_conn_add(hdev, LE_LINK, dst);
                if (!le)
                        return ERR_PTR(-ENOMEM);
 -              if (le->state == BT_OPEN)
 -                      hci_le_connect(le);
 +
 +              le->dst_type = entry->bdaddr_type;
 +
 +              hci_le_connect(le);
  
                hci_conn_hold(le);
  
        if (acl->state == BT_CONNECTED &&
                        (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
                acl->power_save = 1;
 -              hci_conn_enter_active_mode(acl);
 +              hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
  
                if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
                        /* defer SCO setup until mode change completed */
@@@ -608,8 -551,6 +611,8 @@@ static int hci_conn_auth(struct hci_con
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
                                                        sizeof(cp), &cp);
 +              if (conn->key_type != 0xff)
 +                      set_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
        }
  
        return 0;
@@@ -693,7 -634,9 +696,7 @@@ int hci_conn_check_secure(struct hci_co
        if (sec_level != BT_SECURITY_HIGH)
                return 1; /* Accept if non-secure is required */
  
 -      if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
 -                      (conn->key_type == HCI_LK_COMBINATION &&
 -                      conn->pin_length == 16))
 +      if (conn->sec_level == BT_SECURITY_HIGH)
                return 1;
  
        return 0; /* Reject not secure link */
@@@ -736,7 -679,7 +739,7 @@@ int hci_conn_switch_role(struct hci_con
  EXPORT_SYMBOL(hci_conn_switch_role);
  
  /* Enter active mode */
 -void hci_conn_enter_active_mode(struct hci_conn *conn)
 +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
  {
        struct hci_dev *hdev = conn->hdev;
  
        if (test_bit(HCI_RAW, &hdev->flags))
                return;
  
 -      if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
 +      if (conn->mode != HCI_CM_SNIFF)
 +              goto timer;
 +
 +      if (!conn->power_save && !force_active)
                goto timer;
  
        if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
@@@ -54,7 -54,6 +54,7 @@@
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  #include <net/bluetooth/l2cap.h>
 +#include <net/bluetooth/smp.h>
  
  int disable_ertm;
  
@@@ -63,34 -62,18 +63,34 @@@ static u8 l2cap_fixed_chan[8] = { 0x02
  
  static struct workqueue_struct *_busy_wq;
  
 -LIST_HEAD(chan_list);
 -DEFINE_RWLOCK(chan_list_lock);
 +static LIST_HEAD(chan_list);
 +static DEFINE_RWLOCK(chan_list_lock);
  
  static void l2cap_busy_work(struct work_struct *work);
  
  static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
                                u8 code, u8 ident, u16 dlen, void *data);
 +static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
 +                                                              void *data);
  static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 +static void l2cap_send_disconn_req(struct l2cap_conn *conn,
 +                              struct l2cap_chan *chan, int err);
  
  static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
  
  /* ---- L2CAP channels ---- */
 +
 +static inline void chan_hold(struct l2cap_chan *c)
 +{
 +      atomic_inc(&c->refcnt);
 +}
 +
 +static inline void chan_put(struct l2cap_chan *c)
 +{
 +      if (atomic_dec_and_test(&c->refcnt))
 +              kfree(c);
 +}
 +
  static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
  {
        struct l2cap_chan *c;
@@@ -221,62 -204,6 +221,62 @@@ static u16 l2cap_alloc_cid(struct l2cap
        return 0;
  }
  
 +static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
 +{
 +       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
 +
 +       if (!mod_timer(timer, jiffies + timeout))
 +             chan_hold(chan);
 +}
 +
 +static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
 +{
 +       BT_DBG("chan %p state %d", chan, chan->state);
 +
 +       if (timer_pending(timer) && del_timer(timer))
 +             chan_put(chan);
 +}
 +
 +static void l2cap_state_change(struct l2cap_chan *chan, int state)
 +{
 +      chan->state = state;
 +      chan->ops->state_change(chan->data, state);
 +}
 +
 +static void l2cap_chan_timeout(unsigned long arg)
 +{
 +      struct l2cap_chan *chan = (struct l2cap_chan *) arg;
 +      struct sock *sk = chan->sk;
 +      int reason;
 +
 +      BT_DBG("chan %p state %d", chan, chan->state);
 +
 +      bh_lock_sock(sk);
 +
 +      if (sock_owned_by_user(sk)) {
 +              /* sk is owned by user. Try again later */
 +              __set_chan_timer(chan, HZ / 5);
 +              bh_unlock_sock(sk);
 +              chan_put(chan);
 +              return;
 +      }
 +
 +      if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
 +              reason = ECONNREFUSED;
 +      else if (chan->state == BT_CONNECT &&
 +                                      chan->sec_level != BT_SECURITY_SDP)
 +              reason = ECONNREFUSED;
 +      else
 +              reason = ETIMEDOUT;
 +
 +      l2cap_chan_close(chan, reason);
 +
 +      bh_unlock_sock(sk);
 +
 +      chan->ops->close(chan->data);
 +      chan_put(chan);
 +}
 +
  struct l2cap_chan *l2cap_chan_create(struct sock *sk)
  {
        struct l2cap_chan *chan;
        list_add(&chan->global_l, &chan_list);
        write_unlock_bh(&chan_list_lock);
  
 +      setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
 +
 +      chan->state = BT_OPEN;
 +
 +      atomic_set(&chan->refcnt, 1);
 +
        return chan;
  }
  
@@@ -306,11 -227,13 +306,11 @@@ void l2cap_chan_destroy(struct l2cap_ch
        list_del(&chan->global_l);
        write_unlock_bh(&chan_list_lock);
  
 -      kfree(chan);
 +      chan_put(chan);
  }
  
  static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
 -      struct sock *sk = chan->sk;
 -
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
  
  
        chan->conn = conn;
  
 -      if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
 +      if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
                if (conn->hcon->type == LE_LINK) {
                        /* LE connection */
                        chan->omtu = L2CAP_LE_DEFAULT_MTU;
                        chan->scid = l2cap_alloc_cid(conn);
                        chan->omtu = L2CAP_DEFAULT_MTU;
                }
 -      } else if (sk->sk_type == SOCK_DGRAM) {
 +      } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
                /* Connectionless socket */
                chan->scid = L2CAP_CID_CONN_LESS;
                chan->dcid = L2CAP_CID_CONN_LESS;
                chan->omtu = L2CAP_DEFAULT_MTU;
        }
  
 -      sock_hold(sk);
 +      chan_hold(chan);
  
        list_add(&chan->list, &conn->chan_l);
  }
  
  /* Delete channel.
   * Must be called on the locked socket. */
 -void l2cap_chan_del(struct l2cap_chan *chan, int err)
 +static void l2cap_chan_del(struct l2cap_chan *chan, int err)
  {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sock *parent = bt_sk(sk)->parent;
  
 -      l2cap_sock_clear_timer(sk);
 +      __clear_chan_timer(chan);
  
        BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
  
                write_lock_bh(&conn->chan_lock);
                list_del(&chan->list);
                write_unlock_bh(&conn->chan_lock);
 -              __sock_put(sk);
 +              chan_put(chan);
  
                chan->conn = NULL;
                hci_conn_put(conn->hcon);
        }
  
 -      sk->sk_state = BT_CLOSED;
 +      l2cap_state_change(chan, BT_CLOSED);
        sock_set_flag(sk, SOCK_ZAPPED);
  
        if (err)
        } else
                sk->sk_state_change(sk);
  
 -      if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
 -                      chan->conf_state & L2CAP_CONF_INPUT_DONE))
 +      if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
 +                      test_bit(CONF_INPUT_DONE, &chan->conf_state)))
                return;
  
        skb_queue_purge(&chan->tx_q);
        if (chan->mode == L2CAP_MODE_ERTM) {
                struct srej_list *l, *tmp;
  
 -              del_timer(&chan->retrans_timer);
 -              del_timer(&chan->monitor_timer);
 -              del_timer(&chan->ack_timer);
 +              __clear_retrans_timer(chan);
 +              __clear_monitor_timer(chan);
 +              __clear_ack_timer(chan);
  
                skb_queue_purge(&chan->srej_q);
                skb_queue_purge(&chan->busy_q);
        }
  }
  
 -static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 +static void l2cap_chan_cleanup_listen(struct sock *parent)
  {
 +      struct sock *sk;
 +
 +      BT_DBG("parent %p", parent);
 +
 +      /* Close not yet accepted channels */
 +      while ((sk = bt_accept_dequeue(parent, NULL))) {
 +              struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 +              __clear_chan_timer(chan);
 +              lock_sock(sk);
 +              l2cap_chan_close(chan, ECONNRESET);
 +              release_sock(sk);
 +              chan->ops->close(chan->data);
 +      }
 +}
 +
 +void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 +{
 +      struct l2cap_conn *conn = chan->conn;
        struct sock *sk = chan->sk;
  
 -      if (sk->sk_type == SOCK_RAW) {
 +      BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
 +
 +      switch (chan->state) {
 +      case BT_LISTEN:
 +              l2cap_chan_cleanup_listen(sk);
 +
 +              l2cap_state_change(chan, BT_CLOSED);
 +              sock_set_flag(sk, SOCK_ZAPPED);
 +              break;
 +
 +      case BT_CONNECTED:
 +      case BT_CONFIG:
 +              if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
 +                                      conn->hcon->type == ACL_LINK) {
 +                      __clear_chan_timer(chan);
 +                      __set_chan_timer(chan, sk->sk_sndtimeo);
 +                      l2cap_send_disconn_req(conn, chan, reason);
 +              } else
 +                      l2cap_chan_del(chan, reason);
 +              break;
 +
 +      case BT_CONNECT2:
 +              if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
 +                                      conn->hcon->type == ACL_LINK) {
 +                      struct l2cap_conn_rsp rsp;
 +                      __u16 result;
 +
 +                      if (bt_sk(sk)->defer_setup)
 +                              result = L2CAP_CR_SEC_BLOCK;
 +                      else
 +                              result = L2CAP_CR_BAD_PSM;
 +                      l2cap_state_change(chan, BT_DISCONN);
 +
 +                      rsp.scid   = cpu_to_le16(chan->dcid);
 +                      rsp.dcid   = cpu_to_le16(chan->scid);
 +                      rsp.result = cpu_to_le16(result);
 +                      rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 +                      l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
 +                                                      sizeof(rsp), &rsp);
 +              }
 +
 +              l2cap_chan_del(chan, reason);
 +              break;
 +
 +      case BT_CONNECT:
 +      case BT_DISCONN:
 +              l2cap_chan_del(chan, reason);
 +              break;
 +
 +      default:
 +              sock_set_flag(sk, SOCK_ZAPPED);
 +              break;
 +      }
 +}
 +
 +static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
 +{
 +      if (chan->chan_type == L2CAP_CHAN_RAW) {
                switch (chan->sec_level) {
                case BT_SECURITY_HIGH:
                        return HCI_AT_DEDICATED_BONDING_MITM;
@@@ -523,7 -371,7 +523,7 @@@ static inline int l2cap_check_security(
        return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
  }
  
 -u8 l2cap_get_ident(struct l2cap_conn *conn)
 +static u8 l2cap_get_ident(struct l2cap_conn *conn)
  {
        u8 id;
  
        return id;
  }
  
 -void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
 +static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
  {
        struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
        u8 flags;
        else
                flags = ACL_START;
  
 +      bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
 +
        hci_send_acl(conn->hcon, skb, flags);
  }
  
@@@ -569,11 -415,13 +569,11 @@@ static inline void l2cap_send_sframe(st
  {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
 -      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
        struct l2cap_conn *conn = chan->conn;
        int count, hlen = L2CAP_HDR_SIZE + 2;
        u8 flags;
  
 -      if (sk->sk_state != BT_CONNECTED)
 +      if (chan->state != BT_CONNECTED)
                return;
  
        if (chan->fcs == L2CAP_FCS_CRC16)
        count = min_t(unsigned int, conn->mtu, hlen);
        control |= L2CAP_CTRL_FRAME_TYPE;
  
 -      if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 +      if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
                control |= L2CAP_CTRL_FINAL;
 -              chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 -      }
  
 -      if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
 +      if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
                control |= L2CAP_CTRL_POLL;
 -              chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
 -      }
  
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
        else
                flags = ACL_START;
  
 +      bt_cb(skb)->force_active = chan->force_active;
 +
        hci_send_acl(chan->conn->hcon, skb, flags);
  }
  
  static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
  {
 -      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
 -              chan->conn_state |= L2CAP_CONN_RNR_SENT;
 +              set_bit(CONN_RNR_SENT, &chan->conn_state);
        } else
                control |= L2CAP_SUPER_RCV_READY;
  
  
  static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
  {
 -      return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
 +      return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
  }
  
  static void l2cap_do_start(struct l2cap_chan *chan)
                        req.psm  = chan->psm;
  
                        chan->ident = l2cap_get_ident(conn);
 -                      chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 +                      set_bit(CONF_CONNECT_PEND, &chan->conf_state);
  
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
                                                        sizeof(req), &req);
@@@ -683,7 -533,7 +683,7 @@@ static inline int l2cap_mode_supported(
        }
  }
  
 -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
 +static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
  {
        struct sock *sk;
        struct l2cap_disconn_req req;
        sk = chan->sk;
  
        if (chan->mode == L2CAP_MODE_ERTM) {
 -              del_timer(&chan->retrans_timer);
 -              del_timer(&chan->monitor_timer);
 -              del_timer(&chan->ack_timer);
 +              __clear_retrans_timer(chan);
 +              __clear_monitor_timer(chan);
 +              __clear_ack_timer(chan);
        }
  
        req.dcid = cpu_to_le16(chan->dcid);
        l2cap_send_cmd(conn, l2cap_get_ident(conn),
                        L2CAP_DISCONN_REQ, sizeof(req), &req);
  
 -      sk->sk_state = BT_DISCONN;
 +      l2cap_state_change(chan, BT_DISCONN);
        sk->sk_err = err;
  }
  
@@@ -722,12 -572,13 +722,12 @@@ static void l2cap_conn_start(struct l2c
  
                bh_lock_sock(sk);
  
 -              if (sk->sk_type != SOCK_SEQPACKET &&
 -                              sk->sk_type != SOCK_STREAM) {
 +              if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
                        bh_unlock_sock(sk);
                        continue;
                }
  
 -              if (sk->sk_state == BT_CONNECT) {
 +              if (chan->state == BT_CONNECT) {
                        struct l2cap_conn_req req;
  
                        if (!l2cap_check_security(chan) ||
                                continue;
                        }
  
 -                      if (!l2cap_mode_supported(chan->mode,
 -                                      conn->feat_mask)
 -                                      && chan->conf_state &
 -                                      L2CAP_CONF_STATE2_DEVICE) {
 -                              /* __l2cap_sock_close() calls list_del(chan)
 +                      if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
 +                                      && test_bit(CONF_STATE2_DEVICE,
 +                                      &chan->conf_state)) {
 +                              /* l2cap_chan_close() calls list_del(chan)
                                 * so release the lock */
                                read_unlock_bh(&conn->chan_lock);
 -                               __l2cap_sock_close(sk, ECONNRESET);
 +                              l2cap_chan_close(chan, ECONNRESET);
                                read_lock_bh(&conn->chan_lock);
                                bh_unlock_sock(sk);
                                continue;
                        req.psm  = chan->psm;
  
                        chan->ident = l2cap_get_ident(conn);
 -                      chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 +                      set_bit(CONF_CONNECT_PEND, &chan->conf_state);
  
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
                                                        sizeof(req), &req);
  
 -              } else if (sk->sk_state == BT_CONNECT2) {
 +              } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
                        char buf[128];
                        rsp.scid = cpu_to_le16(chan->dcid);
                                        parent->sk_data_ready(parent, 0);
  
                                } else {
 -                                      sk->sk_state = BT_CONFIG;
 +                                      l2cap_state_change(chan, BT_CONFIG);
                                        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 (chan->conf_state & L2CAP_CONF_REQ_SENT ||
 +                      if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
                                        rsp.result != L2CAP_CR_SUCCESS) {
                                bh_unlock_sock(sk);
                                continue;
                        }
  
 -                      chan->conf_state |= L2CAP_CONF_REQ_SENT;
 +                      set_bit(CONF_REQ_SENT, &chan->conf_state);
                        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                                l2cap_build_conf_req(chan, buf), buf);
                        chan->num_conf_req++;
@@@ -813,7 -665,7 +813,7 @@@ static struct l2cap_chan *l2cap_global_
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
  
 -              if (state && sk->sk_state != state)
 +              if (state && c->state != state)
                        continue;
  
                if (c->scid == cid) {
@@@ -857,16 -709,24 +857,16 @@@ static void l2cap_le_conn_ready(struct 
                goto clean;
        }
  
 -      sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
 -      if (!sk)
 -              goto clean;
 -
 -      chan = l2cap_chan_create(sk);
 -      if (!chan) {
 -              l2cap_sock_kill(sk);
 +      chan = pchan->ops->new_connection(pchan->data);
 +      if (!chan)
                goto clean;
 -      }
  
 -      l2cap_pi(sk)->chan = chan;
 +      sk = chan->sk;
  
        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, chan);
  
 -      l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 +      __set_chan_timer(chan, sk->sk_sndtimeo);
  
 -      sk->sk_state = BT_CONNECTED;
 +      l2cap_state_change(chan, BT_CONNECTED);
        parent->sk_data_ready(parent, 0);
  
        write_unlock_bh(&conn->chan_lock);
@@@ -885,23 -745,6 +885,23 @@@ clean
        bh_unlock_sock(parent);
  }
  
 +static void l2cap_chan_ready(struct sock *sk)
 +{
 +      struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 +      struct sock *parent = bt_sk(sk)->parent;
 +
 +      BT_DBG("sk %p, parent %p", sk, parent);
 +
 +      chan->conf_state = 0;
 +      __clear_chan_timer(chan);
 +
 +      l2cap_state_change(chan, BT_CONNECTED);
 +      sk->sk_state_change(sk);
 +
 +      if (parent)
 +              parent->sk_data_ready(parent, 0);
 +}
 +
  static void l2cap_conn_ready(struct l2cap_conn *conn)
  {
        struct l2cap_chan *chan;
                bh_lock_sock(sk);
  
                if (conn->hcon->type == LE_LINK) {
 -                      l2cap_sock_clear_timer(sk);
 -                      sk->sk_state = BT_CONNECTED;
 -                      sk->sk_state_change(sk);
 -              }
 +                      if (smp_conn_security(conn, chan->sec_level))
 +                              l2cap_chan_ready(sk);
  
 -              if (sk->sk_type != SOCK_SEQPACKET &&
 -                              sk->sk_type != SOCK_STREAM) {
 -                      l2cap_sock_clear_timer(sk);
 -                      sk->sk_state = BT_CONNECTED;
 +              } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 +                      __clear_chan_timer(chan);
 +                      l2cap_state_change(chan, BT_CONNECTED);
                        sk->sk_state_change(sk);
 -              } else if (sk->sk_state == BT_CONNECT)
 +
 +              } else if (chan->state == BT_CONNECT)
                        l2cap_do_start(chan);
  
                bh_unlock_sock(sk);
@@@ -965,45 -810,6 +965,45 @@@ static void l2cap_info_timeout(unsigne
        l2cap_conn_start(conn);
  }
  
 +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)
 +              return;
 +
 +      BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 +
 +      kfree_skb(conn->rx_skb);
 +
 +      /* Kill channels */
 +      list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
 +              sk = chan->sk;
 +              bh_lock_sock(sk);
 +              l2cap_chan_del(chan, err);
 +              bh_unlock_sock(sk);
 +              chan->ops->close(chan->data);
 +      }
 +
 +      if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
 +              del_timer_sync(&conn->info_timer);
 +
 +      if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
 +              del_timer(&conn->security_timer);
 +
 +      hcon->l2cap_data = NULL;
 +      kfree(conn);
 +}
 +
 +static void security_timeout(unsigned long arg)
 +{
 +      struct l2cap_conn *conn = (void *) arg;
 +
 +      l2cap_conn_del(conn->hcon, ETIMEDOUT);
 +}
 +
  static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
  {
        struct l2cap_conn *conn = hcon->l2cap_data;
  
        INIT_LIST_HEAD(&conn->chan_l);
  
 -      if (hcon->type != LE_LINK)
 +      if (hcon->type == LE_LINK)
 +              setup_timer(&conn->security_timer, security_timeout,
 +                                              (unsigned long) conn);
 +      else
                setup_timer(&conn->info_timer, l2cap_info_timeout,
                                                (unsigned long) conn);
  
        return conn;
  }
  
 -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)
 -              return;
 -
 -      BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 -
 -      kfree_skb(conn->rx_skb);
 -
 -      /* Kill channels */
 -      list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
 -              sk = chan->sk;
 -              bh_lock_sock(sk);
 -              l2cap_chan_del(chan, err);
 -              bh_unlock_sock(sk);
 -              l2cap_sock_kill(sk);
 -      }
 -
 -      if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
 -              del_timer_sync(&conn->info_timer);
 -
 -      hcon->l2cap_data = NULL;
 -      kfree(conn);
 -}
 -
  static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
        write_lock_bh(&conn->chan_lock);
@@@ -1068,7 -900,7 +1068,7 @@@ static struct l2cap_chan *l2cap_global_
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
  
 -              if (state && sk->sk_state != state)
 +              if (state && c->state != state)
                        continue;
  
                if (c->psm == psm) {
@@@ -1135,14 -967,15 +1135,14 @@@ int l2cap_chan_connect(struct l2cap_cha
  
        l2cap_chan_add(conn, chan);
  
 -      sk->sk_state = BT_CONNECT;
 -      l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 +      l2cap_state_change(chan, BT_CONNECT);
 +      __set_chan_timer(chan, sk->sk_sndtimeo);
  
        if (hcon->state == BT_CONNECTED) {
 -              if (sk->sk_type != SOCK_SEQPACKET &&
 -                              sk->sk_type != SOCK_STREAM) {
 -                      l2cap_sock_clear_timer(sk);
 +              if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 +                      __clear_chan_timer(chan);
                        if (l2cap_check_security(chan))
 -                              sk->sk_state = BT_CONNECTED;
 +                              l2cap_state_change(chan, BT_CONNECTED);
                } else
                        l2cap_do_start(chan);
        }
@@@ -1202,7 -1035,7 +1202,7 @@@ static void l2cap_monitor_timeout(unsig
        }
  
        chan->retry_count++;
 -      __mod_monitor_timer();
 +      __set_monitor_timer(chan);
  
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
@@@ -1217,9 -1050,9 +1217,9 @@@ static void l2cap_retrans_timeout(unsig
  
        bh_lock_sock(sk);
        chan->retry_count = 1;
 -      __mod_monitor_timer();
 +      __set_monitor_timer(chan);
  
 -      chan->conn_state |= L2CAP_CONN_WAIT_F;
 +      set_bit(CONN_WAIT_F, &chan->conn_state);
  
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
@@@ -1241,7 -1074,7 +1241,7 @@@ static void l2cap_drop_acked_frames(str
        }
  
        if (!chan->unacked_frames)
 -              del_timer(&chan->retrans_timer);
 +              __clear_retrans_timer(chan);
  }
  
  void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
        else
                flags = ACL_START;
  
 +      bt_cb(skb)->force_active = chan->force_active;
        hci_send_acl(hcon, skb, flags);
  }
  
@@@ -1310,8 -1142,10 +1310,8 @@@ static void l2cap_retransmit_one_frame(
        control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
        control &= L2CAP_CTRL_SAR;
  
 -      if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 +      if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
                control |= L2CAP_CTRL_FINAL;
 -              chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 -      }
  
        control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
                        | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
  int l2cap_ertm_send(struct l2cap_chan *chan)
  {
        struct sk_buff *skb, *tx_skb;
        u16 control, fcs;
        int nsent = 0;
  
 -      if (sk->sk_state != BT_CONNECTED)
 +      if (chan->state != BT_CONNECTED)
                return -ENOTCONN;
  
        while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
                control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
                control &= L2CAP_CTRL_SAR;
  
 -              if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
 +              if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
                        control |= L2CAP_CTRL_FINAL;
 -                      chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
 -              }
 +
                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);
  
                l2cap_do_send(chan, tx_skb);
  
 -              __mod_retrans_timer();
 +              __set_retrans_timer(chan);
  
                bt_cb(skb)->tx_seq = chan->next_tx_seq;
                chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
@@@ -1404,9 -1240,9 +1404,9 @@@ static void l2cap_send_ack(struct l2cap
  
        control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
 -              chan->conn_state |= L2CAP_CONN_RNR_SENT;
 +              set_bit(CONN_RNR_SENT, &chan->conn_state);
                l2cap_send_sframe(chan, control);
                return;
        }
@@@ -1614,83 -1450,28 +1614,83 @@@ int l2cap_sar_segment_sdu(struct l2cap_
        return size;
  }
  
 -static void l2cap_chan_ready(struct sock *sk)
 +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
  {
 -      struct sock *parent = bt_sk(sk)->parent;
 -      struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 +      struct sk_buff *skb;
 +      u16 control;
 +      int err;
  
 -      BT_DBG("sk %p, parent %p", sk, parent);
 +      /* Connectionless channel */
 +      if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
 +              skb = l2cap_create_connless_pdu(chan, msg, len);
 +              if (IS_ERR(skb))
 +                      return PTR_ERR(skb);
  
 -      chan->conf_state = 0;
 -      l2cap_sock_clear_timer(sk);
 +              l2cap_do_send(chan, skb);
 +              return len;
 +      }
  
 -      if (!parent) {
 -              /* Outgoing channel.
 -               * Wake up socket sleeping on connect.
 -               */
 -              sk->sk_state = BT_CONNECTED;
 -              sk->sk_state_change(sk);
 -      } else {
 -              /* Incoming channel.
 -               * Wake up socket sleeping on accept.
 -               */
 -              parent->sk_data_ready(parent, 0);
 +      switch (chan->mode) {
 +      case L2CAP_MODE_BASIC:
 +              /* Check outgoing MTU */
 +              if (len > chan->omtu)
 +                      return -EMSGSIZE;
 +
 +              /* Create a basic PDU */
 +              skb = l2cap_create_basic_pdu(chan, msg, len);
 +              if (IS_ERR(skb))
 +                      return PTR_ERR(skb);
 +
 +              l2cap_do_send(chan, skb);
 +              err = len;
 +              break;
 +
 +      case L2CAP_MODE_ERTM:
 +      case L2CAP_MODE_STREAMING:
 +              /* Entire SDU fits into one PDU */
 +              if (len <= chan->remote_mps) {
 +                      control = L2CAP_SDU_UNSEGMENTED;
 +                      skb = l2cap_create_iframe_pdu(chan, msg, len, control,
 +                                                                      0);
 +                      if (IS_ERR(skb))
 +                              return PTR_ERR(skb);
 +
 +                      __skb_queue_tail(&chan->tx_q, skb);
 +
 +                      if (chan->tx_send_head == NULL)
 +                              chan->tx_send_head = skb;
 +
 +              } else {
 +                      /* Segment SDU into multiples PDUs */
 +                      err = l2cap_sar_segment_sdu(chan, msg, len);
 +                      if (err < 0)
 +                              return err;
 +              }
 +
 +              if (chan->mode == L2CAP_MODE_STREAMING) {
 +                      l2cap_streaming_send(chan);
 +                      err = len;
 +                      break;
 +              }
 +
 +              if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
 +                              test_bit(CONN_WAIT_F, &chan->conn_state)) {
 +                      err = len;
 +                      break;
 +              }
 +
 +              err = l2cap_ertm_send(chan);
 +              if (err >= 0)
 +                      err = len;
 +
 +              break;
 +
 +      default:
 +              BT_DBG("bad state %1.1x", chan->mode);
 +              err = -EBADFD;
        }
 +
 +      return err;
  }
  
  /* Copy frame to all raw sockets on that connection */
@@@ -1704,7 -1485,7 +1704,7 @@@ static void l2cap_raw_recv(struct l2cap
        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)
 +              if (chan->chan_type != L2CAP_CHAN_RAW)
                        continue;
  
                /* Don't send frame to the socket it came from */
                if (!nskb)
                        continue;
  
 -              if (sock_queue_rcv_skb(sk, nskb))
 +              if (chan->ops->recv(chan->data, nskb))
                        kfree_skb(nskb);
        }
        read_unlock(&conn->chan_lock);
@@@ -1909,7 -1690,7 +1909,7 @@@ static int l2cap_build_conf_req(struct 
        switch (chan->mode) {
        case L2CAP_MODE_STREAMING:
        case L2CAP_MODE_ERTM:
 -              if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
 +              if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
                        break;
  
                /* fall through */
@@@ -1956,7 -1737,7 +1956,7 @@@ done
                        break;
  
                if (chan->fcs == L2CAP_FCS_NONE ||
 -                              chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
 +                              test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
                        break;
  
                if (chan->fcs == L2CAP_FCS_NONE ||
 -                              chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
 +                              test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
@@@ -2031,7 -1812,7 +2031,7 @@@ static int l2cap_parse_conf_req(struct 
  
                case L2CAP_CONF_FCS:
                        if (val == L2CAP_FCS_NONE)
 -                              chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
 +                              set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
  
                        break;
  
        switch (chan->mode) {
        case L2CAP_MODE_STREAMING:
        case L2CAP_MODE_ERTM:
 -              if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
 +              if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
                        chan->mode = l2cap_select_mode(rfc.mode,
                                        chan->conn->feat_mask);
                        break;
@@@ -2084,14 -1865,14 +2084,14 @@@ done
                        result = L2CAP_CONF_UNACCEPT;
                else {
                        chan->omtu = mtu;
 -                      chan->conf_state |= L2CAP_CONF_MTU_DONE;
 +                      set_bit(CONF_MTU_DONE, &chan->conf_state);
                }
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
  
                switch (rfc.mode) {
                case L2CAP_MODE_BASIC:
                        chan->fcs = L2CAP_FCS_NONE;
 -                      chan->conf_state |= L2CAP_CONF_MODE_DONE;
 +                      set_bit(CONF_MODE_DONE, &chan->conf_state);
                        break;
  
                case L2CAP_MODE_ERTM:
                        rfc.monitor_timeout =
                                le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
  
 -                      chan->conf_state |= L2CAP_CONF_MODE_DONE;
 +                      set_bit(CONF_MODE_DONE, &chan->conf_state);
  
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
  
                        chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
  
 -                      chan->conf_state |= L2CAP_CONF_MODE_DONE;
 +                      set_bit(CONF_MODE_DONE, &chan->conf_state);
  
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
                }
  
                if (result == L2CAP_CONF_SUCCESS)
 -                      chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
 +                      set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
        }
        rsp->scid   = cpu_to_le16(chan->dcid);
        rsp->result = cpu_to_le16(result);
@@@ -2178,7 -1959,7 +2178,7 @@@ static int l2cap_parse_conf_rsp(struct 
                        if (olen == sizeof(rfc))
                                memcpy(&rfc, (void *)val, olen);
  
 -                      if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
 +                      if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
                                                        rfc.mode != chan->mode)
                                return -ECONNREFUSED;
  
@@@ -2240,9 -2021,10 +2240,9 @@@ void __l2cap_connect_rsp_defer(struct l
        l2cap_send_cmd(conn, chan->ident,
                                L2CAP_CONN_RSP, sizeof(rsp), &rsp);
  
 -      if (chan->conf_state & L2CAP_CONF_REQ_SENT)
 +      if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                return;
  
 -      chan->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++;
@@@ -2342,11 -2124,17 +2342,11 @@@ static inline int l2cap_connect_req(str
                goto response;
        }
  
 -      sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
 -      if (!sk)
 -              goto response;
 -
 -      chan = l2cap_chan_create(sk);
 -      if (!chan) {
 -              l2cap_sock_kill(sk);
 +      chan = pchan->ops->new_connection(pchan->data);
 +      if (!chan)
                goto response;
 -      }
  
 -      l2cap_pi(sk)->chan = chan;
 +      sk = chan->sk;
  
        write_lock_bh(&conn->chan_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);
 +              chan->ops->close(chan->data);
                goto response;
        }
  
        hci_conn_hold(conn->hcon);
  
 -      l2cap_sock_init(sk, parent);
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
        chan->psm  = psm;
  
        dcid = chan->scid;
  
 -      l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 +      __set_chan_timer(chan, sk->sk_sndtimeo);
  
        chan->ident = cmd->ident;
  
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
                if (l2cap_check_security(chan)) {
                        if (bt_sk(sk)->defer_setup) {
 -                              sk->sk_state = BT_CONNECT2;
 +                              l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
                                parent->sk_data_ready(parent, 0);
                        } else {
 -                              sk->sk_state = BT_CONFIG;
 +                              l2cap_state_change(chan, BT_CONFIG);
                                result = L2CAP_CR_SUCCESS;
                                status = L2CAP_CS_NO_INFO;
                        }
                } else {
 -                      sk->sk_state = BT_CONNECT2;
 +                      l2cap_state_change(chan, BT_CONNECT2);
                        result = L2CAP_CR_PEND;
                        status = L2CAP_CS_AUTHEN_PEND;
                }
        } else {
 -              sk->sk_state = BT_CONNECT2;
 +              l2cap_state_change(chan, BT_CONNECT2);
                result = L2CAP_CR_PEND;
                status = L2CAP_CS_NO_INFO;
        }
@@@ -2424,10 -2213,10 +2424,10 @@@ sendresp
                                        L2CAP_INFO_REQ, sizeof(info), &info);
        }
  
 -      if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
 +      if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
                                result == L2CAP_CR_SUCCESS) {
                u8 buf[128];
 -              chan->conf_state |= L2CAP_CONF_REQ_SENT;
 +              set_bit(CONF_REQ_SENT, &chan->conf_state);
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
@@@ -2465,29 -2254,31 +2465,29 @@@ static inline int l2cap_connect_rsp(str
  
        switch (result) {
        case L2CAP_CR_SUCCESS:
 -              sk->sk_state = BT_CONFIG;
 +              l2cap_state_change(chan, BT_CONFIG);
                chan->ident = 0;
                chan->dcid = dcid;
 -              chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
 +              clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
  
 -              if (chan->conf_state & L2CAP_CONF_REQ_SENT)
 +              if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                        break;
  
 -              chan->conf_state |= L2CAP_CONF_REQ_SENT;
 -
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(chan, req), req);
                chan->num_conf_req++;
                break;
  
        case L2CAP_CR_PEND:
 -              chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 +              set_bit(CONF_CONNECT_PEND, &chan->conf_state);
                break;
  
        default:
                /* don't delete l2cap channel if sk is owned by user */
                if (sock_owned_by_user(sk)) {
 -                      sk->sk_state = BT_DISCONN;
 -                      l2cap_sock_clear_timer(sk);
 -                      l2cap_sock_set_timer(sk, HZ / 5);
 +                      l2cap_state_change(chan, BT_DISCONN);
 +                      __clear_chan_timer(chan);
 +                      __set_chan_timer(chan, HZ / 5);
                        break;
                }
  
  
  static inline void set_default_fcs(struct l2cap_chan *chan)
  {
 -      struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
 -
        /* FCS is enabled only in ERTM or streaming mode, if one or both
         * sides request it.
         */
        if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
                chan->fcs = L2CAP_FCS_NONE;
 -      else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
 +      else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
                chan->fcs = L2CAP_FCS_CRC16;
  }
  
@@@ -2530,7 -2323,8 +2530,8 @@@ static inline int l2cap_config_req(stru
  
        sk = chan->sk;
  
-       if (chan->state != BT_CONFIG) {
 -      if ((bt_sk(sk)->defer_setup && sk->sk_state != BT_CONNECT2) ||
 -               (!bt_sk(sk)->defer_setup && sk->sk_state != BT_CONFIG)) {
++      if ((bt_sk(sk)->defer_setup && chan->state != BT_CONNECT2) ||
++               (!bt_sk(sk)->defer_setup && chan->state != BT_CONFIG)) {
                struct l2cap_cmd_rej rej;
  
                rej.reason = cpu_to_le16(0x0002);
  
        /* Reject if config buffer is too small. */
        len = cmd_len - sizeof(*req);
-       if (chan->conf_len + len > sizeof(chan->conf_req)) {
+       if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                l2cap_build_conf_rsp(chan, rsp,
                                        L2CAP_CONF_REJECT, flags), rsp);
        /* Reset config buffer. */
        chan->conf_len = 0;
  
 -      if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
 +      if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
                goto unlock;
  
 -      if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
 +      if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
  
 -              sk->sk_state = BT_CONNECTED;
 +              l2cap_state_change(chan, BT_CONNECTED);
  
                chan->next_tx_seq = 0;
                chan->expected_tx_seq = 0;
                goto unlock;
        }
  
 -      if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
 +      if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
                u8 buf[64];
 -              chan->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++;
@@@ -2657,7 -2452,7 +2658,7 @@@ static inline int l2cap_config_rsp(stru
  
        default:
                sk->sk_err = ECONNRESET;
 -              l2cap_sock_set_timer(sk, HZ * 5);
 +              __set_chan_timer(chan, HZ * 5);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
        if (flags & 0x01)
                goto done;
  
 -      chan->conf_state |= L2CAP_CONF_INPUT_DONE;
 +      set_bit(CONF_INPUT_DONE, &chan->conf_state);
  
 -      if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
 +      if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
  
 -              sk->sk_state = BT_CONNECTED;
 +              l2cap_state_change(chan, BT_CONNECTED);
                chan->next_tx_seq = 0;
                chan->expected_tx_seq = 0;
                skb_queue_head_init(&chan->tx_q);
@@@ -2712,9 -2507,9 +2713,9 @@@ static inline int l2cap_disconnect_req(
  
        /* don't delete l2cap channel if sk is owned by user */
        if (sock_owned_by_user(sk)) {
 -              sk->sk_state = BT_DISCONN;
 -              l2cap_sock_clear_timer(sk);
 -              l2cap_sock_set_timer(sk, HZ / 5);
 +              l2cap_state_change(chan, BT_DISCONN);
 +              __clear_chan_timer(chan);
 +              __set_chan_timer(chan, HZ / 5);
                bh_unlock_sock(sk);
                return 0;
        }
        l2cap_chan_del(chan, ECONNRESET);
        bh_unlock_sock(sk);
  
 -      l2cap_sock_kill(sk);
 +      chan->ops->close(chan->data);
        return 0;
  }
  
@@@ -2746,9 -2541,9 +2747,9 @@@ static inline int l2cap_disconnect_rsp(
  
        /* don't delete l2cap channel if sk is owned by user */
        if (sock_owned_by_user(sk)) {
 -              sk->sk_state = BT_DISCONN;
 -              l2cap_sock_clear_timer(sk);
 -              l2cap_sock_set_timer(sk, HZ / 5);
 +              l2cap_state_change(chan,BT_DISCONN);
 +              __clear_chan_timer(chan);
 +              __set_chan_timer(chan, HZ / 5);
                bh_unlock_sock(sk);
                return 0;
        }
        l2cap_chan_del(chan, 0);
        bh_unlock_sock(sk);
  
 -      l2cap_sock_kill(sk);
 +      chan->ops->close(chan->data);
        return 0;
  }
  
@@@ -3064,18 -2859,18 +3065,18 @@@ static inline void l2cap_send_i_or_rr_o
  
        control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
  
 -      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
                l2cap_send_sframe(chan, control);
 -              chan->conn_state |= L2CAP_CONN_RNR_SENT;
 +              set_bit(CONN_RNR_SENT, &chan->conn_state);
        }
  
 -      if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
 +      if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                l2cap_retransmit_frames(chan);
  
        l2cap_ertm_send(chan);
  
 -      if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
 +      if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
                        chan->frames_sent == 0) {
                control |= L2CAP_SUPER_RCV_READY;
                l2cap_send_sframe(chan, control);
@@@ -3131,13 -2926,17 +3132,13 @@@ static int l2cap_ertm_reassembly_sdu(st
  
        switch (control & L2CAP_CTRL_SAR) {
        case L2CAP_SDU_UNSEGMENTED:
 -              if (chan->conn_state & L2CAP_CONN_SAR_SDU)
 +              if (test_bit(CONN_SAR_SDU, &chan->conn_state))
                        goto drop;
  
 -              err = sock_queue_rcv_skb(chan->sk, skb);
 -              if (!err)
 -                      return err;
 -
 -              break;
 +              return chan->ops->recv(chan->data, skb);
  
        case L2CAP_SDU_START:
 -              if (chan->conn_state & L2CAP_CONN_SAR_SDU)
 +              if (test_bit(CONN_SAR_SDU, &chan->conn_state))
                        goto drop;
  
                chan->sdu_len = get_unaligned_le16(skb->data);
  
                memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              chan->conn_state |= L2CAP_CONN_SAR_SDU;
 +              set_bit(CONN_SAR_SDU, &chan->conn_state);
                chan->partial_sdu_len = skb->len;
                break;
  
        case L2CAP_SDU_CONTINUE:
 -              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
                        goto disconnect;
  
                if (!chan->sdu)
                break;
  
        case L2CAP_SDU_END:
 -              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
                        goto disconnect;
  
                if (!chan->sdu)
                        goto disconnect;
  
 -              if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
 +              if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) {
                        chan->partial_sdu_len += skb->len;
  
                        if (chan->partial_sdu_len > chan->imtu)
  
                _skb = skb_clone(chan->sdu, GFP_ATOMIC);
                if (!_skb) {
 -                      chan->conn_state |= L2CAP_CONN_SAR_RETRY;
 +                      set_bit(CONN_SAR_RETRY, &chan->conn_state);
                        return -ENOMEM;
                }
  
 -              err = sock_queue_rcv_skb(chan->sk, _skb);
 +              err = chan->ops->recv(chan->data, _skb);
                if (err < 0) {
                        kfree_skb(_skb);
 -                      chan->conn_state |= L2CAP_CONN_SAR_RETRY;
 +                      set_bit(CONN_SAR_RETRY, &chan->conn_state);
                        return err;
                }
  
 -              chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
 -              chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
 +              clear_bit(CONN_SAR_RETRY, &chan->conn_state);
 +              clear_bit(CONN_SAR_SDU, &chan->conn_state);
  
                kfree_skb(chan->sdu);
                break;
@@@ -3244,7 -3043,7 +3245,7 @@@ static int l2cap_try_push_rx_skb(struc
                chan->buffer_seq = (chan->buffer_seq + 1) % 64;
        }
  
 -      if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
 +      if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
                goto done;
  
        control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
        l2cap_send_sframe(chan, control);
        chan->retry_count = 1;
  
 -      del_timer(&chan->retrans_timer);
 -      __mod_monitor_timer();
 +      __clear_retrans_timer(chan);
 +      __set_monitor_timer(chan);
  
 -      chan->conn_state |= L2CAP_CONN_WAIT_F;
 +      set_bit(CONN_WAIT_F, &chan->conn_state);
  
  done:
 -      chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
 -      chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
 +      clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 +      clear_bit(CONN_RNR_SENT, &chan->conn_state);
  
        BT_DBG("chan %p, Exit local busy", chan);
  
@@@ -3317,7 -3116,7 +3318,7 @@@ static int l2cap_push_rx_skb(struct l2c
  {
        int sctrl, err;
  
 -      if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
                bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
                __skb_queue_tail(&chan->busy_q, skb);
                return l2cap_try_push_rx_skb(chan);
        /* Busy Condition */
        BT_DBG("chan %p, Enter local busy", chan);
  
 -      chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
 +      set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
        bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
        __skb_queue_tail(&chan->busy_q, skb);
  
        sctrl |= L2CAP_SUPER_RCV_NOT_READY;
        l2cap_send_sframe(chan, sctrl);
  
 -      chan->conn_state |= L2CAP_CONN_RNR_SENT;
 +      set_bit(CONN_RNR_SENT, &chan->conn_state);
  
 -      del_timer(&chan->ack_timer);
 +      __clear_ack_timer(chan);
  
        queue_work(_busy_wq, &chan->busy_work);
  
@@@ -3363,19 -3162,19 +3364,19 @@@ static int l2cap_streaming_reassembly_s
  
        switch (control & L2CAP_CTRL_SAR) {
        case L2CAP_SDU_UNSEGMENTED:
 -              if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
 +              if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
                        kfree_skb(chan->sdu);
                        break;
                }
  
 -              err = sock_queue_rcv_skb(chan->sk, skb);
 +              err = chan->ops->recv(chan->data, skb);
                if (!err)
                        return 0;
  
                break;
  
        case L2CAP_SDU_START:
 -              if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
 +              if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
                        kfree_skb(chan->sdu);
                        break;
                }
  
                memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              chan->conn_state |= L2CAP_CONN_SAR_SDU;
 +              set_bit(CONN_SAR_SDU, &chan->conn_state);
                chan->partial_sdu_len = skb->len;
                err = 0;
                break;
  
        case L2CAP_SDU_CONTINUE:
 -              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
                        break;
  
                memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
                break;
  
        case L2CAP_SDU_END:
 -              if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
 +              if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
                        break;
  
                memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
  
 -              chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
 +              clear_bit(CONN_SAR_SDU, &chan->conn_state);
                chan->partial_sdu_len += skb->len;
  
                if (chan->partial_sdu_len > chan->imtu)
  
                if (chan->partial_sdu_len == chan->sdu_len) {
                        _skb = skb_clone(chan->sdu, GFP_ATOMIC);
 -                      err = sock_queue_rcv_skb(chan->sk, _skb);
 +                      err = chan->ops->recv(chan->data, _skb);
                        if (err < 0)
                                kfree_skb(_skb);
                }
@@@ -3512,11 -3311,11 +3513,11 @@@ static inline int l2cap_data_channel_if
                                                        tx_seq, rx_control);
  
        if (L2CAP_CTRL_FINAL & rx_control &&
 -                      chan->conn_state & L2CAP_CONN_WAIT_F) {
 -              del_timer(&chan->monitor_timer);
 +                      test_bit(CONN_WAIT_F, &chan->conn_state)) {
 +              __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
 -                      __mod_retrans_timer();
 -              chan->conn_state &= ~L2CAP_CONN_WAIT_F;
 +                      __set_retrans_timer(chan);
 +              clear_bit(CONN_WAIT_F, &chan->conn_state);
        }
  
        chan->expected_ack_seq = req_seq;
                goto drop;
        }
  
 -      if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
                goto drop;
  
 -      if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 +      if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                struct srej_list *first;
  
                first = list_first_entry(&chan->srej_l,
  
                        if (list_empty(&chan->srej_l)) {
                                chan->buffer_seq = chan->buffer_seq_srej;
 -                              chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
 +                              clear_bit(CONN_SREJ_SENT, &chan->conn_state);
                                l2cap_send_ack(chan);
                                BT_DBG("chan %p, Exit SREJ_SENT", chan);
                        }
                if (tx_seq_offset < expected_tx_seq_offset)
                        goto drop;
  
 -              chan->conn_state |= L2CAP_CONN_SREJ_SENT;
 +              set_bit(CONN_SREJ_SENT, &chan->conn_state);
  
                BT_DBG("chan %p, Enter SREJ", chan);
  
                __skb_queue_head_init(&chan->busy_q);
                l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
  
 -              chan->conn_state |= L2CAP_CONN_SEND_PBIT;
 +              set_bit(CONN_SEND_PBIT, &chan->conn_state);
  
                l2cap_send_srejframe(chan, tx_seq);
  
 -              del_timer(&chan->ack_timer);
 +              __clear_ack_timer(chan);
        }
        return 0;
  
  expected:
        chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
  
 -      if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 +      if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                bt_cb(skb)->tx_seq = tx_seq;
                bt_cb(skb)->sar = sar;
                __skb_queue_tail(&chan->srej_q, skb);
                return 0;
  
        if (rx_control & L2CAP_CTRL_FINAL) {
 -              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 -                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 -              else
 +              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        }
  
 -      __mod_ack_timer();
 +      __set_ack_timer(chan);
  
        chan->num_acked = (chan->num_acked + 1) % num_to_ack;
        if (chan->num_acked == num_to_ack - 1)
@@@ -3641,31 -3442,33 +3642,31 @@@ static inline void l2cap_data_channel_r
        l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_POLL) {
 -              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 -              if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
 -                      if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 +              set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +              if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 +                      if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
                                        (chan->unacked_frames > 0))
 -                              __mod_retrans_timer();
 +                              __set_retrans_timer(chan);
  
 -                      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +                      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
                        l2cap_send_srejtail(chan);
                } else {
                        l2cap_send_i_or_rr_or_rnr(chan);
                }
  
        } else if (rx_control & L2CAP_CTRL_FINAL) {
 -              chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +              clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
 -              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 -                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 -              else
 +              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
  
        } else {
 -              if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
 +              if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
                                (chan->unacked_frames > 0))
 -                      __mod_retrans_timer();
 +                      __set_retrans_timer(chan);
  
 -              chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 -              if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
 +              clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 +              if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
                        l2cap_send_ack(chan);
                else
                        l2cap_ertm_send(chan);
@@@ -3678,19 -3481,21 +3679,19 @@@ static inline void l2cap_data_channel_r
  
        BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_FINAL) {
 -              if (chan->conn_state & L2CAP_CONN_REJ_ACT)
 -                      chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
 -              else
 +              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        } else {
                l2cap_retransmit_frames(chan);
  
 -              if (chan->conn_state & L2CAP_CONN_WAIT_F)
 -                      chan->conn_state |= L2CAP_CONN_REJ_ACT;
 +              if (test_bit(CONN_WAIT_F, &chan->conn_state))
 +                      set_bit(CONN_REJ_ACT, &chan->conn_state);
        }
  }
  static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
  
        BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 +      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
        if (rx_control & L2CAP_CTRL_POLL) {
                chan->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(chan);
  
 -              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 +              set_bit(CONN_SEND_FBIT, &chan->conn_state);
                l2cap_retransmit_one_frame(chan, tx_seq);
  
                l2cap_ertm_send(chan);
  
 -              if (chan->conn_state & L2CAP_CONN_WAIT_F) {
 +              if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
                        chan->srej_save_reqseq = tx_seq;
 -                      chan->conn_state |= L2CAP_CONN_SREJ_ACT;
 +                      set_bit(CONN_SREJ_ACT, &chan->conn_state);
                }
        } else if (rx_control & L2CAP_CTRL_FINAL) {
 -              if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
 +              if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
                                chan->srej_save_reqseq == tx_seq)
 -                      chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
 +                      clear_bit(CONN_SREJ_ACT, &chan->conn_state);
                else
                        l2cap_retransmit_one_frame(chan, tx_seq);
        } else {
                l2cap_retransmit_one_frame(chan, tx_seq);
 -              if (chan->conn_state & L2CAP_CONN_WAIT_F) {
 +              if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
                        chan->srej_save_reqseq = tx_seq;
 -                      chan->conn_state |= L2CAP_CONN_SREJ_ACT;
 +                      set_bit(CONN_SREJ_ACT, &chan->conn_state);
                }
        }
  }
@@@ -3735,15 -3540,15 +3736,15 @@@ static inline void l2cap_data_channel_r
  
        BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
  
 -      chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
 +      set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
  
        if (rx_control & L2CAP_CTRL_POLL)
 -              chan->conn_state |= L2CAP_CONN_SEND_FBIT;
 +              set_bit(CONN_SEND_FBIT, &chan->conn_state);
  
 -      if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
 -              del_timer(&chan->retrans_timer);
 +      if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 +              __clear_retrans_timer(chan);
                if (rx_control & L2CAP_CTRL_POLL)
                        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
                return;
@@@ -3760,11 -3565,11 +3761,11 @@@ static inline int l2cap_data_channel_sf
        BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
  
        if (L2CAP_CTRL_FINAL & rx_control &&
 -                      chan->conn_state & L2CAP_CONN_WAIT_F) {
 -              del_timer(&chan->monitor_timer);
 +                      test_bit(CONN_WAIT_F, &chan->conn_state)) {
 +              __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
 -                      __mod_retrans_timer();
 -              chan->conn_state &= ~L2CAP_CONN_WAIT_F;
 +                      __set_retrans_timer(chan);
 +              clear_bit(CONN_WAIT_F, &chan->conn_state);
        }
  
        switch (rx_control & L2CAP_CTRL_SUPERVISE) {
@@@ -3863,6 -3668,7 +3864,6 @@@ static inline int l2cap_data_channel(st
  {
        struct l2cap_chan *chan;
        struct sock *sk = NULL;
 -      struct l2cap_pinfo *pi;
        u16 control;
        u8 tx_seq;
        int len;
        }
  
        sk = chan->sk;
  
        BT_DBG("chan %p, len %d", chan, skb->len);
  
 -      if (sk->sk_state != BT_CONNECTED)
 +      if (chan->state != BT_CONNECTED)
                goto drop;
  
        switch (chan->mode) {
                if (chan->imtu < skb->len)
                        goto drop;
  
 -              if (!sock_queue_rcv_skb(sk, skb))
 +              if (!chan->ops->recv(chan->data, skb))
                        goto done;
                break;
  
@@@ -3962,13 -3769,13 +3963,13 @@@ static inline int l2cap_conless_channel
  
        BT_DBG("sk %p, len %d", sk, skb->len);
  
 -      if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
 +      if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
  
 -      if (l2cap_pi(sk)->chan->imtu < skb->len)
 +      if (chan->imtu < skb->len)
                goto drop;
  
 -      if (!sock_queue_rcv_skb(sk, skb))
 +      if (!chan->ops->recv(chan->data, skb))
                goto done;
  
  drop:
@@@ -3995,13 -3802,13 +3996,13 @@@ static inline int l2cap_att_channel(str
  
        BT_DBG("sk %p, len %d", sk, skb->len);
  
 -      if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
 +      if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
                goto drop;
  
 -      if (l2cap_pi(sk)->chan->imtu < skb->len)
 +      if (chan->imtu < skb->len)
                goto drop;
  
 -      if (!sock_queue_rcv_skb(sk, skb))
 +      if (!chan->ops->recv(chan->data, skb))
                goto done;
  
  drop:
@@@ -4046,11 -3853,6 +4047,11 @@@ static void l2cap_recv_frame(struct l2c
                l2cap_att_channel(conn, cid, skb);
                break;
  
 +      case L2CAP_CID_SMP:
 +              if (smp_sig_channel(conn, skb))
 +                      l2cap_conn_del(conn->hcon, EACCES);
 +              break;
 +
        default:
                l2cap_data_channel(conn, cid, skb);
                break;
@@@ -4074,7 -3876,7 +4075,7 @@@ static int l2cap_connect_ind(struct hci
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
  
 -              if (sk->sk_state != BT_LISTEN)
 +              if (c->state != BT_LISTEN)
                        continue;
  
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
@@@ -4118,7 -3920,7 +4119,7 @@@ static int l2cap_disconn_ind(struct hci
  
        BT_DBG("hcon %p", hcon);
  
 -      if (hcon->type != ACL_LINK || !conn)
 +      if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
                return 0x13;
  
        return conn->disc_reason;
@@@ -4138,18 -3940,20 +4139,18 @@@ static int l2cap_disconn_cfm(struct hci
  
  static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
  {
 -      struct sock *sk = chan->sk;
 -
 -      if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM)
 +      if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
                return;
  
        if (encrypt == 0x00) {
                if (chan->sec_level == BT_SECURITY_MEDIUM) {
 -                      l2cap_sock_clear_timer(sk);
 -                      l2cap_sock_set_timer(sk, HZ * 5);
 +                      __clear_chan_timer(chan);
 +                      __set_chan_timer(chan, HZ * 5);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
 -                      __l2cap_sock_close(sk, ECONNREFUSED);
 +                      l2cap_chan_close(chan, ECONNREFUSED);
        } else {
                if (chan->sec_level == BT_SECURITY_MEDIUM)
 -                      l2cap_sock_clear_timer(sk);
 +                      __clear_chan_timer(chan);
        }
  }
  
@@@ -4170,47 -3974,34 +4171,47 @@@ static int l2cap_security_cfm(struct hc
  
                bh_lock_sock(sk);
  
 -              if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
 +              BT_DBG("chan->scid %d", chan->scid);
 +
 +              if (chan->scid == L2CAP_CID_LE_DATA) {
 +                      if (!status && encrypt) {
 +                              chan->sec_level = hcon->sec_level;
 +                              del_timer(&conn->security_timer);
 +                              l2cap_chan_ready(sk);
 +                      }
 +
                        bh_unlock_sock(sk);
                        continue;
                }
  
 -              if (!status && (sk->sk_state == BT_CONNECTED ||
 -                                              sk->sk_state == BT_CONFIG)) {
 +              if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
 +                      bh_unlock_sock(sk);
 +                      continue;
 +              }
 +
 +              if (!status && (chan->state == BT_CONNECTED ||
 +                                              chan->state == BT_CONFIG)) {
                        l2cap_check_encryption(chan, encrypt);
                        bh_unlock_sock(sk);
                        continue;
                }
  
 -              if (sk->sk_state == BT_CONNECT) {
 +              if (chan->state == BT_CONNECT) {
                        if (!status) {
                                struct l2cap_conn_req req;
                                req.scid = cpu_to_le16(chan->scid);
                                req.psm  = chan->psm;
  
                                chan->ident = l2cap_get_ident(conn);
 -                              chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
 +                              set_bit(CONF_CONNECT_PEND, &chan->conf_state);
  
                                l2cap_send_cmd(conn, chan->ident,
                                        L2CAP_CONN_REQ, sizeof(req), &req);
                        } else {
 -                              l2cap_sock_clear_timer(sk);
 -                              l2cap_sock_set_timer(sk, HZ / 10);
 +                              __clear_chan_timer(chan);
 +                              __set_chan_timer(chan, HZ / 10);
                        }
 -              } else if (sk->sk_state == BT_CONNECT2) {
 +              } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
                        __u16 res, stat;
  
                                        stat = L2CAP_CS_AUTHOR_PEND;
                                        parent->sk_data_ready(parent, 0);
                                } else {
 -                                      sk->sk_state = BT_CONFIG;
 +                                      l2cap_state_change(chan, BT_CONFIG);
                                        res = L2CAP_CR_SUCCESS;
                                        stat = L2CAP_CS_NO_INFO;
                                }
                        } else {
 -                              sk->sk_state = BT_DISCONN;
 -                              l2cap_sock_set_timer(sk, HZ / 10);
 +                              l2cap_state_change(chan, BT_DISCONN);
 +                              __set_chan_timer(chan, HZ / 10);
                                res = L2CAP_CR_SEC_BLOCK;
                                stat = L2CAP_CS_NO_INFO;
                        }
@@@ -4371,10 -4162,10 +4372,10 @@@ static int l2cap_debugfs_show(struct se
                seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
                                        batostr(&bt_sk(sk)->src),
                                        batostr(&bt_sk(sk)->dst),
 -                                      sk->sk_state, __le16_to_cpu(c->psm),
 +                                      c->state, __le16_to_cpu(c->psm),
                                        c->scid, c->dcid, c->imtu, c->omtu,
                                        c->sec_level, c->mode);
 -      }
 +}
  
        read_unlock_bh(&chan_list_lock);
  
diff --combined net/mac80211/scan.c
@@@ -228,7 -228,6 +228,7 @@@ ieee80211_scan_rx(struct ieee80211_sub_
  static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
  {
        struct cfg80211_scan_request *req = local->scan_req;
 +      struct ieee80211_sub_if_data *sdata = local->scan_sdata;
        enum ieee80211_band band;
        int i, ielen, n_chans;
  
        local->hw_scan_req->n_channels = n_chans;
  
        ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
 -                                       req->ie, req->ie_len, band, (u32) -1,
 -                                       0);
 +                                       req->ie, req->ie_len, band,
 +                                       sdata->rc_rateidx_mask[band], 0);
        local->hw_scan_req->ie_len = ielen;
  
        return true;
@@@ -659,8 -658,7 +659,8 @@@ static void ieee80211_scan_state_send_p
                        sdata, NULL,
                        local->scan_req->ssids[i].ssid,
                        local->scan_req->ssids[i].ssid_len,
 -                      local->scan_req->ie, local->scan_req->ie_len);
 +                      local->scan_req->ie, local->scan_req->ie_len,
 +                      false);
  
        /*
         * After sending probe requests, wait for probe responses
@@@ -823,8 -821,10 +823,8 @@@ int ieee80211_request_internal_scan(str
   */
  void ieee80211_scan_cancel(struct ieee80211_local *local)
  {
 -      bool abortscan;
 -
        /*
 -       * We are only canceling software scan, or deferred scan that was not
 +       * We are canceling software scan, or deferred scan that was not
         * yet really started (see __ieee80211_start_scan ).
         *
         * Regarding hardware scan:
         * - we can not cancel scan_work since driver can schedule it
         *   by ieee80211_scan_completed(..., true) to finish scan
         *
 -       * Hence low lever driver is responsible for canceling HW scan.
 +       * Hence we only call the cancel_hw_scan() callback, but the low-level
 +       * driver is still responsible for calling ieee80211_scan_completed()
 +       * after the scan was completed/aborted.
         */
  
        mutex_lock(&local->mtx);
 -      abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
 -      if (abortscan) {
 -              /*
 -               * The scan is canceled, but stop work from being pending.
 -               *
 -               * If the work is currently running, it must be blocked on
 -               * the mutex, but we'll set scan_sdata = NULL and it'll
 -               * simply exit once it acquires the mutex.
 -               */
 -              cancel_delayed_work(&local->scan_work);
 -              /* and clean up */
 -              __ieee80211_scan_completed(&local->hw, true, false);
 +      if (!local->scan_req)
 +              goto out;
 +
 +      if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
 +              if (local->ops->cancel_hw_scan)
 +                      drv_cancel_hw_scan(local, local->scan_sdata);
 +              goto out;
        }
 +
 +      /*
 +       * If the work is currently running, it must be blocked on
 +       * the mutex, but we'll set scan_sdata = NULL and it'll
 +       * simply exit once it acquires the mutex.
 +       */
 +      cancel_delayed_work(&local->scan_work);
 +      /* and clean up */
 +      __ieee80211_scan_completed(&local->hw, true, false);
 +out:
        mutex_unlock(&local->mtx);
  }
  
@@@ -884,7 -877,8 +884,8 @@@ int ieee80211_request_sched_scan_start(
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                local->sched_scan_ies.ie[i] = kzalloc(2 +
                                                      IEEE80211_MAX_SSID_LEN +
-                                                     local->scan_ies_len,
+                                                     local->scan_ies_len +
+                                                     req->ie_len,
                                                      GFP_KERNEL);
                if (!local->sched_scan_ies.ie[i]) {
                        ret = -ENOMEM;
diff --combined net/wireless/nl80211.c
@@@ -176,7 -176,6 +176,7 @@@ static const struct nla_policy nl80211_
        [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
        [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
        [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
 +      [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
  };
  
  /* policy for the key attributes */
@@@ -207,14 -206,6 +207,14 @@@ nl80211_wowlan_policy[NUM_NL80211_WOWLA
        [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
  };
  
 +/* policy for GTK rekey offload attributes */
 +static const struct nla_policy
 +nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
 +      [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
 +      [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
 +      [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
 +};
 +
  /* ifidx get helper */
  static int nl80211_get_ifidx(struct netlink_callback *cb)
  {
@@@ -3470,9 -3461,6 +3470,6 @@@ static int nl80211_start_sched_scan(str
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
  
-       if (rdev->sched_scan_req)
-               return -EINPROGRESS;
        if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
                return -EINVAL;
  
        if (ie_len > wiphy->max_scan_ie_len)
                return -EINVAL;
  
+       mutex_lock(&rdev->sched_scan_mtx);
+       if (rdev->sched_scan_req) {
+               err = -EINPROGRESS;
+               goto out;
+       }
        request = kzalloc(sizeof(*request)
                        + sizeof(*request->ssids) * n_ssids
                        + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
-       if (!request)
-               return -ENOMEM;
+       if (!request) {
+               err = -ENOMEM;
+               goto out;
+       }
  
        if (n_ssids)
                request->ssids = (void *)&request->channels[n_channels];
  out_free:
        kfree(request);
  out:
+       mutex_unlock(&rdev->sched_scan_mtx);
        return err;
  }
  
@@@ -3621,16 -3619,20 +3628,21 @@@ static int nl80211_stop_sched_scan(stru
                                   struct genl_info *info)
  {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       int err;
  
        if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
            !rdev->ops->sched_scan_stop)
                return -EOPNOTSUPP;
  
-       return __cfg80211_stop_sched_scan(rdev, false);
+       mutex_lock(&rdev->sched_scan_mtx);
+       err = __cfg80211_stop_sched_scan(rdev, false);
+       mutex_unlock(&rdev->sched_scan_mtx);
+       return err;
  }
  
 -static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 +static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
 +                          u32 seq, int flags,
                            struct cfg80211_registered_device *rdev,
                            struct wireless_dev *wdev,
                            struct cfg80211_internal_bss *intbss)
  
        ASSERT_WDEV_LOCK(wdev);
  
 -      hdr = nl80211hdr_put(msg, pid, seq, flags,
 +      hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).pid, seq, flags,
                             NL80211_CMD_NEW_SCAN_RESULTS);
        if (!hdr)
                return -1;
  
 +      genl_dump_check_consistent(cb, hdr, &nl80211_fam);
 +
        NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex);
  
@@@ -3737,12 -3737,11 +3749,12 @@@ static int nl80211_dump_scan(struct sk_
        spin_lock_bh(&rdev->bss_lock);
        cfg80211_bss_expire(rdev);
  
 +      cb->seq = rdev->bss_generation;
 +
        list_for_each_entry(scan, &rdev->bss_list, list) {
                if (++idx <= start)
                        continue;
 -              if (nl80211_send_bss(skb,
 -                              NETLINK_CB(cb->skb).pid,
 +              if (nl80211_send_bss(skb, cb,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                rdev, wdev, scan) < 0) {
                        idx--;
@@@ -3766,6 -3765,10 +3778,6 @@@ static int nl80211_send_survey(struct s
        void *hdr;
        struct nlattr *infoattr;
  
 -      /* Survey without a channel doesn't make sense */
 -      if (!survey->channel)
 -              return -EINVAL;
 -
        hdr = nl80211hdr_put(msg, pid, seq, flags,
                             NL80211_CMD_NEW_SURVEY_RESULTS);
        if (!hdr)
@@@ -3828,8 -3831,6 +3840,8 @@@ static int nl80211_dump_survey(struct s
        }
  
        while (1) {
 +              struct ieee80211_channel *chan;
 +
                res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
                                            &survey);
                if (res == -ENOENT)
                if (res)
                        goto out_err;
  
 +              /* Survey without a channel doesn't make sense */
 +              if (!survey.channel) {
 +                      res = -EINVAL;
 +                      goto out;
 +              }
 +
 +              chan = ieee80211_get_channel(&dev->wiphy,
 +                                           survey.channel->center_freq);
 +              if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
 +                      survey_idx++;
 +                      continue;
 +              }
 +
                if (nl80211_send_survey(skb,
                                NETLINK_CB(cb->skb).pid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
@@@ -4384,93 -4372,6 +4396,93 @@@ static int nl80211_testmode_do(struct s
        return err;
  }
  
 +static int nl80211_testmode_dump(struct sk_buff *skb,
 +                               struct netlink_callback *cb)
 +{
 +      struct cfg80211_registered_device *dev;
 +      int err;
 +      long phy_idx;
 +      void *data = NULL;
 +      int data_len = 0;
 +
 +      if (cb->args[0]) {
 +              /*
 +               * 0 is a valid index, but not valid for args[0],
 +               * so we need to offset by 1.
 +               */
 +              phy_idx = cb->args[0] - 1;
 +      } else {
 +              err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
 +                                nl80211_fam.attrbuf, nl80211_fam.maxattr,
 +                                nl80211_policy);
 +              if (err)
 +                      return err;
 +              if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY])
 +                      return -EINVAL;
 +              phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
 +              if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
 +                      cb->args[1] =
 +                              (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
 +      }
 +
 +      if (cb->args[1]) {
 +              data = nla_data((void *)cb->args[1]);
 +              data_len = nla_len((void *)cb->args[1]);
 +      }
 +
 +      mutex_lock(&cfg80211_mutex);
 +      dev = cfg80211_rdev_by_wiphy_idx(phy_idx);
 +      if (!dev) {
 +              mutex_unlock(&cfg80211_mutex);
 +              return -ENOENT;
 +      }
 +      cfg80211_lock_rdev(dev);
 +      mutex_unlock(&cfg80211_mutex);
 +
 +      if (!dev->ops->testmode_dump) {
 +              err = -EOPNOTSUPP;
 +              goto out_err;
 +      }
 +
 +      while (1) {
 +              void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid,
 +                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
 +                                         NL80211_CMD_TESTMODE);
 +              struct nlattr *tmdata;
 +
 +              if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) {
 +                      genlmsg_cancel(skb, hdr);
 +                      break;
 +              }
 +
 +              tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
 +              if (!tmdata) {
 +                      genlmsg_cancel(skb, hdr);
 +                      break;
 +              }
 +              err = dev->ops->testmode_dump(&dev->wiphy, skb, cb,
 +                                            data, data_len);
 +              nla_nest_end(skb, tmdata);
 +
 +              if (err == -ENOBUFS || err == -ENOENT) {
 +                      genlmsg_cancel(skb, hdr);
 +                      break;
 +              } else if (err) {
 +                      genlmsg_cancel(skb, hdr);
 +                      goto out_err;
 +              }
 +
 +              genlmsg_end(skb, hdr);
 +      }
 +
 +      err = skb->len;
 +      /* see above */
 +      cb->args[0] = phy_idx + 1;
 + out_err:
 +      cfg80211_unlock_rdev(dev);
 +      return err;
 +}
 +
  static struct sk_buff *
  __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
                              int approxlen, u32 pid, u32 seq, gfp_t gfp)
@@@ -5417,57 -5318,6 +5429,57 @@@ static int nl80211_set_wowlan(struct sk
        return err;
  }
  
 +static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +      struct net_device *dev = info->user_ptr[1];
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +      struct nlattr *tb[NUM_NL80211_REKEY_DATA];
 +      struct cfg80211_gtk_rekey_data rekey_data;
 +      int err;
 +
 +      if (!info->attrs[NL80211_ATTR_REKEY_DATA])
 +              return -EINVAL;
 +
 +      err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
 +                      nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
 +                      nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
 +                      nl80211_rekey_policy);
 +      if (err)
 +              return err;
 +
 +      if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
 +              return -ERANGE;
 +      if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
 +              return -ERANGE;
 +      if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
 +              return -ERANGE;
 +
 +      memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]),
 +             NL80211_KEK_LEN);
 +      memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]),
 +             NL80211_KCK_LEN);
 +      memcpy(rekey_data.replay_ctr,
 +             nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]),
 +             NL80211_REPLAY_CTR_LEN);
 +
 +      wdev_lock(wdev);
 +      if (!wdev->current_bss) {
 +              err = -ENOTCONN;
 +              goto out;
 +      }
 +
 +      if (!rdev->ops->set_rekey_data) {
 +              err = -EOPNOTSUPP;
 +              goto out;
 +      }
 +
 +      err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data);
 + out:
 +      wdev_unlock(wdev);
 +      return err;
 +}
 +
  #define NL80211_FLAG_NEED_WIPHY               0x01
  #define NL80211_FLAG_NEED_NETDEV      0x02
  #define NL80211_FLAG_NEED_RTNL                0x04
@@@ -5819,7 -5669,6 +5831,7 @@@ static struct genl_ops nl80211_ops[] = 
        {
                .cmd = NL80211_CMD_TESTMODE,
                .doit = nl80211_testmode_do,
 +              .dumpit = nl80211_testmode_dump,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
                                  NL80211_FLAG_NEED_RTNL,
        },
 +      {
 +              .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
 +              .doit = nl80211_set_rekey_data,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
  };
  
  static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@@ -6951,51 -6792,6 +6963,51 @@@ nl80211_send_cqm_rssi_notify(struct cfg
        nlmsg_free(msg);
  }
  
 +void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 +                            struct net_device *netdev, const u8 *bssid,
 +                            const u8 *replay_ctr, gfp_t gfp)
 +{
 +      struct sk_buff *msg;
 +      struct nlattr *rekey_attr;
 +      void *hdr;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
 +      if (!msg)
 +              return;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 +      NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
 +
 +      rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
 +      if (!rekey_attr)
 +              goto nla_put_failure;
 +
 +      NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR,
 +              NL80211_REPLAY_CTR_LEN, replay_ctr);
 +
 +      nla_nest_end(msg, rekey_attr);
 +
 +      if (genlmsg_end(msg, hdr) < 0) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
 +                              nl80211_mlme_mcgrp.id, gfp);
 +      return;
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +}
 +
  void
  nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
                                struct net_device *netdev, const u8 *peer,
diff --combined net/wireless/scan.c
@@@ -100,14 -100,14 +100,14 @@@ void __cfg80211_sched_scan_results(stru
        rdev = container_of(wk, struct cfg80211_registered_device,
                            sched_scan_results_wk);
  
-       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->sched_scan_mtx);
  
        /* we don't have sched_scan_req anymore if the scan is stopping */
        if (rdev->sched_scan_req)
                nl80211_send_sched_scan_results(rdev,
                                                rdev->sched_scan_req->dev);
  
-       cfg80211_unlock_rdev(rdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
  }
  
  void cfg80211_sched_scan_results(struct wiphy *wiphy)
@@@ -123,26 -123,27 +123,26 @@@ void cfg80211_sched_scan_stopped(struc
  {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  
-       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->sched_scan_mtx);
        __cfg80211_stop_sched_scan(rdev, true);
-       cfg80211_unlock_rdev(rdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
  }
  EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
  
  int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
                               bool driver_initiated)
  {
 -      int err;
        struct net_device *dev;
  
-       ASSERT_RDEV_LOCK(rdev);
+       lockdep_assert_held(&rdev->sched_scan_mtx);
  
        if (!rdev->sched_scan_req)
 -              return 0;
 +              return -ENOENT;
  
        dev = rdev->sched_scan_req->dev;
  
        if (!driver_initiated) {
 -              err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
 +              int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
                if (err)
                        return err;
        }
        kfree(rdev->sched_scan_req);
        rdev->sched_scan_req = NULL;
  
 -      return err;
 +      return 0;
  }
  
  static void bss_release(struct kref *ref)