]> Git Repo - linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <[email protected]>
Wed, 13 Jun 2012 19:35:35 +0000 (15:35 -0400)
committerJohn W. Linville <[email protected]>
Wed, 13 Jun 2012 19:35:35 +0000 (15:35 -0400)
Conflicts:
drivers/net/wireless/ath/ath9k/main.c
net/bluetooth/hci_event.c

1  2 
drivers/net/wireless/ath/ath9k/main.c
include/net/bluetooth/hci.h
include/net/mac80211.h
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/mac80211/cfg.c
net/mac80211/mlme.c

index a6f83b683db198b2de11be6d92100a04356d7f51,dac1a2709e3cb7aa961240a088ef15fe3311bec2..52561b341d68798e55bbe8237e589da274b539b7
@@@ -101,7 -101,6 +101,7 @@@ void ath9k_ps_wakeup(struct ath_softc *
                spin_lock(&common->cc_lock);
                ath_hw_cycle_counters_update(common);
                memset(&common->cc_survey, 0, sizeof(common->cc_survey));
 +              memset(&common->cc_ani, 0, sizeof(common->cc_ani));
                spin_unlock(&common->cc_lock);
        }
  
@@@ -144,15 -143,90 +144,15 @@@ void ath9k_ps_restore(struct ath_softc 
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  }
  
 -void ath_start_ani(struct ath_common *common)
 -{
 -      struct ath_hw *ah = common->ah;
 -      unsigned long timestamp = jiffies_to_msecs(jiffies);
 -      struct ath_softc *sc = (struct ath_softc *) common->priv;
 -
 -      if (!(sc->sc_flags & SC_OP_ANI_RUN))
 -              return;
 -
 -      if (sc->sc_flags & SC_OP_OFFCHANNEL)
 -              return;
 -
 -      common->ani.longcal_timer = timestamp;
 -      common->ani.shortcal_timer = timestamp;
 -      common->ani.checkani_timer = timestamp;
 -
 -      mod_timer(&common->ani.timer,
 -                jiffies +
 -                      msecs_to_jiffies((u32)ah->config.ani_poll_interval));
 -}
 -
 -static void ath_update_survey_nf(struct ath_softc *sc, int channel)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath9k_channel *chan = &ah->channels[channel];
 -      struct survey_info *survey = &sc->survey[channel];
 -
 -      if (chan->noisefloor) {
 -              survey->filled |= SURVEY_INFO_NOISE_DBM;
 -              survey->noise = ath9k_hw_getchan_noise(ah, chan);
 -      }
 -}
 -
 -/*
 - * Updates the survey statistics and returns the busy time since last
 - * update in %, if the measurement duration was long enough for the
 - * result to be useful, -1 otherwise.
 - */
 -static int ath_update_survey_stats(struct ath_softc *sc)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -      int pos = ah->curchan - &ah->channels[0];
 -      struct survey_info *survey = &sc->survey[pos];
 -      struct ath_cycle_counters *cc = &common->cc_survey;
 -      unsigned int div = common->clockrate * 1000;
 -      int ret = 0;
 -
 -      if (!ah->curchan)
 -              return -1;
 -
 -      if (ah->power_mode == ATH9K_PM_AWAKE)
 -              ath_hw_cycle_counters_update(common);
 -
 -      if (cc->cycles > 0) {
 -              survey->filled |= SURVEY_INFO_CHANNEL_TIME |
 -                      SURVEY_INFO_CHANNEL_TIME_BUSY |
 -                      SURVEY_INFO_CHANNEL_TIME_RX |
 -                      SURVEY_INFO_CHANNEL_TIME_TX;
 -              survey->channel_time += cc->cycles / div;
 -              survey->channel_time_busy += cc->rx_busy / div;
 -              survey->channel_time_rx += cc->rx_frame / div;
 -              survey->channel_time_tx += cc->tx_frame / div;
 -      }
 -
 -      if (cc->cycles < div)
 -              return -1;
 -
 -      if (cc->cycles > 0)
 -              ret = cc->rx_busy * 100 / cc->cycles;
 -
 -      memset(cc, 0, sizeof(*cc));
 -
 -      ath_update_survey_nf(sc, pos);
 -
 -      return ret;
 -}
 -
  static void __ath_cancel_work(struct ath_softc *sc)
  {
        cancel_work_sync(&sc->paprd_work);
        cancel_work_sync(&sc->hw_check_work);
        cancel_delayed_work_sync(&sc->tx_complete_work);
        cancel_delayed_work_sync(&sc->hw_pll_work);
 +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 +      cancel_work_sync(&sc->mci_work);
 +#endif
  }
  
  static void ath_cancel_work(struct ath_softc *sc)
        cancel_work_sync(&sc->hw_reset_work);
  }
  
 +static void ath_restart_work(struct ath_softc *sc)
 +{
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +
 +      ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 +
 +      if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah))
 +              ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
 +                                   msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 +
 +      ath_start_rx_poll(sc, 3);
 +
 +      if (!common->disable_ani)
 +              ath_start_ani(common);
 +}
 +
  static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
  {
        struct ath_hw *ah = sc->sc_ah;
@@@ -213,7 -271,6 +213,7 @@@ static bool ath_complete_reset(struct a
  {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 +      unsigned long flags;
  
        if (ath_startrecv(sc) != 0) {
                ath_err(common, "Unable to restart recv logic\n");
  
        ath9k_cmn_update_txpow(ah, sc->curtxpow,
                               sc->config.txpowlimit, &sc->curtxpow);
 +
 +      clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
        ath9k_hw_set_interrupts(ah);
        ath9k_hw_enable_interrupts(ah);
  
 -      if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
 -              if (sc->sc_flags & SC_OP_BEACONS)
 -                      ath_set_beacon(sc);
 -
 -              ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 -              ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
 -              ath_start_rx_poll(sc, 3);
 -              if (!common->disable_ani)
 -                      ath_start_ani(common);
 -      }
 -
 -      if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
 -              struct ath_hw_antcomb_conf div_ant_conf;
 -              u8 lna_conf;
 +      if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
 +              if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
 +                      goto work;
  
 -              ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
 -
 -              if (sc->ant_rx == 1)
 -                      lna_conf = ATH_ANT_DIV_COMB_LNA1;
 -              else
 -                      lna_conf = ATH_ANT_DIV_COMB_LNA2;
 -              div_ant_conf.main_lna_conf = lna_conf;
 -              div_ant_conf.alt_lna_conf = lna_conf;
 +              ath_set_beacon(sc);
  
 -              ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
 +              if (ah->opmode == NL80211_IFTYPE_STATION &&
 +                  test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
 +                      spin_lock_irqsave(&sc->sc_pm_lock, flags);
 +                      sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 +                      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 +              }
 +      work:
 +              ath_restart_work(sc);
        }
  
 +      if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
 +              ath_ant_comb_update(sc);
 +
        ieee80211_wake_queues(sc->hw);
  
        return true;
@@@ -265,7 -328,7 +265,7 @@@ static int ath_reset_internal(struct at
  
        spin_lock_bh(&sc->sc_pcu_lock);
  
 -      if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
 +      if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
                fastcc = false;
                caldata = &sc->caldata;
        }
@@@ -308,7 -371,7 +308,7 @@@ static int ath_set_channel(struct ath_s
  {
        int r;
  
 -      if (sc->sc_flags & SC_OP_INVALID)
 +      if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
  
        r = ath_reset_internal(sc, hchan, false);
        return r;
  }
  
 -static void ath_paprd_activate(struct ath_softc *sc)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath9k_hw_cal_data *caldata = ah->caldata;
 -      int chain;
 -
 -      if (!caldata || !caldata->paprd_done)
 -              return;
 -
 -      ath9k_ps_wakeup(sc);
 -      ar9003_paprd_enable(ah, false);
 -      for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
 -              if (!(ah->txchainmask & BIT(chain)))
 -                      continue;
 -
 -              ar9003_paprd_populate_single_table(ah, caldata, chain);
 -      }
 -
 -      ar9003_paprd_enable(ah, true);
 -      ath9k_ps_restore(sc);
 -}
 -
 -static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
 -{
 -      struct ieee80211_hw *hw = sc->hw;
 -      struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -      struct ath_tx_control txctl;
 -      int time_left;
 -
 -      memset(&txctl, 0, sizeof(txctl));
 -      txctl.txq = sc->tx.txq_map[WME_AC_BE];
 -
 -      memset(tx_info, 0, sizeof(*tx_info));
 -      tx_info->band = hw->conf.channel->band;
 -      tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
 -      tx_info->control.rates[0].idx = 0;
 -      tx_info->control.rates[0].count = 1;
 -      tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
 -      tx_info->control.rates[1].idx = -1;
 -
 -      init_completion(&sc->paprd_complete);
 -      txctl.paprd = BIT(chain);
 -
 -      if (ath_tx_start(hw, skb, &txctl) != 0) {
 -              ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
 -              dev_kfree_skb_any(skb);
 -              return false;
 -      }
 -
 -      time_left = wait_for_completion_timeout(&sc->paprd_complete,
 -                      msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
 -
 -      if (!time_left)
 -              ath_dbg(common, CALIBRATE,
 -                      "Timeout waiting for paprd training on TX chain %d\n",
 -                      chain);
 -
 -      return !!time_left;
 -}
 -
 -void ath_paprd_calibrate(struct work_struct *work)
 -{
 -      struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
 -      struct ieee80211_hw *hw = sc->hw;
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ieee80211_hdr *hdr;
 -      struct sk_buff *skb = NULL;
 -      struct ath9k_hw_cal_data *caldata = ah->caldata;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -      int ftype;
 -      int chain_ok = 0;
 -      int chain;
 -      int len = 1800;
 -
 -      if (!caldata)
 -              return;
 -
 -      ath9k_ps_wakeup(sc);
 -
 -      if (ar9003_paprd_init_table(ah) < 0)
 -              goto fail_paprd;
 -
 -      skb = alloc_skb(len, GFP_KERNEL);
 -      if (!skb)
 -              goto fail_paprd;
 -
 -      skb_put(skb, len);
 -      memset(skb->data, 0, len);
 -      hdr = (struct ieee80211_hdr *)skb->data;
 -      ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
 -      hdr->frame_control = cpu_to_le16(ftype);
 -      hdr->duration_id = cpu_to_le16(10);
 -      memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
 -      memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
 -      memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
 -
 -      for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
 -              if (!(ah->txchainmask & BIT(chain)))
 -                      continue;
 -
 -              chain_ok = 0;
 -
 -              ath_dbg(common, CALIBRATE,
 -                      "Sending PAPRD frame for thermal measurement on chain %d\n",
 -                      chain);
 -              if (!ath_paprd_send_frame(sc, skb, chain))
 -                      goto fail_paprd;
 -
 -              ar9003_paprd_setup_gain_table(ah, chain);
 -
 -              ath_dbg(common, CALIBRATE,
 -                      "Sending PAPRD training frame on chain %d\n", chain);
 -              if (!ath_paprd_send_frame(sc, skb, chain))
 -                      goto fail_paprd;
 -
 -              if (!ar9003_paprd_is_done(ah)) {
 -                      ath_dbg(common, CALIBRATE,
 -                              "PAPRD not yet done on chain %d\n", chain);
 -                      break;
 -              }
 -
 -              if (ar9003_paprd_create_curve(ah, caldata, chain)) {
 -                      ath_dbg(common, CALIBRATE,
 -                              "PAPRD create curve failed on chain %d\n",
 -                                                                 chain);
 -                      break;
 -              }
 -
 -              chain_ok = 1;
 -      }
 -      kfree_skb(skb);
 -
 -      if (chain_ok) {
 -              caldata->paprd_done = true;
 -              ath_paprd_activate(sc);
 -      }
 -
 -fail_paprd:
 -      ath9k_ps_restore(sc);
 -}
 -
 -/*
 - *  This routine performs the periodic noise floor calibration function
 - *  that is used to adjust and optimize the chip performance.  This
 - *  takes environmental changes (location, temperature) into account.
 - *  When the task is complete, it reschedules itself depending on the
 - *  appropriate interval that was calculated.
 - */
 -void ath_ani_calibrate(unsigned long data)
 -{
 -      struct ath_softc *sc = (struct ath_softc *)data;
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -      bool longcal = false;
 -      bool shortcal = false;
 -      bool aniflag = false;
 -      unsigned int timestamp = jiffies_to_msecs(jiffies);
 -      u32 cal_interval, short_cal_interval, long_cal_interval;
 -      unsigned long flags;
 -
 -      if (ah->caldata && ah->caldata->nfcal_interference)
 -              long_cal_interval = ATH_LONG_CALINTERVAL_INT;
 -      else
 -              long_cal_interval = ATH_LONG_CALINTERVAL;
 -
 -      short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
 -              ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
 -
 -      /* Only calibrate if awake */
 -      if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
 -              goto set_timer;
 -
 -      ath9k_ps_wakeup(sc);
 -
 -      /* Long calibration runs independently of short calibration. */
 -      if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
 -              longcal = true;
 -              common->ani.longcal_timer = timestamp;
 -      }
 -
 -      /* Short calibration applies only while caldone is false */
 -      if (!common->ani.caldone) {
 -              if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
 -                      shortcal = true;
 -                      common->ani.shortcal_timer = timestamp;
 -                      common->ani.resetcal_timer = timestamp;
 -              }
 -      } else {
 -              if ((timestamp - common->ani.resetcal_timer) >=
 -                  ATH_RESTART_CALINTERVAL) {
 -                      common->ani.caldone = ath9k_hw_reset_calvalid(ah);
 -                      if (common->ani.caldone)
 -                              common->ani.resetcal_timer = timestamp;
 -              }
 -      }
 -
 -      /* Verify whether we must check ANI */
 -      if (sc->sc_ah->config.enable_ani
 -          && (timestamp - common->ani.checkani_timer) >=
 -          ah->config.ani_poll_interval) {
 -              aniflag = true;
 -              common->ani.checkani_timer = timestamp;
 -      }
 -
 -      /* Call ANI routine if necessary */
 -      if (aniflag) {
 -              spin_lock_irqsave(&common->cc_lock, flags);
 -              ath9k_hw_ani_monitor(ah, ah->curchan);
 -              ath_update_survey_stats(sc);
 -              spin_unlock_irqrestore(&common->cc_lock, flags);
 -      }
 -
 -      /* Perform calibration if necessary */
 -      if (longcal || shortcal) {
 -              common->ani.caldone =
 -                      ath9k_hw_calibrate(ah, ah->curchan,
 -                                              ah->rxchainmask, longcal);
 -      }
 -
 -      ath_dbg(common, ANI,
 -              "Calibration @%lu finished: %s %s %s, caldone: %s\n",
 -              jiffies,
 -              longcal ? "long" : "", shortcal ? "short" : "",
 -              aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
 -
 -      ath9k_ps_restore(sc);
 -
 -set_timer:
 -      /*
 -      * Set timer interval based on previous results.
 -      * The interval must be the shortest necessary to satisfy ANI,
 -      * short calibration and long calibration.
 -      */
 -      ath9k_debug_samp_bb_mac(sc);
 -      cal_interval = ATH_LONG_CALINTERVAL;
 -      if (sc->sc_ah->config.enable_ani)
 -              cal_interval = min(cal_interval,
 -                                 (u32)ah->config.ani_poll_interval);
 -      if (!common->ani.caldone)
 -              cal_interval = min(cal_interval, (u32)short_cal_interval);
 -
 -      mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 -      if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
 -              if (!ah->caldata->paprd_done)
 -                      ieee80211_queue_work(sc->hw, &sc->paprd_work);
 -              else if (!ah->paprd_table_write_done)
 -                      ath_paprd_activate(sc);
 -      }
 -}
 -
  static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
                            struct ieee80211_vif *vif)
  {
@@@ -353,12 -668,13 +353,12 @@@ static void ath_node_detach(struct ath_
                ath_tx_node_cleanup(sc, an);
  }
  
 -
  void ath9k_tasklet(unsigned long data)
  {
        struct ath_softc *sc = (struct ath_softc *)data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 -
 +      unsigned long flags;
        u32 status = sc->intrstatus;
        u32 rxmask;
  
  
                RESET_STAT_INC(sc, type);
  #endif
 +              set_bit(SC_OP_HW_RESET, &sc->sc_flags);
                ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
                goto out;
        }
  
 +      spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
                 * TSF sync does not look correct; remain awake to sync with
                ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
                sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
 +      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
@@@ -453,17 -766,15 +453,17 @@@ irqreturn_t ath_isr(int irq, void *dev
         * touch anything. Note this can happen early
         * on if the IRQ is shared.
         */
 -      if (sc->sc_flags & SC_OP_INVALID)
 +      if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return IRQ_NONE;
  
 -
        /* shared irq, not for us */
  
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
  
 +      if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
 +              return IRQ_HANDLED;
 +
        /*
         * Figure out the reason(s) for the interrupt.  Note
         * that the hal returns a pseudo-ISR that may include
                        /* Clear RxAbort bit so that we can
                         * receive frames */
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
 +                      spin_lock(&sc->sc_pm_lock);
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                        sc->ps_flags |= PS_WAIT_FOR_BEACON;
 +                      spin_unlock(&sc->sc_pm_lock);
                }
  
  chip_reset:
@@@ -593,6 -902,96 +593,6 @@@ void ath_reset_work(struct work_struct 
        ath_reset(sc, true);
  }
  
 -void ath_hw_check(struct work_struct *work)
 -{
 -      struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
 -      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 -      unsigned long flags;
 -      int busy;
 -      u8 is_alive, nbeacon = 1;
 -
 -      ath9k_ps_wakeup(sc);
 -      is_alive = ath9k_hw_check_alive(sc->sc_ah);
 -
 -      if (is_alive && !AR_SREV_9300(sc->sc_ah))
 -              goto out;
 -      else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
 -              ath_dbg(common, RESET,
 -                      "DCU stuck is detected. Schedule chip reset\n");
 -              RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
 -              goto sched_reset;
 -      }
 -
 -      spin_lock_irqsave(&common->cc_lock, flags);
 -      busy = ath_update_survey_stats(sc);
 -      spin_unlock_irqrestore(&common->cc_lock, flags);
 -
 -      ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
 -              busy, sc->hw_busy_count + 1);
 -      if (busy >= 99) {
 -              if (++sc->hw_busy_count >= 3) {
 -                      RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
 -                      goto sched_reset;
 -              }
 -      } else if (busy >= 0) {
 -              sc->hw_busy_count = 0;
 -              nbeacon = 3;
 -      }
 -
 -      ath_start_rx_poll(sc, nbeacon);
 -      goto out;
 -
 -sched_reset:
 -      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
 -out:
 -      ath9k_ps_restore(sc);
 -}
 -
 -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
 -{
 -      static int count;
 -      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 -
 -      if (pll_sqsum >= 0x40000) {
 -              count++;
 -              if (count == 3) {
 -                      /* Rx is hung for more than 500ms. Reset it */
 -                      ath_dbg(common, RESET, "Possible RX hang, resetting\n");
 -                      RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
 -                      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
 -                      count = 0;
 -              }
 -      } else
 -              count = 0;
 -}
 -
 -void ath_hw_pll_work(struct work_struct *work)
 -{
 -      struct ath_softc *sc = container_of(work, struct ath_softc,
 -                                          hw_pll_work.work);
 -      u32 pll_sqsum;
 -
 -      /*
 -       * ensure that the PLL WAR is executed only
 -       * after the STA is associated (or) if the
 -       * beaconing had started in interfaces that
 -       * uses beacons.
 -       */
 -      if (!(sc->sc_flags & SC_OP_BEACONS))
 -              return;
 -
 -      if (AR_SREV_9485(sc->sc_ah)) {
 -
 -              ath9k_ps_wakeup(sc);
 -              pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
 -              ath9k_ps_restore(sc);
 -
 -              ath_hw_pll_rx_hang_check(sc, pll_sqsum);
 -
 -              ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
 -      }
 -}
 -
  /**********************/
  /* mac80211 callbacks */
  /**********************/
@@@ -655,9 -1054,10 +655,9 @@@ static int ath9k_start(struct ieee80211
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ah->imask |= ATH9K_INT_CST;
  
 -      if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
 -              ah->imask |= ATH9K_INT_MCI;
 +      ath_mci_enable(sc);
  
 -      sc->sc_flags &= ~SC_OP_INVALID;
 +      clear_bit(SC_OP_INVALID, &sc->sc_flags);
        sc->sc_ah->is_monitoring = false;
  
        if (!ath_complete_reset(sc, false)) {
@@@ -699,7 -1099,6 +699,7 @@@ static void ath9k_tx(struct ieee80211_h
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_tx_control txctl;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 +      unsigned long flags;
  
        if (sc->ps_enabled) {
                /*
                 * completed and if needed, also for RX of buffered frames.
                 */
                ath9k_ps_wakeup(sc);
 +              spin_lock_irqsave(&sc->sc_pm_lock, flags);
                if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                if (ieee80211_is_pspoll(hdr->frame_control)) {
                 * the ps_flags bit is cleared. We are just dropping
                 * the ps_usecount here.
                 */
 +              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
                ath9k_ps_restore(sc);
        }
  
@@@ -779,7 -1176,7 +779,7 @@@ static void ath9k_stop(struct ieee80211
        ath_cancel_work(sc);
        del_timer_sync(&sc->rx_poll_timer);
  
 -      if (sc->sc_flags & SC_OP_INVALID) {
 +      if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
  
        ath9k_ps_restore(sc);
  
 -      sc->sc_flags |= SC_OP_INVALID;
 +      set_bit(SC_OP_INVALID, &sc->sc_flags);
        sc->ps_idle = prev_idle;
  
        mutex_unlock(&sc->mutex);
@@@ -940,11 -1337,11 +940,11 @@@ static void ath9k_calculate_summary_sta
        /* Set op-mode & TSF */
        if (iter_data.naps > 0) {
                ath9k_hw_set_tsfadjust(ah, 1);
 -              sc->sc_flags |= SC_OP_TSF_RESET;
 +              set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
                ah->opmode = NL80211_IFTYPE_AP;
        } else {
                ath9k_hw_set_tsfadjust(ah, 0);
 -              sc->sc_flags &= ~SC_OP_TSF_RESET;
 +              clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
  
                if (iter_data.nmeshes)
                        ah->opmode = NL80211_IFTYPE_MESH_POINT;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
  
                if (!common->disable_ani) {
 -                      sc->sc_flags |= SC_OP_ANI_RUN;
 +                      set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        ath_start_ani(common);
                }
  
        } else {
 -              sc->sc_flags &= ~SC_OP_ANI_RUN;
 +              clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                del_timer_sync(&common->ani.timer);
        }
  }
@@@ -1001,6 -1398,25 +1001,6 @@@ static void ath9k_do_vif_add_setup(stru
        }
  }
  
 -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
 -{
 -      if (!AR_SREV_9300(sc->sc_ah))
 -              return;
 -
 -      if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
 -              return;
 -
 -      mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
 -                      (nbeacon * sc->cur_beacon_conf.beacon_interval));
 -}
 -
 -void ath_rx_poll(unsigned long data)
 -{
 -      struct ath_softc *sc = (struct ath_softc *)data;
 -
 -      ieee80211_queue_work(sc->hw, &sc->hw_check_work);
 -}
 -
  static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif)
  {
                }
        }
  
-       if ((ah->opmode == NL80211_IFTYPE_ADHOC) ||
-           ((vif->type == NL80211_IFTYPE_ADHOC) &&
-            sc->nvifs > 0)) {
-               ath_err(common, "Cannot create ADHOC interface when other"
-                       " interfaces already exist.\n");
-               ret = -EINVAL;
-               goto out;
-       }
        ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
  
        sc->nvifs++;
@@@ -1069,15 -1476,6 +1060,6 @@@ static int ath9k_change_interface(struc
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
  
-       /* See if new interface type is valid. */
-       if ((new_type == NL80211_IFTYPE_ADHOC) &&
-           (sc->nvifs > 1)) {
-               ath_err(common, "When using ADHOC, it must be the only"
-                       " interface.\n");
-               ret = -EINVAL;
-               goto out;
-       }
        if (ath9k_uses_beacons(new_type) &&
            !ath9k_uses_beacons(vif->type)) {
                if (sc->nbcnvifs >= ATH_BCBUF) {
@@@ -1220,6 -1618,11 +1202,6 @@@ static int ath9k_config(struct ieee8021
                if (ah->curchan)
                        old_pos = ah->curchan - &ah->channels[0];
  
 -              if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
 -                      sc->sc_flags |= SC_OP_OFFCHANNEL;
 -              else
 -                      sc->sc_flags &= ~SC_OP_OFFCHANNEL;
 -
                ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
                        curchan->center_freq, conf->channel_type);
  
                if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
                        ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
 +                      ath9k_ps_restore(sc);
                        return -EINVAL;
                }
  
@@@ -1500,16 -1902,16 +1482,16 @@@ static void ath9k_bss_iter(void *data, 
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
 -
 +      unsigned long flags;
        /*
         * Skip iteration if primary station vif's bss info
         * was not changed
         */
 -      if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
 +      if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
                return;
  
        if (bss_conf->assoc) {
 -              sc->sc_flags |= SC_OP_PRIM_STA_VIF;
 +              set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
                avp->primary_sta_vif = true;
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = bss_conf->aid;
                 * on the receipt of the first Beacon frame (i.e.,
                 * after time sync with the AP).
                 */
 +              spin_lock_irqsave(&sc->sc_pm_lock, flags);
                sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
 +              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 +
                /* Reset rssi stats */
                sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
                ath_start_rx_poll(sc, 3);
  
                if (!common->disable_ani) {
 -                      sc->sc_flags |= SC_OP_ANI_RUN;
 +                      set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        ath_start_ani(common);
                }
  
@@@ -1553,8 -1952,7 +1535,8 @@@ static void ath9k_config_bss(struct ath
        if (avp->primary_sta_vif && !bss_conf->assoc) {
                ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
                        common->curaid, common->curbssid);
 -              sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
 +              clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
 +              clear_bit(SC_OP_BEACONS, &sc->sc_flags);
                avp->primary_sta_vif = false;
                memset(common->curbssid, 0, ETH_ALEN);
                common->curaid = 0;
         * None of station vifs are associated.
         * Clear bssid & aid
         */
 -      if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
 +      if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
                ath9k_hw_write_associd(sc->sc_ah);
 -              /* Stop ANI */
 -              sc->sc_flags &= ~SC_OP_ANI_RUN;
 +              clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                del_timer_sync(&common->ani.timer);
                del_timer_sync(&sc->rx_poll_timer);
                memset(&sc->caldata, 0, sizeof(sc->caldata));
@@@ -1607,12 -2006,12 +1589,12 @@@ static void ath9k_bss_info_changed(stru
                        sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
  
                        if (!common->disable_ani) {
 -                              sc->sc_flags |= SC_OP_ANI_RUN;
 +                              set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                                ath_start_ani(common);
                        }
  
                } else {
 -                      sc->sc_flags &= ~SC_OP_ANI_RUN;
 +                      clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        del_timer_sync(&common->ani.timer);
                        del_timer_sync(&sc->rx_poll_timer);
                }
         */
        if ((changed & BSS_CHANGED_BEACON_INT) &&
            (vif->type == NL80211_IFTYPE_AP))
 -              sc->sc_flags |= SC_OP_TSF_RESET;
 +              set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
  
        /* Configure beaconing (AP, IBSS, MESH) */
        if (ath9k_uses_beacons(vif->type) &&
@@@ -1816,7 -2215,7 +1798,7 @@@ static void ath9k_flush(struct ieee8021
                return;
        }
  
 -      if (sc->sc_flags & SC_OP_INVALID) {
 +      if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
@@@ -1981,134 -2380,6 +1963,134 @@@ static int ath9k_get_antenna(struct iee
        return 0;
  }
  
 +#ifdef CONFIG_ATH9K_DEBUGFS
 +
 +/* Ethtool support for get-stats */
 +
 +#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
 +static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
 +      "tx_pkts_nic",
 +      "tx_bytes_nic",
 +      "rx_pkts_nic",
 +      "rx_bytes_nic",
 +      AMKSTR(d_tx_pkts),
 +      AMKSTR(d_tx_bytes),
 +      AMKSTR(d_tx_mpdus_queued),
 +      AMKSTR(d_tx_mpdus_completed),
 +      AMKSTR(d_tx_mpdu_xretries),
 +      AMKSTR(d_tx_aggregates),
 +      AMKSTR(d_tx_ampdus_queued_hw),
 +      AMKSTR(d_tx_ampdus_queued_sw),
 +      AMKSTR(d_tx_ampdus_completed),
 +      AMKSTR(d_tx_ampdu_retries),
 +      AMKSTR(d_tx_ampdu_xretries),
 +      AMKSTR(d_tx_fifo_underrun),
 +      AMKSTR(d_tx_op_exceeded),
 +      AMKSTR(d_tx_timer_expiry),
 +      AMKSTR(d_tx_desc_cfg_err),
 +      AMKSTR(d_tx_data_underrun),
 +      AMKSTR(d_tx_delim_underrun),
 +
 +      "d_rx_decrypt_crc_err",
 +      "d_rx_phy_err",
 +      "d_rx_mic_err",
 +      "d_rx_pre_delim_crc_err",
 +      "d_rx_post_delim_crc_err",
 +      "d_rx_decrypt_busy_err",
 +
 +      "d_rx_phyerr_radar",
 +      "d_rx_phyerr_ofdm_timing",
 +      "d_rx_phyerr_cck_timing",
 +
 +};
 +#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats)
 +
 +static void ath9k_get_et_strings(struct ieee80211_hw *hw,
 +                               struct ieee80211_vif *vif,
 +                               u32 sset, u8 *data)
 +{
 +      if (sset == ETH_SS_STATS)
 +              memcpy(data, *ath9k_gstrings_stats,
 +                     sizeof(ath9k_gstrings_stats));
 +}
 +
 +static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
 +                                 struct ieee80211_vif *vif, int sset)
 +{
 +      if (sset == ETH_SS_STATS)
 +              return ATH9K_SSTATS_LEN;
 +      return 0;
 +}
 +
 +#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
 +#define AWDATA(elem)                                                  \
 +      do {                                                            \
 +              data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
 +              data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
 +              data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
 +              data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
 +      } while (0)
 +
 +#define AWDATA_RX(elem)                                               \
 +      do {                                                    \
 +              data[i++] = sc->debug.stats.rxstats.elem;       \
 +      } while (0)
 +
 +static void ath9k_get_et_stats(struct ieee80211_hw *hw,
 +                             struct ieee80211_vif *vif,
 +                             struct ethtool_stats *stats, u64 *data)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      int i = 0;
 +
 +      data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
 +      data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
 +                   sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
 +      AWDATA_RX(rx_pkts_all);
 +      AWDATA_RX(rx_bytes_all);
 +
 +      AWDATA(tx_pkts_all);
 +      AWDATA(tx_bytes_all);
 +      AWDATA(queued);
 +      AWDATA(completed);
 +      AWDATA(xretries);
 +      AWDATA(a_aggr);
 +      AWDATA(a_queued_hw);
 +      AWDATA(a_queued_sw);
 +      AWDATA(a_completed);
 +      AWDATA(a_retries);
 +      AWDATA(a_xretries);
 +      AWDATA(fifo_underrun);
 +      AWDATA(xtxop);
 +      AWDATA(timer_exp);
 +      AWDATA(desc_cfg_err);
 +      AWDATA(data_underrun);
 +      AWDATA(delim_underrun);
 +
 +      AWDATA_RX(decrypt_crc_err);
 +      AWDATA_RX(phy_err);
 +      AWDATA_RX(mic_err);
 +      AWDATA_RX(pre_delim_crc_err);
 +      AWDATA_RX(post_delim_crc_err);
 +      AWDATA_RX(decrypt_busy_err);
 +
 +      AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]);
 +      AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]);
 +      AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]);
 +
 +      WARN_ON(i != ATH9K_SSTATS_LEN);
 +}
 +
 +/* End of ethtool get-stats functions */
 +
 +#endif
 +
 +
  struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
        .get_stats          = ath9k_get_stats,
        .set_antenna        = ath9k_set_antenna,
        .get_antenna        = ath9k_get_antenna,
 +
 +#ifdef CONFIG_ATH9K_DEBUGFS
 +      .get_et_sset_count  = ath9k_get_et_sset_count,
 +      .get_et_stats  = ath9k_get_et_stats,
 +      .get_et_strings  = ath9k_get_et_strings,
 +#endif
  };
index 3f5d682e866fb17774cdc7b9f2e8959f0eb80563,3def64ba77fa0100bd62f0072cc6989e0f403f3f..2a6b0b8b71201dac383ee058a9df6f7f595a150e
@@@ -30,9 -30,6 +30,9 @@@
  #define HCI_MAX_EVENT_SIZE    260
  #define HCI_MAX_FRAME_SIZE    (HCI_MAX_ACL_SIZE + 4)
  
 +#define HCI_LINK_KEY_SIZE     16
 +#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
 +
  /* HCI dev events */
  #define HCI_DEV_REG                   1
  #define HCI_DEV_UNREG                 2
  #define HCI_BREDR     0x00
  #define HCI_AMP               0x01
  
 +/* First BR/EDR Controller shall have ID = 0 */
 +#define HCI_BREDR_ID  0
 +
  /* HCI device quirks */
  enum {
 -      HCI_QUIRK_NO_RESET,
 +      HCI_QUIRK_RESET_ON_CLOSE,
        HCI_QUIRK_RAW_DEVICE,
        HCI_QUIRK_FIXUP_BUFFER_SIZE
  };
@@@ -139,8 -133,10 +139,8 @@@ enum 
  #define HCIINQUIRY    _IOR('H', 240, int)
  
  /* HCI timeouts */
 -#define HCI_CONNECT_TIMEOUT   (40000) /* 40 seconds */
  #define HCI_DISCONN_TIMEOUT   (2000)  /* 2 seconds */
  #define HCI_PAIRING_TIMEOUT   (60000) /* 60 seconds */
 -#define HCI_IDLE_TIMEOUT      (6000)  /* 6 seconds */
  #define HCI_INIT_TIMEOUT      (10000) /* 10 seconds */
  #define HCI_CMD_TIMEOUT               (1000)  /* 1 seconds */
  #define HCI_ACL_TX_TIMEOUT    (45000) /* 45 seconds */
@@@ -375,7 -371,7 +375,7 @@@ struct hci_cp_reject_conn_req 
  #define HCI_OP_LINK_KEY_REPLY         0x040b
  struct hci_cp_link_key_reply {
        bdaddr_t bdaddr;
 -      __u8     link_key[16];
 +      __u8     link_key[HCI_LINK_KEY_SIZE];
  } __packed;
  
  #define HCI_OP_LINK_KEY_NEG_REPLY     0x040c
@@@ -527,28 -523,6 +527,28 @@@ struct hci_cp_io_capability_neg_reply 
        __u8     reason;
  } __packed;
  
 +#define HCI_OP_CREATE_PHY_LINK                0x0435
 +struct hci_cp_create_phy_link {
 +      __u8     phy_handle;
 +      __u8     key_len;
 +      __u8     key_type;
 +      __u8     key[HCI_AMP_LINK_KEY_SIZE];
 +} __packed;
 +
 +#define HCI_OP_ACCEPT_PHY_LINK                0x0436
 +struct hci_cp_accept_phy_link {
 +      __u8     phy_handle;
 +      __u8     key_len;
 +      __u8     key_type;
 +      __u8     key[HCI_AMP_LINK_KEY_SIZE];
 +} __packed;
 +
 +#define HCI_OP_DISCONN_PHY_LINK       0x0437
 +struct hci_cp_disconn_phy_link {
 +      __u8     phy_handle;
 +      __u8     reason;
 +} __packed;
 +
  #define HCI_OP_SNIFF_MODE             0x0803
  struct hci_cp_sniff_mode {
        __le16   handle;
@@@ -844,31 -818,6 +844,31 @@@ struct hci_rp_read_local_amp_info 
        __le32   be_flush_to;
  } __packed;
  
 +#define HCI_OP_READ_LOCAL_AMP_ASSOC   0x140a
 +struct hci_cp_read_local_amp_assoc {
 +      __u8     phy_handle;
 +      __le16   len_so_far;
 +      __le16   max_len;
 +} __packed;
 +struct hci_rp_read_local_amp_assoc {
 +      __u8     status;
 +      __u8     phy_handle;
 +      __le16   rem_len;
 +      __u8     frag[0];
 +} __packed;
 +
 +#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b
 +struct hci_cp_write_remote_amp_assoc {
 +      __u8     phy_handle;
 +      __le16   len_so_far;
 +      __le16   rem_len;
 +      __u8     frag[0];
 +} __packed;
 +struct hci_rp_write_remote_amp_assoc {
 +      __u8     status;
 +      __u8     phy_handle;
 +} __packed;
 +
  #define HCI_OP_LE_SET_EVENT_MASK      0x2001
  struct hci_cp_le_set_event_mask {
        __u8     mask[8];
@@@ -1099,7 -1048,7 +1099,7 @@@ struct hci_ev_link_key_req 
  #define HCI_EV_LINK_KEY_NOTIFY                0x18
  struct hci_ev_link_key_notify {
        bdaddr_t bdaddr;
 -      __u8     link_key[16];
 +      __u8     link_key[HCI_LINK_KEY_SIZE];
        __u8     key_type;
  } __packed;
  
@@@ -1195,6 -1144,12 +1195,12 @@@ struct extended_inquiry_info 
        __u8     data[240];
  } __packed;
  
+ #define HCI_EV_KEY_REFRESH_COMPLETE   0x30
+ struct hci_ev_key_refresh_complete {
+       __u8    status;
+       __le16  handle;
+ } __packed;
  #define HCI_EV_IO_CAPA_REQUEST                0x31
  struct hci_ev_io_capa_request {
        bdaddr_t bdaddr;
@@@ -1241,39 -1196,6 +1247,39 @@@ struct hci_ev_le_meta 
        __u8     subevent;
  } __packed;
  
 +#define HCI_EV_PHY_LINK_COMPLETE      0x40
 +struct hci_ev_phy_link_complete {
 +      __u8     status;
 +      __u8     phy_handle;
 +} __packed;
 +
 +#define HCI_EV_CHANNEL_SELECTED               0x41
 +struct hci_ev_channel_selected {
 +      __u8     phy_handle;
 +} __packed;
 +
 +#define HCI_EV_DISCONN_PHY_LINK_COMPLETE      0x42
 +struct hci_ev_disconn_phy_link_complete {
 +      __u8     status;
 +      __u8     phy_handle;
 +      __u8     reason;
 +} __packed;
 +
 +#define HCI_EV_LOGICAL_LINK_COMPLETE          0x45
 +struct hci_ev_logical_link_complete {
 +      __u8     status;
 +      __le16   handle;
 +      __u8     phy_handle;
 +      __u8     flow_spec_id;
 +} __packed;
 +
 +#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE  0x46
 +struct hci_ev_disconn_logical_link_complete {
 +      __u8     status;
 +      __le16   handle;
 +      __u8     reason;
 +} __packed;
 +
  #define HCI_EV_NUM_COMP_BLOCKS                0x48
  struct hci_comp_blocks_info {
        __le16   handle;
@@@ -1374,6 -1296,7 +1380,6 @@@ struct hci_sco_hdr 
        __u8    dlen;
  } __packed;
  
 -#include <linux/skbuff.h>
  static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
  {
        return (struct hci_event_hdr *) skb->data;
@@@ -1390,12 -1313,12 +1396,12 @@@ static inline struct hci_sco_hdr *hci_s
  }
  
  /* Command opcode pack/unpack */
 -#define hci_opcode_pack(ogf, ocf)     (__u16) ((ocf & 0x03ff)|(ogf << 10))
 +#define hci_opcode_pack(ogf, ocf)     ((__u16) ((ocf & 0x03ff)|(ogf << 10)))
  #define hci_opcode_ogf(op)            (op >> 10)
  #define hci_opcode_ocf(op)            (op & 0x03ff)
  
  /* ACL handle and flags pack/unpack */
 -#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12))
 +#define hci_handle_pack(h, f) ((__u16) ((h & 0x0fff)|(f << 12)))
  #define hci_handle(h)         (h & 0x0fff)
  #define hci_flags(h)          (h >> 12)
  
diff --combined include/net/mac80211.h
index d152f54064fd612bc6c95c2de3bf9a30c1a92919,95e39b6a02ec924ab1229e728ddb4bd45ff3d682..6914f9978aea0347da19c485d296492624dc9a8b
@@@ -1297,10 -1297,6 +1297,10 @@@ enum ieee80211_hw_flags 
   *    reports, by default it is set to _MCS, _GI and _BW but doesn't
   *    include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
   *    adding _BW is supported today.
 + *
 + * @netdev_features: netdev features to be set in each netdev created
 + *    from this HW. Note only HW checksum features are currently
 + *    compatible with mac80211. Other feature bits will be rejected.
   */
  struct ieee80211_hw {
        struct ieee80211_conf conf;
        u8 max_tx_aggregation_subframes;
        u8 offchannel_tx_hw_queue;
        u8 radiotap_mcs_details;
 +      netdev_features_t netdev_features;
  };
  
  /**
@@@ -1945,6 -1940,11 +1945,11 @@@ enum ieee80211_rate_control_changed 
   *    to also unregister the device. If it returns 1, then mac80211
   *    will also go through the regular complete restart on resume.
   *
+  * @set_wakeup: Enable or disable wakeup when WoWLAN configuration is
+  *    modified. The reason is that device_set_wakeup_enable() is
+  *    supposed to be called when the configuration changes, not only
+  *    in suspend().
+  *
   * @add_interface: Called when a netdevice attached to the hardware is
   *    enabled. Because it is not called for monitor mode devices, @start
   *    and @stop must be implemented.
   *    offload. Frames to transmit on the off-channel channel are transmitted
   *    normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
   *    duration (which will always be non-zero) expires, the driver must call
 - *    ieee80211_remain_on_channel_expired(). This callback may sleep.
 + *    ieee80211_remain_on_channel_expired().
 + *    Note that this callback may be called while the device is in IDLE and
 + *    must be accepted in this case.
 + *    This callback may sleep.
   * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
   *    aborted before it expires. This callback may sleep.
   *
@@@ -2974,6 -2971,7 +2979,7 @@@ __le16 ieee80211_ctstoself_duration(str
   * ieee80211_generic_frame_duration - Calculate the duration field for a frame
   * @hw: pointer obtained from ieee80211_alloc_hw().
   * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+  * @band: the band to calculate the frame duration on
   * @frame_len: the length of the frame.
   * @rate: the rate at which the frame is going to be transmitted.
   *
@@@ -3558,6 -3556,16 +3564,6 @@@ void ieee80211_cqm_rssi_notify(struct i
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp);
  
 -/**
 - * ieee80211_get_operstate - get the operstate of the vif
 - *
 - * @vif: &struct ieee80211_vif pointer from the add_interface callback.
 - *
 - * The driver might need to know the operstate of the net_device
 - * (specifically, whether the link is IF_OPER_UP after resume)
 - */
 -unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif);
 -
  /**
   * ieee80211_chswitch_done - Complete channel switch process
   * @vif: &struct ieee80211_vif pointer from the add_interface callback.
@@@ -3837,28 -3845,4 +3843,28 @@@ int ieee80211_add_ext_srates_ie(struct 
   */
  int ieee80211_ave_rssi(struct ieee80211_vif *vif);
  
 +/* Extra debugging macros */
 +
 +#ifdef CONFIG_MAC80211_HT_DEBUG
 +#define ht_vdbg(fmt, ...)                     \
 +      pr_debug(fmt, ##__VA_ARGS__)
 +#else
 +#define ht_vdbg(fmt, ...)                     \
 +do {                                          \
 +      if (0)                                  \
 +              pr_debug(fmt, ##__VA_ARGS__);   \
 +} while (0)
 +#endif
 +
 +#ifdef CONFIG_MAC80211_IBSS_DEBUG
 +#define ibss_vdbg(fmt, ...)                   \
 +      pr_debug(fmt, ##__VA_ARGS__)
 +#else
 +#define ibss_vdbg(fmt, ...)                   \
 +do {                                          \
 +      if (0)                                  \
 +              pr_debug(fmt, ##__VA_ARGS__);   \
 +} while (0)
 +#endif
 +
  #endif /* MAC80211_H */
index 47656beee14cd6b5685d868fc03c69caeeecc7f7,94ad124a4ea3496c4bd971b3bc4ac9d4dda8860f..1ba929c05d0da41c7c584a9166383a4f29f169da
  
  /* Bluetooth HCI event handling. */
  
 -#include <linux/module.h>
 -
 -#include <linux/types.h>
 -#include <linux/errno.h>
 -#include <linux/kernel.h>
 -#include <linux/slab.h>
 -#include <linux/poll.h>
 -#include <linux/fcntl.h>
 -#include <linux/init.h>
 -#include <linux/skbuff.h>
 -#include <linux/interrupt.h>
 -#include <net/sock.h>
 -
 -#include <linux/uaccess.h>
 +#include <linux/export.h>
  #include <asm/unaligned.h>
  
  #include <net/bluetooth/bluetooth.h>
@@@ -82,8 -95,7 +82,8 @@@ static void hci_cc_exit_periodic_inq(st
        hci_conn_check_pending(hdev);
  }
  
 -static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
 +                                        struct sk_buff *skb)
  {
        BT_DBG("%s", hdev->name);
  }
@@@ -154,8 -166,7 +154,8 @@@ static void hci_cc_write_link_policy(st
        hci_dev_unlock(hdev);
  }
  
 -static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
 +                                      struct sk_buff *skb)
  {
        struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
  
        hdev->link_policy = __le16_to_cpu(rp->policy);
  }
  
 -static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
 +                                       struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
        void *sent;
@@@ -319,7 -329,7 +319,7 @@@ static void hci_cc_write_scan_enable(st
                if (hdev->discov_timeout > 0) {
                        int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
                        queue_delayed_work(hdev->workqueue, &hdev->discov_off,
 -                                                                      to);
 +                                         to);
                }
        } else if (old_iscan)
                mgmt_discoverable(hdev, 0);
@@@ -348,7 -358,7 +348,7 @@@ static void hci_cc_read_class_of_dev(st
        memcpy(hdev->dev_class, rp->dev_class, 3);
  
        BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
 -              hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 +             hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
  }
  
  static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@@ -396,8 -406,7 +396,8 @@@ static void hci_cc_read_voice_setting(s
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
  }
  
 -static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_write_voice_setting(struct hci_dev *hdev,
 +                                     struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
        __u16 setting;
@@@ -464,7 -473,7 +464,7 @@@ static u8 hci_get_inquiry_mode(struct h
                return 1;
  
        if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
 -                                              hdev->lmp_subver == 0x0757)
 +          hdev->lmp_subver == 0x0757)
                return 1;
  
        if (hdev->manufacturer == 15) {
        }
  
        if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
 -                                              hdev->lmp_subver == 0x1805)
 +          hdev->lmp_subver == 0x1805)
                return 1;
  
        return 0;
@@@ -557,7 -566,7 +557,7 @@@ static void hci_setup(struct hci_dev *h
        if (hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
  
 -      if (hdev->features[6] & LMP_SIMPLE_PAIR) {
 +      if (lmp_ssp_capable(hdev)) {
                if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
                        u8 mode = 0x01;
                        hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
@@@ -609,7 -618,8 +609,7 @@@ static void hci_cc_read_local_version(s
        hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
  
        BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
 -                                      hdev->manufacturer,
 -                                      hdev->hci_ver, hdev->hci_rev);
 +             hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
  
        if (test_bit(HCI_INIT, &hdev->flags))
                hci_setup(hdev);
@@@ -636,8 -646,7 +636,8 @@@ static void hci_setup_link_policy(struc
        hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
  }
  
 -static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_read_local_commands(struct hci_dev *hdev,
 +                                     struct sk_buff *skb)
  {
        struct hci_rp_read_local_commands *rp = (void *) skb->data;
  
@@@ -655,8 -664,7 +655,8 @@@ done
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
  }
  
 -static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cc_read_local_features(struct hci_dev *hdev,
 +                                     struct sk_buff *skb)
  {
        struct hci_rp_read_local_features *rp = (void *) skb->data;
  
                hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
  
        BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
 -                                      hdev->features[0], hdev->features[1],
 -                                      hdev->features[2], hdev->features[3],
 -                                      hdev->features[4], hdev->features[5],
 -                                      hdev->features[6], hdev->features[7]);
 +             hdev->features[0], hdev->features[1],
 +             hdev->features[2], hdev->features[3],
 +             hdev->features[4], hdev->features[5],
 +             hdev->features[6], hdev->features[7]);
  }
  
  static void hci_set_le_support(struct hci_dev *hdev)
  }
  
  static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                         struct sk_buff *skb)
  {
        struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
  
@@@ -754,7 -762,7 +754,7 @@@ done
  }
  
  static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
 -                                              struct sk_buff *skb)
 +                                        struct sk_buff *skb)
  {
        struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
  
@@@ -790,8 -798,9 +790,8 @@@ static void hci_cc_read_buffer_size(str
        hdev->acl_cnt = hdev->acl_pkts;
        hdev->sco_cnt = hdev->sco_pkts;
  
 -      BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
 -                                      hdev->acl_mtu, hdev->acl_pkts,
 -                                      hdev->sco_mtu, hdev->sco_pkts);
 +      BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
 +             hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
  }
  
  static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
  }
  
  static void hci_cc_read_data_block_size(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                      struct sk_buff *skb)
  {
        struct hci_rp_read_data_block_size *rp = (void *) skb->data;
  
        hdev->block_cnt = hdev->num_blocks;
  
        BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
 -                                      hdev->block_cnt, hdev->block_len);
 +             hdev->block_cnt, hdev->block_len);
  
        hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
  }
@@@ -838,7 -847,7 +838,7 @@@ static void hci_cc_write_ca_timeout(str
  }
  
  static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 -              struct sk_buff *skb)
 +                                     struct sk_buff *skb)
  {
        struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
  
  }
  
  static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                        struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
  
@@@ -881,7 -890,7 +881,7 @@@ static void hci_cc_set_event_mask(struc
  }
  
  static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                    struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
  
  }
  
  static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                       struct sk_buff *skb)
  {
        struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
  
@@@ -950,7 -959,7 +950,7 @@@ static void hci_cc_pin_code_neg_reply(s
  
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
 -                                                              rp->status);
 +                                               rp->status);
  
        hci_dev_unlock(hdev);
  }
@@@ -991,7 -1000,7 +991,7 @@@ static void hci_cc_user_confirm_reply(s
  }
  
  static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                        struct sk_buff *skb)
  {
        struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
  
@@@ -1022,7 -1031,7 +1022,7 @@@ static void hci_cc_user_passkey_reply(s
  }
  
  static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                        struct sk_buff *skb)
  {
        struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
  
  }
  
  static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +                                           struct sk_buff *skb)
  {
        struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
  
@@@ -1067,7 -1076,7 +1067,7 @@@ static void hci_cc_le_set_scan_param(st
  }
  
  static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 -                                      struct sk_buff *skb)
 +                                    struct sk_buff *skb)
  {
        struct hci_cp_le_set_scan_enable *cp;
        __u8 status = *((__u8 *) skb->data);
@@@ -1147,8 -1156,8 +1147,8 @@@ static void hci_cc_le_ltk_neg_reply(str
        hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
  }
  
 -static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 +                                         struct sk_buff *skb)
  {
        struct hci_cp_write_le_host_supported *sent;
        __u8 status = *((__u8 *) skb->data);
        }
  
        if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
 -                                      !test_bit(HCI_INIT, &hdev->flags))
 +          !test_bit(HCI_INIT, &hdev->flags))
                mgmt_le_enable_complete(hdev, sent->le, status);
  
        hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
  }
  
 -static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 +static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
  {
        BT_DBG("%s status 0x%x", hdev->name, status);
  
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 +static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
  {
        struct hci_cp_create_conn *cp;
        struct hci_conn *conn;
@@@ -1324,7 -1333,7 +1324,7 @@@ static void hci_cs_set_conn_encrypt(str
  }
  
  static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 -                                                      struct hci_conn *conn)
 +                                  struct hci_conn *conn)
  {
        if (conn->state != BT_CONFIG || !conn->out)
                return 0;
  
        /* Only request authentication for SSP connections or non-SSP
         * devices with sec_level HIGH or if MITM protection is requested */
 -      if (!hci_conn_ssp_enabled(conn) &&
 -                              conn->pending_sec_level != BT_SECURITY_HIGH &&
 -                              !(conn->auth_type & 0x01))
 +      if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
 +          conn->pending_sec_level != BT_SECURITY_HIGH)
                return 0;
  
        return 1;
  }
  
 -static inline int hci_resolve_name(struct hci_dev *hdev,
 +static int hci_resolve_name(struct hci_dev *hdev,
                                   struct inquiry_entry *e)
  {
        struct hci_cp_remote_name_req cp;
@@@ -1628,7 -1638,7 +1628,7 @@@ static void hci_cs_le_create_conn(struc
        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
  
        BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
 -              conn);
 +             conn);
  
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@@ -1658,7 -1668,7 +1658,7 @@@ static void hci_cs_le_start_enc(struct 
        BT_DBG("%s status 0x%x", hdev->name, status);
  }
  
 -static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
        struct discovery_state *discov = &hdev->discovery;
@@@ -1698,7 -1708,7 +1698,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct inquiry_data data;
        struct inquiry_info *info = (void *) (skb->data + 1);
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -1813,18 -1823,18 +1813,18 @@@ unlock
        hci_conn_check_pending(hdev);
  }
  
 -static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_conn_request *ev = (void *) skb->data;
        int mask = hdev->link_mode;
  
 -      BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
 -                                      batostr(&ev->bdaddr), ev->link_type);
 +      BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
 +             ev->link_type);
  
        mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
  
        if ((mask & HCI_LM_ACCEPT) &&
 -                      !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
 +          !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
                /* Connection accepted */
                struct inquiry_entry *ie;
                struct hci_conn *conn;
                if (ie)
                        memcpy(ie->data.dev_class, ev->dev_class, 3);
  
 -              conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
 +              conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
 +                                             &ev->bdaddr);
                if (!conn) {
                        conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
                        if (!conn) {
                        bacpy(&cp.bdaddr, &ev->bdaddr);
                        cp.pkt_type = cpu_to_le16(conn->pkt_type);
  
 -                      cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
 -                      cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
 -                      cp.max_latency    = cpu_to_le16(0xffff);
 +                      cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
 +                      cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
 +                      cp.max_latency    = __constant_cpu_to_le16(0xffff);
                        cp.content_format = cpu_to_le16(hdev->voice_setting);
                        cp.retrans_effort = 0xff;
  
        }
  }
  
 -static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
                conn->state = BT_CLOSED;
  
        if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
 -                      (conn->type == ACL_LINK || conn->type == LE_LINK)) {
 +          (conn->type == ACL_LINK || conn->type == LE_LINK)) {
                if (ev->status != 0)
                        mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
 -                                              conn->dst_type, ev->status);
 +                                             conn->dst_type, ev->status);
                else
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
                                                 conn->dst_type);
@@@ -1925,7 -1934,7 +1925,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_auth_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
  
        if (!ev->status) {
                if (!hci_conn_ssp_enabled(conn) &&
 -                              test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
 +                  test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
                        BT_INFO("re-auth of legacy device is not possible.");
                } else {
                        conn->link_mode |= HCI_LM_AUTH;
                        cp.handle  = ev->handle;
                        cp.encrypt = 0x01;
                        hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
 -                                                                      &cp);
 +                                   &cp);
                } else {
                        conn->state = BT_CONNECTED;
                        hci_proto_connect_cfm(conn, ev->status);
                        cp.handle  = ev->handle;
                        cp.encrypt = 0x01;
                        hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
 -                                                                      &cp);
 +                                   &cp);
                } else {
                        clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
                        hci_encrypt_cfm(conn, ev->status, 0x00);
@@@ -1991,7 -2000,7 +1991,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_remote_name *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -2030,7 -2039,7 +2030,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_encrypt_change *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -2073,8 -2082,7 +2073,8 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
 +                                           struct sk_buff *skb)
  {
        struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_remote_features_evt(struct hci_dev *hdev,
 +                                  struct sk_buff *skb)
  {
        struct hci_ev_remote_features *ev = (void *) skb->data;
        struct hci_conn *conn;
                cp.handle = ev->handle;
                cp.page = 0x01;
                hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
 -                                                      sizeof(cp), &cp);
 +                           sizeof(cp), &cp);
                goto unlock;
        }
  
@@@ -2146,18 -2153,17 +2146,18 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        BT_DBG("%s", hdev->name);
  }
  
 -static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
 +                                     struct sk_buff *skb)
  {
        BT_DBG("%s", hdev->name);
  }
  
 -static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_cmd_complete *ev = (void *) skb->data;
        __u16 opcode;
        }
  }
  
 -static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_cmd_status *ev = (void *) skb->data;
        __u16 opcode;
        }
  }
  
 -static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_role_change *ev = (void *) skb->data;
        struct hci_conn *conn;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
        int i;
        }
  
        if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
 -                      ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
 +          ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
        queue_work(hdev->workqueue, &hdev->tx_work);
  }
  
 -static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
 -                                         struct sk_buff *skb)
 +static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
        int i;
        }
  
        if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
 -                      ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
 +          ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
  
        BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
 -                                                              ev->num_hndl);
 +             ev->num_hndl);
  
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_blocks_info *info = &ev->handles[i];
        queue_work(hdev->workqueue, &hdev->tx_work);
  }
  
 -static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_mode_change *ev = (void *) skb->data;
        struct hci_conn *conn;
                conn->mode = ev->mode;
                conn->interval = __le16_to_cpu(ev->interval);
  
 -              if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
 +              if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
 +                                      &conn->flags)) {
                        if (conn->mode == HCI_CM_ACTIVE)
                                set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
                        else
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_pin_code_req *ev = (void *) skb->data;
        struct hci_conn *conn;
  
        if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
                hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 -                                      sizeof(ev->bdaddr), &ev->bdaddr);
 +                           sizeof(ev->bdaddr), &ev->bdaddr);
        else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
                u8 secure;
  
@@@ -2666,7 -2672,7 +2666,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_link_key_req *ev = (void *) skb->data;
        struct hci_cp_link_key_reply cp;
        key = hci_find_link_key(hdev, &ev->bdaddr);
        if (!key) {
                BT_DBG("%s link key not found for %s", hdev->name,
 -                                                      batostr(&ev->bdaddr));
 +                     batostr(&ev->bdaddr));
                goto not_found;
        }
  
        BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 -                                                      batostr(&ev->bdaddr));
 +             batostr(&ev->bdaddr));
  
        if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
 -                              key->type == HCI_LK_DEBUG_COMBINATION) {
 +          key->type == HCI_LK_DEBUG_COMBINATION) {
                BT_DBG("%s ignoring debug key", hdev->name);
                goto not_found;
        }
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn) {
                if (key->type == HCI_LK_UNAUTH_COMBINATION &&
 -                              conn->auth_type != 0xff &&
 -                              (conn->auth_type & 0x01)) {
 +                  conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
                        BT_DBG("%s ignoring unauthenticated key", hdev->name);
                        goto not_found;
                }
  
                if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
 -                              conn->pending_sec_level == BT_SECURITY_HIGH) {
 -                      BT_DBG("%s ignoring key unauthenticated for high \
 -                                                      security", hdev->name);
 +                  conn->pending_sec_level == BT_SECURITY_HIGH) {
 +                      BT_DBG("%s ignoring key unauthenticated for high security",
 +                             hdev->name);
                        goto not_found;
                }
  
        }
  
        bacpy(&cp.bdaddr, &ev->bdaddr);
 -      memcpy(cp.link_key, key->val, 16);
 +      memcpy(cp.link_key, key->val, HCI_LINK_KEY_SIZE);
  
        hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
  
@@@ -2729,7 -2736,7 +2729,7 @@@ not_found
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_link_key_notify *ev = (void *) skb->data;
        struct hci_conn *conn;
  
        if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
                hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
 -                                                      ev->key_type, pin_len);
 +                               ev->key_type, pin_len);
  
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_clock_offset *ev = (void *) skb->data;
        struct hci_conn *conn;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_pkt_type_change *ev = (void *) skb->data;
        struct hci_conn *conn;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
        struct inquiry_entry *ie;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 +                                           struct sk_buff *skb)
  {
        struct inquiry_data data;
        int num_rsp = *((__u8 *) skb->data);
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_remote_ext_features_evt(struct hci_dev *hdev,
 +                                      struct sk_buff *skb)
  {
        struct hci_ev_remote_ext_features *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -2924,8 -2929,7 +2924,8 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
 +                                     struct sk_buff *skb)
  {
        struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -2980,20 -2984,19 +2980,20 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        BT_DBG("%s", hdev->name);
  }
  
 -static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_sniff_subrate *ev = (void *) skb->data;
  
        BT_DBG("%s status %d", hdev->name, ev->status);
  }
  
 -static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
 +                                          struct sk_buff *skb)
  {
        struct inquiry_data data;
        struct extended_inquiry_info *info = (void *) (skb->data + 1);
        hci_dev_unlock(hdev);
  }
  
 -static inline u8 hci_get_auth_req(struct hci_conn *conn)
+ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
+ {
+       struct hci_ev_key_refresh_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
+       BT_DBG("%s status %u handle %u", hdev->name, ev->status,
+              __le16_to_cpu(ev->handle));
+       hci_dev_lock(hdev);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (!conn)
+               goto unlock;
+       if (!ev->status)
+               conn->sec_level = conn->pending_sec_level;
+       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
+       if (ev->status && conn->state == BT_CONNECTED) {
+               hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
+               hci_conn_put(conn);
+               goto unlock;
+       }
+       if (conn->state == BT_CONFIG) {
+               if (!ev->status)
+                       conn->state = BT_CONNECTED;
+               hci_proto_connect_cfm(conn, ev->status);
+               hci_conn_put(conn);
+       } else {
+               hci_auth_cfm(conn, ev->status);
+               hci_conn_hold(conn);
+               conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+               hci_conn_put(conn);
+       }
+ unlock:
+       hci_dev_unlock(hdev);
+ }
 +static u8 hci_get_auth_req(struct hci_conn *conn)
  {
        /* If remote requests dedicated bonding follow that lead */
        if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
        return conn->auth_type;
  }
  
 -static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_io_capa_request *ev = (void *) skb->data;
        struct hci_conn *conn;
                goto unlock;
  
        if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
 -                      (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
 +          (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
                struct hci_cp_io_capability_reply cp;
  
                bacpy(&cp.bdaddr, &ev->bdaddr);
                conn->auth_type = hci_get_auth_req(conn);
                cp.authentication = conn->auth_type;
  
 -              if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
 -                              hci_find_remote_oob_data(hdev, &conn->dst))
 +              if (hci_find_remote_oob_data(hdev, &conn->dst) &&
 +                  (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
                        cp.oob_data = 0x01;
                else
                        cp.oob_data = 0x00;
  
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
 -                                                      sizeof(cp), &cp);
 +                           sizeof(cp), &cp);
        } else {
                struct hci_cp_io_capability_neg_reply cp;
  
                cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
  
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
 -                                                      sizeof(cp), &cp);
 +                           sizeof(cp), &cp);
        }
  
  unlock:
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_io_capa_reply *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -3133,8 -3180,8 +3177,8 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +static void hci_user_confirm_request_evt(struct hci_dev *hdev,
 +                                       struct sk_buff *skb)
  {
        struct hci_ev_user_confirm_req *ev = (void *) skb->data;
        int loc_mitm, rem_mitm, confirm_hint = 0;
        if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
                BT_DBG("Rejecting request: remote device can't provide MITM");
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
 -                                      sizeof(ev->bdaddr), &ev->bdaddr);
 +                           sizeof(ev->bdaddr), &ev->bdaddr);
                goto unlock;
        }
  
        /* If no side requires MITM protection; auto-accept */
        if ((!loc_mitm || conn->remote_cap == 0x03) &&
 -                              (!rem_mitm || conn->io_capability == 0x03)) {
 +          (!rem_mitm || conn->io_capability == 0x03)) {
  
                /* If we're not the initiators request authorization to
                 * proceed from user space (mgmt_user_confirm with
                }
  
                BT_DBG("Auto-accept of user confirmation with %ums delay",
 -                                              hdev->auto_accept_delay);
 +                     hdev->auto_accept_delay);
  
                if (hdev->auto_accept_delay > 0) {
                        int delay = msecs_to_jiffies(hdev->auto_accept_delay);
                }
  
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
 -                                              sizeof(ev->bdaddr), &ev->bdaddr);
 +                           sizeof(ev->bdaddr), &ev->bdaddr);
                goto unlock;
        }
  
@@@ -3201,8 -3248,8 +3245,8 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
 -                                                      struct sk_buff *skb)
 +static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 +                                       struct sk_buff *skb)
  {
        struct hci_ev_user_passkey_req *ev = (void *) skb->data;
  
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 +                                       struct sk_buff *skb)
  {
        struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@@ -3245,8 -3291,7 +3289,8 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_remote_host_features_evt(struct hci_dev *hdev,
 +                                       struct sk_buff *skb)
  {
        struct hci_ev_remote_host_features *ev = (void *) skb->data;
        struct inquiry_entry *ie;
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 -                                                 struct sk_buff *skb)
 +static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 +                                          struct sk_buff *skb)
  {
        struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
        struct oob_data *data;
                memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
  
                hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
 -                                                                      &cp);
 +                           &cp);
        } else {
                struct hci_cp_remote_oob_data_neg_reply cp;
  
                bacpy(&cp.bdaddr, &ev->bdaddr);
                hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
 -                                                                      &cp);
 +                           &cp);
        }
  
  unlock:
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
  
        hci_dev_lock(hdev);
  
 +      if (ev->status) {
 +              conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
 +              if (!conn)
 +                      goto unlock;
 +
 +              mgmt_connect_failed(hdev, &conn->dst, conn->type,
 +                                  conn->dst_type, ev->status);
 +              hci_proto_connect_cfm(conn, ev->status);
 +              conn->state = BT_CLOSED;
 +              hci_conn_del(conn);
 +              goto unlock;
 +      }
 +
        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
        if (!conn) {
                conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
                conn->dst_type = ev->bdaddr_type;
        }
  
 -      if (ev->status) {
 -              mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
 -                                              conn->dst_type, ev->status);
 -              hci_proto_connect_cfm(conn, ev->status);
 -              conn->state = BT_CLOSED;
 -              hci_conn_del(conn);
 -              goto unlock;
 -      }
 -
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
                                      conn->dst_type, 0, NULL, 0, NULL);
@@@ -3348,7 -3389,8 +3392,7 @@@ unlock
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 -                                              struct sk_buff *skb)
 +static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 -                                              struct sk_buff *skb)
 +static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_le_ltk_req *ev = (void *) skb->data;
        struct hci_cp_le_ltk_reply cp;
@@@ -3412,7 -3455,7 +3456,7 @@@ not_found
        hci_dev_unlock(hdev);
  }
  
 -static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
 +static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_le_meta *le_ev = (void *) skb->data;
  
@@@ -3560,6 -3603,10 +3604,10 @@@ void hci_event_packet(struct hci_dev *h
                hci_extended_inquiry_result_evt(hdev, skb);
                break;
  
+       case HCI_EV_KEY_REFRESH_COMPLETE:
+               hci_key_refresh_complete_evt(hdev, skb);
+               break;
        case HCI_EV_IO_CAPA_REQUEST:
                hci_io_capa_request_evt(hdev, skb);
                break;
index f9bffe3af026e3ba291063fa21415ed4c5c338a8,8394e3615ef6f42c6e8ec2022c3bc5fda7964000..4ca88247b7c25595b8a1c05141e74be4e714a641
  
  #include <linux/module.h>
  
 -#include <linux/types.h>
 -#include <linux/capability.h>
 -#include <linux/errno.h>
 -#include <linux/kernel.h>
 -#include <linux/sched.h>
 -#include <linux/slab.h>
 -#include <linux/poll.h>
 -#include <linux/fcntl.h>
 -#include <linux/init.h>
 -#include <linux/interrupt.h>
 -#include <linux/socket.h>
 -#include <linux/skbuff.h>
 -#include <linux/list.h>
 -#include <linux/device.h>
  #include <linux/debugfs.h>
 -#include <linux/seq_file.h>
 -#include <linux/uaccess.h>
  #include <linux/crc16.h>
 -#include <net/sock.h>
 -
 -#include <asm/unaligned.h>
  
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  #include <net/bluetooth/l2cap.h>
  #include <net/bluetooth/smp.h>
 +#include <net/bluetooth/a2mp.h>
  
  bool disable_ertm;
  
@@@ -55,9 -73,6 +55,9 @@@ static int l2cap_build_conf_req(struct 
  static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                   struct l2cap_chan *chan, int err);
  
 +static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 +                  struct sk_buff_head *skbs, u8 event);
 +
  /* ---- L2CAP channels ---- */
  
  static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
@@@ -181,7 -196,7 +181,7 @@@ static void __l2cap_state_change(struc
                                                state_to_string(state));
  
        chan->state = state;
 -      chan->ops->state_change(chan->data, state);
 +      chan->ops->state_change(chan, state);
  }
  
  static void l2cap_state_change(struct l2cap_chan *chan, int state)
@@@ -209,37 -224,6 +209,37 @@@ static inline void l2cap_chan_set_err(s
        release_sock(sk);
  }
  
 +static void __set_retrans_timer(struct l2cap_chan *chan)
 +{
 +      if (!delayed_work_pending(&chan->monitor_timer) &&
 +          chan->retrans_timeout) {
 +              l2cap_set_timer(chan, &chan->retrans_timer,
 +                              msecs_to_jiffies(chan->retrans_timeout));
 +      }
 +}
 +
 +static void __set_monitor_timer(struct l2cap_chan *chan)
 +{
 +      __clear_retrans_timer(chan);
 +      if (chan->monitor_timeout) {
 +              l2cap_set_timer(chan, &chan->monitor_timer,
 +                              msecs_to_jiffies(chan->monitor_timeout));
 +      }
 +}
 +
 +static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head,
 +                                             u16 seq)
 +{
 +      struct sk_buff *skb;
 +
 +      skb_queue_walk(head, skb) {
 +              if (bt_cb(skb)->control.txseq == seq)
 +                      return skb;
 +      }
 +
 +      return NULL;
 +}
 +
  /* ---- L2CAP sequence number lists ---- */
  
  /* For ERTM, ordered lists of sequence numbers must be tracked for
@@@ -382,7 -366,7 +382,7 @@@ static void l2cap_chan_timeout(struct w
  
        l2cap_chan_unlock(chan);
  
 -      chan->ops->close(chan->data);
 +      chan->ops->close(chan);
        mutex_unlock(&conn->chan_lock);
  
        l2cap_chan_put(chan);
@@@ -408,9 -392,6 +408,9 @@@ struct l2cap_chan *l2cap_chan_create(vo
  
        atomic_set(&chan->refcnt, 1);
  
 +      /* This flag is cleared in l2cap_chan_ready() */
 +      set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
 +
        BT_DBG("chan %p", chan);
  
        return chan;
@@@ -449,7 -430,7 +449,7 @@@ static void __l2cap_chan_add(struct l2c
        case L2CAP_CHAN_CONN_ORIENTED:
                if (conn->hcon->type == LE_LINK) {
                        /* LE connection */
 -                      chan->omtu = L2CAP_LE_DEFAULT_MTU;
 +                      chan->omtu = L2CAP_DEFAULT_MTU;
                        chan->scid = L2CAP_CID_LE_DATA;
                        chan->dcid = L2CAP_CID_LE_DATA;
                } else {
                chan->omtu = L2CAP_DEFAULT_MTU;
                break;
  
 +      case L2CAP_CHAN_CONN_FIX_A2MP:
 +              chan->scid = L2CAP_CID_A2MP;
 +              chan->dcid = L2CAP_CID_A2MP;
 +              chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
 +              chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
 +              break;
 +
        default:
                /* Raw socket can send/recv signalling messages only */
                chan->scid = L2CAP_CID_SIGNALING;
        list_add(&chan->list, &conn->chan_l);
  }
  
 -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
        mutex_lock(&conn->chan_lock);
        __l2cap_chan_add(conn, chan);
        mutex_unlock(&conn->chan_lock);
  }
  
 -static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 +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;
  
        __clear_chan_timer(chan);
  
                l2cap_chan_put(chan);
  
                chan->conn = NULL;
 -              hci_conn_put(conn->hcon);
 -      }
 -
 -      lock_sock(sk);
 -
 -      __l2cap_state_change(chan, BT_CLOSED);
 -      sock_set_flag(sk, SOCK_ZAPPED);
  
 -      if (err)
 -              __l2cap_chan_set_err(chan, err);
 -
 -      if (parent) {
 -              bt_accept_unlink(sk);
 -              parent->sk_data_ready(parent, 0);
 -      } else
 -              sk->sk_state_change(sk);
 +              if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
 +                      hci_conn_put(conn->hcon);
 +      }
  
 -      release_sock(sk);
 +      if (chan->ops->teardown)
 +              chan->ops->teardown(chan, err);
  
 -      if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
 -                      test_bit(CONF_INPUT_DONE, &chan->conf_state)))
 +      if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
                return;
  
 -      skb_queue_purge(&chan->tx_q);
 -
 -      if (chan->mode == L2CAP_MODE_ERTM) {
 -              struct srej_list *l, *tmp;
 +      switch(chan->mode) {
 +      case L2CAP_MODE_BASIC:
 +              break;
  
 +      case L2CAP_MODE_ERTM:
                __clear_retrans_timer(chan);
                __clear_monitor_timer(chan);
                __clear_ack_timer(chan);
  
                l2cap_seq_list_free(&chan->srej_list);
                l2cap_seq_list_free(&chan->retrans_list);
 -              list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
 -                      list_del(&l->list);
 -                      kfree(l);
 -              }
 -      }
 -}
 -
 -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;
 -
 -              l2cap_chan_lock(chan);
 -              __clear_chan_timer(chan);
 -              l2cap_chan_close(chan, ECONNRESET);
 -              l2cap_chan_unlock(chan);
 +              /* fall through */
  
 -              chan->ops->close(chan->data);
 +      case L2CAP_MODE_STREAMING:
 +              skb_queue_purge(&chan->tx_q);
 +              break;
        }
 +
 +      return;
  }
  
  void l2cap_chan_close(struct l2cap_chan *chan, int reason)
  
        switch (chan->state) {
        case BT_LISTEN:
 -              lock_sock(sk);
 -              l2cap_chan_cleanup_listen(sk);
 -
 -              __l2cap_state_change(chan, BT_CLOSED);
 -              sock_set_flag(sk, SOCK_ZAPPED);
 -              release_sock(sk);
 +              if (chan->ops->teardown)
 +                      chan->ops->teardown(chan, 0);
                break;
  
        case BT_CONNECTED:
                        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);
 +                      rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
                                                        sizeof(rsp), &rsp);
                }
                break;
  
        default:
 -              lock_sock(sk);
 -              sock_set_flag(sk, SOCK_ZAPPED);
 -              release_sock(sk);
 +              if (chan->ops->teardown)
 +                      chan->ops->teardown(chan, 0);
                break;
        }
  }
@@@ -619,7 -627,7 +619,7 @@@ static inline u8 l2cap_get_auth_type(st
                default:
                        return HCI_AT_NO_BONDING;
                }
 -      } else if (chan->psm == cpu_to_le16(0x0001)) {
 +      } else if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) {
                if (chan->sec_level == BT_SECURITY_LOW)
                        chan->sec_level = BT_SECURITY_SDP;
  
@@@ -765,11 -773,9 +765,11 @@@ static inline void __unpack_control(str
        if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
                __unpack_extended_control(get_unaligned_le32(skb->data),
                                          &bt_cb(skb)->control);
 +              skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
        } else {
                __unpack_enhanced_control(get_unaligned_le16(skb->data),
                                          &bt_cb(skb)->control);
 +              skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
        }
  }
  
@@@ -824,102 -830,66 +824,102 @@@ static inline void __pack_control(struc
        }
  }
  
 -static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 +static inline unsigned int __ertm_hdr_size(struct l2cap_chan *chan)
  {
 -      struct sk_buff *skb;
 -      struct l2cap_hdr *lh;
 -      struct l2cap_conn *conn = chan->conn;
 -      int count, hlen;
 -
 -      if (chan->state != BT_CONNECTED)
 -              return;
 -
        if (test_bit(FLAG_EXT_CTRL, &chan->flags))
 -              hlen = L2CAP_EXT_HDR_SIZE;
 +              return L2CAP_EXT_HDR_SIZE;
        else
 -              hlen = L2CAP_ENH_HDR_SIZE;
 +              return L2CAP_ENH_HDR_SIZE;
 +}
 +
 +static struct sk_buff *l2cap_create_sframe_pdu(struct l2cap_chan *chan,
 +                                             u32 control)
 +{
 +      struct sk_buff *skb;
 +      struct l2cap_hdr *lh;
 +      int hlen = __ertm_hdr_size(chan);
  
        if (chan->fcs == L2CAP_FCS_CRC16)
                hlen += L2CAP_FCS_SIZE;
  
 -      BT_DBG("chan %p, control 0x%8.8x", chan, control);
 -
 -      count = min_t(unsigned int, conn->mtu, hlen);
 -
 -      control |= __set_sframe(chan);
 -
 -      if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
 -              control |= __set_ctrl_final(chan);
 +      skb = bt_skb_alloc(hlen, GFP_KERNEL);
  
 -      if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
 -              control |= __set_ctrl_poll(chan);
 -
 -      skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
 -              return;
 +              return ERR_PTR(-ENOMEM);
  
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
  
 -      __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
 +      if (test_bit(FLAG_EXT_CTRL, &chan->flags))
 +              put_unaligned_le32(control, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
 +      else
 +              put_unaligned_le16(control, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
  
        if (chan->fcs == L2CAP_FCS_CRC16) {
 -              u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
 +              u16 fcs = crc16(0, (u8 *)skb->data, skb->len);
                put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
        }
  
        skb->priority = HCI_PRIO_MAX;
 -      l2cap_do_send(chan, skb);
 +      return skb;
  }
  
 -static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
 +static void l2cap_send_sframe(struct l2cap_chan *chan,
 +                            struct l2cap_ctrl *control)
  {
 -      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 -              control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 +      struct sk_buff *skb;
 +      u32 control_field;
 +
 +      BT_DBG("chan %p, control %p", chan, control);
 +
 +      if (!control->sframe)
 +              return;
 +
 +      if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
 +          !control->poll)
 +              control->final = 1;
 +
 +      if (control->super == L2CAP_SUPER_RR)
 +              clear_bit(CONN_RNR_SENT, &chan->conn_state);
 +      else if (control->super == L2CAP_SUPER_RNR)
                set_bit(CONN_RNR_SENT, &chan->conn_state);
 -      } else
 -              control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
  
 -      control |= __set_reqseq(chan, chan->buffer_seq);
 +      if (control->super != L2CAP_SUPER_SREJ) {
 +              chan->last_acked_seq = control->reqseq;
 +              __clear_ack_timer(chan);
 +      }
 +
 +      BT_DBG("reqseq %d, final %d, poll %d, super %d", control->reqseq,
 +             control->final, control->poll, control->super);
 +
 +      if (test_bit(FLAG_EXT_CTRL, &chan->flags))
 +              control_field = __pack_extended_control(control);
 +      else
 +              control_field = __pack_enhanced_control(control);
 +
 +      skb = l2cap_create_sframe_pdu(chan, control_field);
 +      if (!IS_ERR(skb))
 +              l2cap_do_send(chan, skb);
 +}
 +
 +static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
 +{
 +      struct l2cap_ctrl control;
 +
 +      BT_DBG("chan %p, poll %d", chan, poll);
 +
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
 +      control.poll = poll;
 +
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
 +              control.super = L2CAP_SUPER_RNR;
 +      else
 +              control.super = L2CAP_SUPER_RR;
  
 -      l2cap_send_sframe(chan, control);
 +      control.reqseq = chan->buffer_seq;
 +      l2cap_send_sframe(chan, &control);
  }
  
  static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
@@@ -944,13 -914,25 +944,13 @@@ static void l2cap_send_conn_req(struct 
  
  static void l2cap_chan_ready(struct l2cap_chan *chan)
  {
 -      struct sock *sk = chan->sk;
 -      struct sock *parent;
 -
 -      lock_sock(sk);
 -
 -      parent = bt_sk(sk)->parent;
 -
 -      BT_DBG("sk %p, parent %p", sk, parent);
 -
 +      /* This clears all conf flags, including CONF_NOT_COMPLETE */
        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);
 +      chan->state = BT_CONNECTED;
  
 -      release_sock(sk);
 +      chan->ops->ready(chan);
  }
  
  static void l2cap_do_start(struct l2cap_chan *chan)
                        l2cap_send_conn_req(chan);
        } else {
                struct l2cap_info_req req;
 -              req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
 +              req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
  
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
@@@ -1013,11 -995,6 +1013,11 @@@ static void l2cap_send_disconn_req(stru
                __clear_ack_timer(chan);
        }
  
 +      if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
 +              __l2cap_state_change(chan, BT_DISCONN);
 +              return;
 +      }
 +
        req.dcid = cpu_to_le16(chan->dcid);
        req.scid = cpu_to_le16(chan->scid);
        l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@@ -1076,20 -1053,20 +1076,20 @@@ static void l2cap_conn_start(struct l2c
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
                                        struct sock *parent = bt_sk(sk)->parent;
 -                                      rsp.result = cpu_to_le16(L2CAP_CR_PEND);
 -                                      rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
 +                                      rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
 +                                      rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
                                        if (parent)
                                                parent->sk_data_ready(parent, 0);
  
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
 -                                      rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 -                                      rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 +                                      rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
 +                                      rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                                }
                                release_sock(sk);
                        } else {
 -                              rsp.result = cpu_to_le16(L2CAP_CR_PEND);
 -                              rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
 +                              rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
 +                              rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
                        }
  
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
@@@ -1173,7 -1150,13 +1173,7 @@@ static void l2cap_le_conn_ready(struct 
  
        lock_sock(parent);
  
 -      /* Check for backlog size */
 -      if (sk_acceptq_is_full(parent)) {
 -              BT_DBG("backlog full %d", parent->sk_ack_backlog);
 -              goto clean;
 -      }
 -
 -      chan = pchan->ops->new_connection(pchan->data);
 +      chan = pchan->ops->new_connection(pchan);
        if (!chan)
                goto clean;
  
  
        l2cap_chan_add(conn, chan);
  
 -      __set_chan_timer(chan, sk->sk_sndtimeo);
 -
 -      __l2cap_state_change(chan, BT_CONNECTED);
 -      parent->sk_data_ready(parent, 0);
 +      l2cap_chan_ready(chan);
  
  clean:
        release_sock(parent);
@@@ -1212,11 -1198,6 +1212,11 @@@ static void l2cap_conn_ready(struct l2c
  
                l2cap_chan_lock(chan);
  
 +              if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
 +                      l2cap_chan_unlock(chan);
 +                      continue;
 +              }
 +
                if (conn->hcon->type == LE_LINK) {
                        if (smp_conn_security(conn, chan->sec_level))
                                l2cap_chan_ready(chan);
@@@ -1289,7 -1270,7 +1289,7 @@@ static void l2cap_conn_del(struct hci_c
  
                l2cap_chan_unlock(chan);
  
 -              chan->ops->close(chan->data);
 +              chan->ops->close(chan);
                l2cap_chan_put(chan);
        }
  
@@@ -1314,7 -1295,12 +1314,12 @@@ static void security_timeout(struct wor
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
                                                security_timer.work);
  
-       l2cap_conn_del(conn->hcon, ETIMEDOUT);
+       BT_DBG("conn %p", conn);
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
+               smp_chan_destroy(conn);
+               l2cap_conn_del(conn->hcon, ETIMEDOUT);
+       }
  }
  
  static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
@@@ -1458,17 -1444,21 +1463,17 @@@ int l2cap_chan_connect(struct l2cap_cha
                goto done;
        }
  
 -      lock_sock(sk);
 -
 -      switch (sk->sk_state) {
 +      switch (chan->state) {
        case BT_CONNECT:
        case BT_CONNECT2:
        case BT_CONFIG:
                /* Already connecting */
                err = 0;
 -              release_sock(sk);
                goto done;
  
        case BT_CONNECTED:
                /* Already connected */
                err = -EISCONN;
 -              release_sock(sk);
                goto done;
  
        case BT_OPEN:
  
        default:
                err = -EBADFD;
 -              release_sock(sk);
                goto done;
        }
  
        /* Set destination address and psm */
 +      lock_sock(sk);
        bacpy(&bt_sk(sk)->dst, dst);
 -
        release_sock(sk);
  
        chan->psm = psm;
@@@ -1585,20 -1576,23 +1590,20 @@@ int __l2cap_wait_ack(struct sock *sk
  static void l2cap_monitor_timeout(struct work_struct *work)
  {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 -                                                      monitor_timer.work);
 +                                             monitor_timer.work);
  
        BT_DBG("chan %p", chan);
  
        l2cap_chan_lock(chan);
  
 -      if (chan->retry_count >= chan->remote_max_tx) {
 -              l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 +      if (!chan->conn) {
                l2cap_chan_unlock(chan);
                l2cap_chan_put(chan);
                return;
        }
  
 -      chan->retry_count++;
 -      __set_monitor_timer(chan);
 +      l2cap_tx(chan, NULL, NULL, L2CAP_EV_MONITOR_TO);
  
 -      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
  }
  static void l2cap_retrans_timeout(struct work_struct *work)
  {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 -                                                      retrans_timer.work);
 +                                             retrans_timer.work);
  
        BT_DBG("chan %p", chan);
  
        l2cap_chan_lock(chan);
  
 -      chan->retry_count = 1;
 -      __set_monitor_timer(chan);
 -
 -      set_bit(CONN_WAIT_F, &chan->conn_state);
 -
 -      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
 +      if (!chan->conn) {
 +              l2cap_chan_unlock(chan);
 +              l2cap_chan_put(chan);
 +              return;
 +      }
  
 +      l2cap_tx(chan, NULL, NULL, L2CAP_EV_RETRANS_TO);
        l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
  }
  
 -static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
 +static void l2cap_streaming_send(struct l2cap_chan *chan,
 +                               struct sk_buff_head *skbs)
  {
        struct sk_buff *skb;
 +      struct l2cap_ctrl *control;
  
 -      while ((skb = skb_peek(&chan->tx_q)) &&
 -                      chan->unacked_frames) {
 -              if (bt_cb(skb)->control.txseq == chan->expected_ack_seq)
 -                      break;
 +      BT_DBG("chan %p, skbs %p", chan, skbs);
  
 -              skb = skb_dequeue(&chan->tx_q);
 -              kfree_skb(skb);
 +      skb_queue_splice_tail_init(skbs, &chan->tx_q);
  
 -              chan->unacked_frames--;
 -      }
 +      while (!skb_queue_empty(&chan->tx_q)) {
  
 -      if (!chan->unacked_frames)
 -              __clear_retrans_timer(chan);
 -}
 +              skb = skb_dequeue(&chan->tx_q);
  
 -static void l2cap_streaming_send(struct l2cap_chan *chan)
 -{
 -      struct sk_buff *skb;
 -      u32 control;
 -      u16 fcs;
 +              bt_cb(skb)->control.retries = 1;
 +              control = &bt_cb(skb)->control;
  
 -      while ((skb = skb_dequeue(&chan->tx_q))) {
 -              control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
 -              control |= __set_txseq(chan, chan->next_tx_seq);
 -              control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
 -              __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 +              control->reqseq = 0;
 +              control->txseq = chan->next_tx_seq;
 +
 +              __pack_control(chan, control, skb);
  
                if (chan->fcs == L2CAP_FCS_CRC16) {
 -                      fcs = crc16(0, (u8 *)skb->data,
 -                                              skb->len - L2CAP_FCS_SIZE);
 -                      put_unaligned_le16(fcs,
 -                                      skb->data + skb->len - L2CAP_FCS_SIZE);
 +                      u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
 +                      put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
                }
  
                l2cap_do_send(chan, skb);
  
 +              BT_DBG("Sent txseq %d", (int)control->txseq);
 +
                chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 +              chan->frames_sent++;
        }
  }
  
 -static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 +static int l2cap_ertm_send(struct l2cap_chan *chan)
  {
        struct sk_buff *skb, *tx_skb;
 -      u16 fcs;
 -      u32 control;
 +      struct l2cap_ctrl *control;
 +      int sent = 0;
  
 -      skb = skb_peek(&chan->tx_q);
 -      if (!skb)
 -              return;
 +      BT_DBG("chan %p", chan);
  
 -      while (bt_cb(skb)->control.txseq != tx_seq) {
 -              if (skb_queue_is_last(&chan->tx_q, skb))
 -                      return;
 +      if (chan->state != BT_CONNECTED)
 +              return -ENOTCONN;
  
 -              skb = skb_queue_next(&chan->tx_q, skb);
 -      }
 +      if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
 +              return 0;
  
 -      if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
 -          chan->remote_max_tx) {
 -              l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 -              return;
 -      }
 +      while (chan->tx_send_head &&
 +             chan->unacked_frames < chan->remote_tx_win &&
 +             chan->tx_state == L2CAP_TX_STATE_XMIT) {
  
 -      tx_skb = skb_clone(skb, GFP_ATOMIC);
 -      bt_cb(skb)->control.retries++;
 +              skb = chan->tx_send_head;
  
 -      control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
 -      control &= __get_sar_mask(chan);
 +              bt_cb(skb)->control.retries = 1;
 +              control = &bt_cb(skb)->control;
  
 -      if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
 -              control |= __set_ctrl_final(chan);
 +              if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
 +                      control->final = 1;
  
 -      control |= __set_reqseq(chan, chan->buffer_seq);
 -      control |= __set_txseq(chan, tx_seq);
 +              control->reqseq = chan->buffer_seq;
 +              chan->last_acked_seq = chan->buffer_seq;
 +              control->txseq = chan->next_tx_seq;
  
 -      __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 +              __pack_control(chan, control, skb);
  
 -      if (chan->fcs == L2CAP_FCS_CRC16) {
 -              fcs = crc16(0, (u8 *)tx_skb->data,
 -                                              tx_skb->len - L2CAP_FCS_SIZE);
 -              put_unaligned_le16(fcs,
 -                              tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
 +              if (chan->fcs == L2CAP_FCS_CRC16) {
 +                      u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
 +                      put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
 +              }
 +
 +              /* Clone after data has been modified. Data is assumed to be
 +                 read-only (for locking purposes) on cloned sk_buffs.
 +               */
 +              tx_skb = skb_clone(skb, GFP_KERNEL);
 +
 +              if (!tx_skb)
 +                      break;
 +
 +              __set_retrans_timer(chan);
 +
 +              chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 +              chan->unacked_frames++;
 +              chan->frames_sent++;
 +              sent++;
 +
 +              if (skb_queue_is_last(&chan->tx_q, skb))
 +                      chan->tx_send_head = NULL;
 +              else
 +                      chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
 +
 +              l2cap_do_send(chan, tx_skb);
 +              BT_DBG("Sent txseq %d", (int)control->txseq);
        }
  
 -      l2cap_do_send(chan, tx_skb);
 +      BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent,
 +             (int) chan->unacked_frames, skb_queue_len(&chan->tx_q));
 +
 +      return sent;
  }
  
 -static int l2cap_ertm_send(struct l2cap_chan *chan)
 +static void l2cap_ertm_resend(struct l2cap_chan *chan)
  {
 -      struct sk_buff *skb, *tx_skb;
 -      u16 fcs;
 -      u32 control;
 -      int nsent = 0;
 +      struct l2cap_ctrl control;
 +      struct sk_buff *skb;
 +      struct sk_buff *tx_skb;
 +      u16 seq;
  
 -      if (chan->state != BT_CONNECTED)
 -              return -ENOTCONN;
 +      BT_DBG("chan %p", chan);
  
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
 -              return 0;
 +              return;
  
 -      while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
 +      while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
 +              seq = l2cap_seq_list_pop(&chan->retrans_list);
  
 -              if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
 -                  chan->remote_max_tx) {
 -                      l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 -                      break;
 +              skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
 +              if (!skb) {
 +                      BT_DBG("Error: Can't retransmit seq %d, frame missing",
 +                              seq);
 +                      continue;
                }
  
 -              tx_skb = skb_clone(skb, GFP_ATOMIC);
 -
                bt_cb(skb)->control.retries++;
 +              control = bt_cb(skb)->control;
  
 -              control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
 -              control &= __get_sar_mask(chan);
 +              if (chan->max_tx != 0 &&
 +                  bt_cb(skb)->control.retries > chan->max_tx) {
 +                      BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
 +                      l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +                      l2cap_seq_list_clear(&chan->retrans_list);
 +                      break;
 +              }
  
 +              control.reqseq = chan->buffer_seq;
                if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
 -                      control |= __set_ctrl_final(chan);
 +                      control.final = 1;
 +              else
 +                      control.final = 0;
 +
 +              if (skb_cloned(skb)) {
 +                      /* Cloned sk_buffs are read-only, so we need a
 +                       * writeable copy
 +                       */
 +                      tx_skb = skb_copy(skb, GFP_ATOMIC);
 +              } else {
 +                      tx_skb = skb_clone(skb, GFP_ATOMIC);
 +              }
  
 -              control |= __set_reqseq(chan, chan->buffer_seq);
 -              control |= __set_txseq(chan, chan->next_tx_seq);
 -              control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
 +              if (!tx_skb) {
 +                      l2cap_seq_list_clear(&chan->retrans_list);
 +                      break;
 +              }
  
 -              __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 +              /* Update skb contents */
 +              if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
 +                      put_unaligned_le32(__pack_extended_control(&control),
 +                                         tx_skb->data + L2CAP_HDR_SIZE);
 +              } else {
 +                      put_unaligned_le16(__pack_enhanced_control(&control),
 +                                         tx_skb->data + L2CAP_HDR_SIZE);
 +              }
  
                if (chan->fcs == L2CAP_FCS_CRC16) {
 -                      fcs = crc16(0, (u8 *)skb->data,
 -                                              tx_skb->len - L2CAP_FCS_SIZE);
 -                      put_unaligned_le16(fcs, skb->data +
 -                                              tx_skb->len - L2CAP_FCS_SIZE);
 +                      u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
 +                      put_unaligned_le16(fcs, skb_put(tx_skb,
 +                                                      L2CAP_FCS_SIZE));
                }
  
                l2cap_do_send(chan, tx_skb);
  
 -              __set_retrans_timer(chan);
 -
 -              bt_cb(skb)->control.txseq = chan->next_tx_seq;
 +              BT_DBG("Resent txseq %d", control.txseq);
  
 -              chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 -
 -              if (bt_cb(skb)->control.retries == 1) {
 -                      chan->unacked_frames++;
 -
 -                      if (!nsent++)
 -                              __clear_ack_timer(chan);
 -              }
 -
 -              chan->frames_sent++;
 -
 -              if (skb_queue_is_last(&chan->tx_q, skb))
 -                      chan->tx_send_head = NULL;
 -              else
 -                      chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
 +              chan->last_acked_seq = chan->buffer_seq;
        }
 -
 -      return nsent;
  }
  
 -static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 +static void l2cap_retransmit(struct l2cap_chan *chan,
 +                           struct l2cap_ctrl *control)
  {
 -      int ret;
 +      BT_DBG("chan %p, control %p", chan, control);
  
 -      if (!skb_queue_empty(&chan->tx_q))
 -              chan->tx_send_head = chan->tx_q.next;
 -
 -      chan->next_tx_seq = chan->expected_ack_seq;
 -      ret = l2cap_ertm_send(chan);
 -      return ret;
 +      l2cap_seq_list_append(&chan->retrans_list, control->reqseq);
 +      l2cap_ertm_resend(chan);
  }
  
 -static void __l2cap_send_ack(struct l2cap_chan *chan)
 +static void l2cap_retransmit_all(struct l2cap_chan *chan,
 +                               struct l2cap_ctrl *control)
  {
 -      u32 control = 0;
 +      struct sk_buff *skb;
  
 -      control |= __set_reqseq(chan, chan->buffer_seq);
 +      BT_DBG("chan %p, control %p", chan, control);
  
 -      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 -              control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 -              set_bit(CONN_RNR_SENT, &chan->conn_state);
 -              l2cap_send_sframe(chan, control);
 -              return;
 -      }
 +      if (control->poll)
 +              set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +
 +      l2cap_seq_list_clear(&chan->retrans_list);
  
 -      if (l2cap_ertm_send(chan) > 0)
 +      if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return;
  
 -      control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 -      l2cap_send_sframe(chan, control);
 +      if (chan->unacked_frames) {
 +              skb_queue_walk(&chan->tx_q, skb) {
 +                      if (bt_cb(skb)->control.txseq == control->reqseq ||
 +                              skb == chan->tx_send_head)
 +                              break;
 +              }
 +
 +              skb_queue_walk_from(&chan->tx_q, skb) {
 +                      if (skb == chan->tx_send_head)
 +                              break;
 +
 +                      l2cap_seq_list_append(&chan->retrans_list,
 +                                            bt_cb(skb)->control.txseq);
 +              }
 +
 +              l2cap_ertm_resend(chan);
 +      }
  }
  
  static void l2cap_send_ack(struct l2cap_chan *chan)
  {
 -      __clear_ack_timer(chan);
 -      __l2cap_send_ack(chan);
 -}
 +      struct l2cap_ctrl control;
 +      u16 frames_to_ack = __seq_offset(chan, chan->buffer_seq,
 +                                       chan->last_acked_seq);
 +      int threshold;
  
 -static void l2cap_send_srejtail(struct l2cap_chan *chan)
 -{
 -      struct srej_list *tail;
 -      u32 control;
 +      BT_DBG("chan %p last_acked_seq %d buffer_seq %d",
 +             chan, chan->last_acked_seq, chan->buffer_seq);
 +
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
  
 -      control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
 -      control |= __set_ctrl_final(chan);
 +      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
 +          chan->rx_state == L2CAP_RX_STATE_RECV) {
 +              __clear_ack_timer(chan);
 +              control.super = L2CAP_SUPER_RNR;
 +              control.reqseq = chan->buffer_seq;
 +              l2cap_send_sframe(chan, &control);
 +      } else {
 +              if (!test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) {
 +                      l2cap_ertm_send(chan);
 +                      /* If any i-frames were sent, they included an ack */
 +                      if (chan->buffer_seq == chan->last_acked_seq)
 +                              frames_to_ack = 0;
 +              }
  
 -      tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
 -      control |= __set_reqseq(chan, tail->tx_seq);
 +              /* Ack now if the tx window is 3/4ths full.
 +               * Calculate without mul or div
 +               */
 +              threshold = chan->tx_win;
 +              threshold += threshold << 1;
 +              threshold >>= 2;
 +
 +              BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack,
 +                     threshold);
 +
 +              if (frames_to_ack >= threshold) {
 +                      __clear_ack_timer(chan);
 +                      control.super = L2CAP_SUPER_RR;
 +                      control.reqseq = chan->buffer_seq;
 +                      l2cap_send_sframe(chan, &control);
 +                      frames_to_ack = 0;
 +              }
  
 -      l2cap_send_sframe(chan, control);
 +              if (frames_to_ack)
 +                      __set_ack_timer(chan);
 +      }
  }
  
  static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
@@@ -2021,7 -1956,10 +2026,7 @@@ static struct sk_buff *l2cap_create_ifr
        if (!conn)
                return ERR_PTR(-ENOTCONN);
  
 -      if (test_bit(FLAG_EXT_CTRL, &chan->flags))
 -              hlen = L2CAP_EXT_HDR_SIZE;
 -      else
 -              hlen = L2CAP_ENH_HDR_SIZE;
 +      hlen = __ertm_hdr_size(chan);
  
        if (sdulen)
                hlen += L2CAP_SDULEN_SIZE;
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
  
 -      __put_control(chan, 0, skb_put(skb, __ctrl_size(chan)));
 +      /* Control header is populated later */
 +      if (test_bit(FLAG_EXT_CTRL, &chan->flags))
 +              put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
 +      else
 +              put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
  
        if (sdulen)
                put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
                return ERR_PTR(err);
        }
  
 -      if (chan->fcs == L2CAP_FCS_CRC16)
 -              put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
 -
 +      bt_cb(skb)->control.fcs = chan->fcs;
        bt_cb(skb)->control.retries = 0;
        return skb;
  }
@@@ -2068,6 -2004,7 +2073,6 @@@ static int l2cap_segment_sdu(struct l2c
        struct sk_buff *skb;
        u16 sdu_len;
        size_t pdu_len;
 -      int err = 0;
        u8 sar;
  
        BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len);
        pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
  
        /* Adjust for largest possible L2CAP overhead. */
 -      pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE;
 +      if (chan->fcs)
 +              pdu_len -= L2CAP_FCS_SIZE;
 +
 +      pdu_len -= __ertm_hdr_size(chan);
  
        /* Remote device may have requested smaller PDUs */
        pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
                }
        }
  
 -      return err;
 +      return 0;
  }
  
  int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
                if (err)
                        break;
  
 -              if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL)
 -                      chan->tx_send_head = seg_queue.next;
 -              skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
 -
                if (chan->mode == L2CAP_MODE_ERTM)
 -                      err = l2cap_ertm_send(chan);
 +                      l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST);
                else
 -                      l2cap_streaming_send(chan);
 +                      l2cap_streaming_send(chan, &seg_queue);
  
 -              if (err >= 0)
 -                      err = len;
 +              err = len;
  
                /* If the skbs were not queued for sending, they'll still be in
                 * seg_queue and need to be purged.
        return err;
  }
  
 +static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
 +{
 +      struct l2cap_ctrl control;
 +      u16 seq;
 +
 +      BT_DBG("chan %p, txseq %d", chan, txseq);
 +
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
 +      control.super = L2CAP_SUPER_SREJ;
 +
 +      for (seq = chan->expected_tx_seq; seq != txseq;
 +           seq = __next_seq(chan, seq)) {
 +              if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) {
 +                      control.reqseq = seq;
 +                      l2cap_send_sframe(chan, &control);
 +                      l2cap_seq_list_append(&chan->srej_list, seq);
 +              }
 +      }
 +
 +      chan->expected_tx_seq = __next_seq(chan, txseq);
 +}
 +
 +static void l2cap_send_srej_tail(struct l2cap_chan *chan)
 +{
 +      struct l2cap_ctrl control;
 +
 +      BT_DBG("chan %p", chan);
 +
 +      if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR)
 +              return;
 +
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
 +      control.super = L2CAP_SUPER_SREJ;
 +      control.reqseq = chan->srej_list.tail;
 +      l2cap_send_sframe(chan, &control);
 +}
 +
 +static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq)
 +{
 +      struct l2cap_ctrl control;
 +      u16 initial_head;
 +      u16 seq;
 +
 +      BT_DBG("chan %p, txseq %d", chan, txseq);
 +
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
 +      control.super = L2CAP_SUPER_SREJ;
 +
 +      /* Capture initial list head to allow only one pass through the list. */
 +      initial_head = chan->srej_list.head;
 +
 +      do {
 +              seq = l2cap_seq_list_pop(&chan->srej_list);
 +              if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR)
 +                      break;
 +
 +              control.reqseq = seq;
 +              l2cap_send_sframe(chan, &control);
 +              l2cap_seq_list_append(&chan->srej_list, seq);
 +      } while (chan->srej_list.head != initial_head);
 +}
 +
 +static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq)
 +{
 +      struct sk_buff *acked_skb;
 +      u16 ackseq;
 +
 +      BT_DBG("chan %p, reqseq %d", chan, reqseq);
 +
 +      if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq)
 +              return;
 +
 +      BT_DBG("expected_ack_seq %d, unacked_frames %d",
 +             chan->expected_ack_seq, chan->unacked_frames);
 +
 +      for (ackseq = chan->expected_ack_seq; ackseq != reqseq;
 +           ackseq = __next_seq(chan, ackseq)) {
 +
 +              acked_skb = l2cap_ertm_seq_in_queue(&chan->tx_q, ackseq);
 +              if (acked_skb) {
 +                      skb_unlink(acked_skb, &chan->tx_q);
 +                      kfree_skb(acked_skb);
 +                      chan->unacked_frames--;
 +              }
 +      }
 +
 +      chan->expected_ack_seq = reqseq;
 +
 +      if (chan->unacked_frames == 0)
 +              __clear_retrans_timer(chan);
 +
 +      BT_DBG("unacked_frames %d", (int) chan->unacked_frames);
 +}
 +
 +static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan)
 +{
 +      BT_DBG("chan %p", chan);
 +
 +      chan->expected_tx_seq = chan->buffer_seq;
 +      l2cap_seq_list_clear(&chan->srej_list);
 +      skb_queue_purge(&chan->srej_q);
 +      chan->rx_state = L2CAP_RX_STATE_RECV;
 +}
 +
 +static void l2cap_tx_state_xmit(struct l2cap_chan *chan,
 +                              struct l2cap_ctrl *control,
 +                              struct sk_buff_head *skbs, u8 event)
 +{
 +      BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
 +             event);
 +
 +      switch (event) {
 +      case L2CAP_EV_DATA_REQUEST:
 +              if (chan->tx_send_head == NULL)
 +                      chan->tx_send_head = skb_peek(skbs);
 +
 +              skb_queue_splice_tail_init(skbs, &chan->tx_q);
 +              l2cap_ertm_send(chan);
 +              break;
 +      case L2CAP_EV_LOCAL_BUSY_DETECTED:
 +              BT_DBG("Enter LOCAL_BUSY");
 +              set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 +
 +              if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
 +                      /* The SREJ_SENT state must be aborted if we are to
 +                       * enter the LOCAL_BUSY state.
 +                       */
 +                      l2cap_abort_rx_srej_sent(chan);
 +              }
 +
 +              l2cap_send_ack(chan);
 +
 +              break;
 +      case L2CAP_EV_LOCAL_BUSY_CLEAR:
 +              BT_DBG("Exit LOCAL_BUSY");
 +              clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 +
 +              if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
 +                      struct l2cap_ctrl local_control;
 +
 +                      memset(&local_control, 0, sizeof(local_control));
 +                      local_control.sframe = 1;
 +                      local_control.super = L2CAP_SUPER_RR;
 +                      local_control.poll = 1;
 +                      local_control.reqseq = chan->buffer_seq;
 +                      l2cap_send_sframe(chan, &local_control);
 +
 +                      chan->retry_count = 1;
 +                      __set_monitor_timer(chan);
 +                      chan->tx_state = L2CAP_TX_STATE_WAIT_F;
 +              }
 +              break;
 +      case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
 +              l2cap_process_reqseq(chan, control->reqseq);
 +              break;
 +      case L2CAP_EV_EXPLICIT_POLL:
 +              l2cap_send_rr_or_rnr(chan, 1);
 +              chan->retry_count = 1;
 +              __set_monitor_timer(chan);
 +              __clear_ack_timer(chan);
 +              chan->tx_state = L2CAP_TX_STATE_WAIT_F;
 +              break;
 +      case L2CAP_EV_RETRANS_TO:
 +              l2cap_send_rr_or_rnr(chan, 1);
 +              chan->retry_count = 1;
 +              __set_monitor_timer(chan);
 +              chan->tx_state = L2CAP_TX_STATE_WAIT_F;
 +              break;
 +      case L2CAP_EV_RECV_FBIT:
 +              /* Nothing to process */
 +              break;
 +      default:
 +              break;
 +      }
 +}
 +
 +static void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
 +                                struct l2cap_ctrl *control,
 +                                struct sk_buff_head *skbs, u8 event)
 +{
 +      BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
 +             event);
 +
 +      switch (event) {
 +      case L2CAP_EV_DATA_REQUEST:
 +              if (chan->tx_send_head == NULL)
 +                      chan->tx_send_head = skb_peek(skbs);
 +              /* Queue data, but don't send. */
 +              skb_queue_splice_tail_init(skbs, &chan->tx_q);
 +              break;
 +      case L2CAP_EV_LOCAL_BUSY_DETECTED:
 +              BT_DBG("Enter LOCAL_BUSY");
 +              set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 +
 +              if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
 +                      /* The SREJ_SENT state must be aborted if we are to
 +                       * enter the LOCAL_BUSY state.
 +                       */
 +                      l2cap_abort_rx_srej_sent(chan);
 +              }
 +
 +              l2cap_send_ack(chan);
 +
 +              break;
 +      case L2CAP_EV_LOCAL_BUSY_CLEAR:
 +              BT_DBG("Exit LOCAL_BUSY");
 +              clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 +
 +              if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
 +                      struct l2cap_ctrl local_control;
 +                      memset(&local_control, 0, sizeof(local_control));
 +                      local_control.sframe = 1;
 +                      local_control.super = L2CAP_SUPER_RR;
 +                      local_control.poll = 1;
 +                      local_control.reqseq = chan->buffer_seq;
 +                      l2cap_send_sframe(chan, &local_control);
 +
 +                      chan->retry_count = 1;
 +                      __set_monitor_timer(chan);
 +                      chan->tx_state = L2CAP_TX_STATE_WAIT_F;
 +              }
 +              break;
 +      case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
 +              l2cap_process_reqseq(chan, control->reqseq);
 +
 +              /* Fall through */
 +
 +      case L2CAP_EV_RECV_FBIT:
 +              if (control && control->final) {
 +                      __clear_monitor_timer(chan);
 +                      if (chan->unacked_frames > 0)
 +                              __set_retrans_timer(chan);
 +                      chan->retry_count = 0;
 +                      chan->tx_state = L2CAP_TX_STATE_XMIT;
 +                      BT_DBG("recv fbit tx_state 0x2.2%x", chan->tx_state);
 +              }
 +              break;
 +      case L2CAP_EV_EXPLICIT_POLL:
 +              /* Ignore */
 +              break;
 +      case L2CAP_EV_MONITOR_TO:
 +              if (chan->max_tx == 0 || chan->retry_count < chan->max_tx) {
 +                      l2cap_send_rr_or_rnr(chan, 1);
 +                      __set_monitor_timer(chan);
 +                      chan->retry_count++;
 +              } else {
 +                      l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 +              }
 +              break;
 +      default:
 +              break;
 +      }
 +}
 +
 +static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 +                   struct sk_buff_head *skbs, u8 event)
 +{
 +      BT_DBG("chan %p, control %p, skbs %p, event %d, state %d",
 +             chan, control, skbs, event, chan->tx_state);
 +
 +      switch (chan->tx_state) {
 +      case L2CAP_TX_STATE_XMIT:
 +              l2cap_tx_state_xmit(chan, control, skbs, event);
 +              break;
 +      case L2CAP_TX_STATE_WAIT_F:
 +              l2cap_tx_state_wait_f(chan, control, skbs, event);
 +              break;
 +      default:
 +              /* Ignore event */
 +              break;
 +      }
 +}
 +
 +static void l2cap_pass_to_tx(struct l2cap_chan *chan,
 +                           struct l2cap_ctrl *control)
 +{
 +      BT_DBG("chan %p, control %p", chan, control);
 +      l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
 +}
 +
 +static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
 +                                struct l2cap_ctrl *control)
 +{
 +      BT_DBG("chan %p, control %p", chan, control);
 +      l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_FBIT);
 +}
 +
  /* Copy frame to all raw sockets on that connection */
  static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
  {
                if (!nskb)
                        continue;
  
 -              if (chan->ops->recv(chan->data, nskb))
 +              if (chan->ops->recv(chan, nskb))
                        kfree_skb(nskb);
        }
  
@@@ -2551,9 -2200,9 +2556,9 @@@ static struct sk_buff *l2cap_build_cmd(
        lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
  
        if (conn->hcon->type == LE_LINK)
 -              lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
 +              lh->cid = __constant_cpu_to_le16(L2CAP_CID_LE_SIGNALING);
        else
 -              lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
 +              lh->cid = __constant_cpu_to_le16(L2CAP_CID_SIGNALING);
  
        cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
        cmd->code  = code;
@@@ -2665,8 -2314,8 +2670,8 @@@ static void l2cap_add_opt_efs(void **pt
                efs.stype       = chan->local_stype;
                efs.msdu        = cpu_to_le16(chan->local_msdu);
                efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
 -              efs.acc_lat     = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
 -              efs.flush_to    = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
 +              efs.acc_lat     = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
 +              efs.flush_to    = __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
                break;
  
        case L2CAP_MODE_STREAMING:
  static void l2cap_ack_timeout(struct work_struct *work)
  {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
 -                                                      ack_timer.work);
 +                                             ack_timer.work);
 +      u16 frames_to_ack;
  
        BT_DBG("chan %p", chan);
  
        l2cap_chan_lock(chan);
  
 -      __l2cap_send_ack(chan);
 +      frames_to_ack = __seq_offset(chan, chan->buffer_seq,
 +                                   chan->last_acked_seq);
  
 -      l2cap_chan_unlock(chan);
 +      if (frames_to_ack)
 +              l2cap_send_rr_or_rnr(chan, 0);
  
 +      l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
  }
  
 -static inline int l2cap_ertm_init(struct l2cap_chan *chan)
 +int l2cap_ertm_init(struct l2cap_chan *chan)
  {
        int err;
  
        chan->expected_ack_seq = 0;
        chan->unacked_frames = 0;
        chan->buffer_seq = 0;
 -      chan->num_acked = 0;
        chan->frames_sent = 0;
        chan->last_acked_seq = 0;
        chan->sdu = NULL;
  
        skb_queue_head_init(&chan->srej_q);
  
 -      INIT_LIST_HEAD(&chan->srej_l);
        err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
        if (err < 0)
                return err;
  
 -      return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
 +      err = l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
 +      if (err < 0)
 +              l2cap_seq_list_free(&chan->srej_list);
 +
 +      return err;
  }
  
  static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@@ -2869,7 -2512,6 +2874,7 @@@ done
                break;
  
        case L2CAP_MODE_STREAMING:
 +              l2cap_txwin_setup(chan);
                rfc.mode            = L2CAP_MODE_STREAMING;
                rfc.txwin_size      = 0;
                rfc.max_transmit    = 0;
        }
  
        req->dcid  = cpu_to_le16(chan->dcid);
 -      req->flags = cpu_to_le16(0);
 +      req->flags = __constant_cpu_to_le16(0);
  
        return ptr - data;
  }
@@@ -3120,7 -2762,7 +3125,7 @@@ done
        }
        rsp->scid   = cpu_to_le16(chan->dcid);
        rsp->result = cpu_to_le16(result);
 -      rsp->flags  = cpu_to_le16(0x0000);
 +      rsp->flags  = __constant_cpu_to_le16(0);
  
        return ptr - data;
  }
@@@ -3219,7 -2861,7 +3224,7 @@@ static int l2cap_parse_conf_rsp(struct 
        }
  
        req->dcid   = cpu_to_le16(chan->dcid);
 -      req->flags  = cpu_to_le16(0x0000);
 +      req->flags  = __constant_cpu_to_le16(0);
  
        return ptr - data;
  }
@@@ -3246,8 -2888,8 +3251,8 @@@ void __l2cap_connect_rsp_defer(struct l
  
        rsp.scid   = cpu_to_le16(chan->dcid);
        rsp.dcid   = cpu_to_le16(chan->scid);
 -      rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
 -      rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
 +      rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
 +      rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
        l2cap_send_cmd(conn, chan->ident,
                                L2CAP_CONN_RSP, sizeof(rsp), &rsp);
  
@@@ -3285,8 -2927,8 +3290,8 @@@ static void l2cap_conf_rfc_get(struct l
         * did not send an RFC option.
         */
        rfc.mode = chan->mode;
 -      rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
 -      rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
 +      rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
 +      rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
        rfc.max_pdu_size = cpu_to_le16(chan->imtu);
  
        BT_ERR("Expected RFC option was not found, using defaults");
@@@ -3349,7 -2991,7 +3354,7 @@@ static inline int l2cap_connect_req(str
        lock_sock(parent);
  
        /* Check if the ACL is secure enough (if not SDP) */
 -      if (psm != cpu_to_le16(0x0001) &&
 +      if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
                conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
  
        result = L2CAP_CR_NO_MEM;
  
 -      /* Check for backlog size */
 -      if (sk_acceptq_is_full(parent)) {
 -              BT_DBG("backlog full %d", parent->sk_ack_backlog);
 +      /* Check if we already have channel with that dcid */
 +      if (__l2cap_get_chan_by_dcid(conn, scid))
                goto response;
 -      }
  
 -      chan = pchan->ops->new_connection(pchan->data);
 +      chan = pchan->ops->new_connection(pchan);
        if (!chan)
                goto response;
  
        sk = chan->sk;
  
 -      /* Check if we already have channel with that dcid */
 -      if (__l2cap_get_chan_by_dcid(conn, scid)) {
 -              sock_set_flag(sk, SOCK_ZAPPED);
 -              chan->ops->close(chan->data);
 -              goto response;
 -      }
 -
        hci_conn_hold(conn->hcon);
  
        bacpy(&bt_sk(sk)->src, conn->src);
@@@ -3421,7 -3072,7 +3426,7 @@@ sendresp
  
        if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
                struct l2cap_info_req info;
 -              info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
 +              info.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
  
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
@@@ -3543,7 -3194,7 +3548,7 @@@ static inline int l2cap_config_req(stru
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
  
 -              rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
 +              rej.reason = __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID);
                rej.scid = cpu_to_le16(chan->scid);
                rej.dcid = cpu_to_le16(chan->dcid);
  
        memcpy(chan->conf_req + chan->conf_len, req->data, len);
        chan->conf_len += len;
  
 -      if (flags & 0x0001) {
 +      if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
                /* Incomplete config. Send empty response. */
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                l2cap_build_conf_rsp(chan, rsp,
 -                                      L2CAP_CONF_SUCCESS, 0x0001), rsp);
 +                                      L2CAP_CONF_SUCCESS, flags), rsp);
                goto unlock;
        }
  
        if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
  
 -              l2cap_state_change(chan, BT_CONNECTED);
 -
                if (chan->mode == L2CAP_MODE_ERTM ||
                    chan->mode == L2CAP_MODE_STREAMING)
                        err = l2cap_ertm_init(chan);
  
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                        l2cap_build_conf_rsp(chan, rsp,
 -                                      L2CAP_CONF_SUCCESS, 0x0000), rsp);
 +                                      L2CAP_CONF_SUCCESS, flags), rsp);
        }
  
  unlock:
@@@ -3714,7 -3367,7 +3719,7 @@@ static inline int l2cap_config_rsp(stru
                goto done;
        }
  
 -      if (flags & 0x01)
 +      if (flags & L2CAP_CONF_FLAG_CONTINUATION)
                goto done;
  
        set_bit(CONF_INPUT_DONE, &chan->conf_state);
        if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
  
 -              l2cap_state_change(chan, BT_CONNECTED);
                if (chan->mode == L2CAP_MODE_ERTM ||
                    chan->mode == L2CAP_MODE_STREAMING)
                        err = l2cap_ertm_init(chan);
@@@ -3775,7 -3429,7 +3780,7 @@@ static inline int l2cap_disconnect_req(
  
        l2cap_chan_unlock(chan);
  
 -      chan->ops->close(chan->data);
 +      chan->ops->close(chan);
        l2cap_chan_put(chan);
  
        mutex_unlock(&conn->chan_lock);
@@@ -3809,7 -3463,7 +3814,7 @@@ static inline int l2cap_disconnect_rsp(
  
        l2cap_chan_unlock(chan);
  
 -      chan->ops->close(chan->data);
 +      chan->ops->close(chan);
        l2cap_chan_put(chan);
  
        mutex_unlock(&conn->chan_lock);
@@@ -3830,8 -3484,8 +3835,8 @@@ static inline int l2cap_information_req
                u8 buf[8];
                u32 feat_mask = l2cap_feat_mask;
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
 -              rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
 -              rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
 +              rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
 +              rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                                         | L2CAP_FEAT_FCS;
                else
                        l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
  
 -              rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 -              rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
 +              rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 +              rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
 -              rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
 +              rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(rsp), &rsp);
        }
@@@ -3899,7 -3553,7 +3904,7 @@@ static inline int l2cap_information_rsp
  
                if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
                        struct l2cap_info_req req;
 -                      req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 +                      req.type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
  
                        conn->info_ident = l2cap_get_ident(conn);
  
@@@ -4134,9 -3788,9 +4139,9 @@@ static inline int l2cap_conn_param_upda
  
        err = l2cap_check_conn_param(min, max, latency, to_multiplier);
        if (err)
 -              rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
 +              rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
        else
 -              rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
 +              rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
  
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
                                                        sizeof(rsp), &rsp);
@@@ -4284,7 -3938,7 +4289,7 @@@ static inline void l2cap_sig_channel(st
                        BT_ERR("Wrong link type (%d)", err);
  
                        /* FIXME: Map err to a valid reason */
 -                      rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
 +                      rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
                        l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
                }
  
@@@ -4316,38 -3970,65 +4321,38 @@@ static int l2cap_check_fcs(struct l2cap
        return 0;
  }
  
 -static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 +static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
  {
 -      u32 control = 0;
 +      struct l2cap_ctrl control;
  
 -      chan->frames_sent = 0;
 +      BT_DBG("chan %p", chan);
  
 -      control |= __set_reqseq(chan, chan->buffer_seq);
 +      memset(&control, 0, sizeof(control));
 +      control.sframe = 1;
 +      control.final = 1;
 +      control.reqseq = chan->buffer_seq;
 +      set_bit(CONN_SEND_FBIT, &chan->conn_state);
  
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 -              control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
 -              l2cap_send_sframe(chan, control);
 -              set_bit(CONN_RNR_SENT, &chan->conn_state);
 +              control.super = L2CAP_SUPER_RNR;
 +              l2cap_send_sframe(chan, &control);
        }
  
 -      if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
 -              l2cap_retransmit_frames(chan);
 +      if (test_and_clear_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
 +          chan->unacked_frames > 0)
 +              __set_retrans_timer(chan);
  
 +      /* Send pending iframes */
        l2cap_ertm_send(chan);
  
        if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
 -                      chan->frames_sent == 0) {
 -              control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 -              l2cap_send_sframe(chan, control);
 -      }
 -}
 -
 -static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
 -{
 -      struct sk_buff *next_skb;
 -      int tx_seq_offset, next_tx_seq_offset;
 -
 -      bt_cb(skb)->control.txseq = tx_seq;
 -      bt_cb(skb)->control.sar = sar;
 -
 -      next_skb = skb_peek(&chan->srej_q);
 -
 -      tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 -
 -      while (next_skb) {
 -              if (bt_cb(next_skb)->control.txseq == tx_seq)
 -                      return -EINVAL;
 -
 -              next_tx_seq_offset = __seq_offset(chan,
 -                      bt_cb(next_skb)->control.txseq, chan->buffer_seq);
 -
 -              if (next_tx_seq_offset > tx_seq_offset) {
 -                      __skb_queue_before(&chan->srej_q, next_skb, skb);
 -                      return 0;
 -              }
 -
 -              if (skb_queue_is_last(&chan->srej_q, next_skb))
 -                      next_skb = NULL;
 -              else
 -                      next_skb = skb_queue_next(&chan->srej_q, next_skb);
 +          test_bit(CONN_SEND_FBIT, &chan->conn_state)) {
 +              /* F-bit wasn't sent in an s-frame or i-frame yet, so
 +               * send it now.
 +               */
 +              control.super = L2CAP_SUPER_RR;
 +              l2cap_send_sframe(chan, &control);
        }
 -
 -      __skb_queue_tail(&chan->srej_q, skb);
 -
 -      return 0;
  }
  
  static void append_skb_frag(struct sk_buff *skb,
        skb->truesize += new_frag->truesize;
  }
  
 -static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
 +static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
 +                              struct l2cap_ctrl *control)
  {
        int err = -EINVAL;
  
 -      switch (__get_ctrl_sar(chan, control)) {
 +      switch (control->sar) {
        case L2CAP_SAR_UNSEGMENTED:
                if (chan->sdu)
                        break;
  
 -              err = chan->ops->recv(chan->data, skb);
 +              err = chan->ops->recv(chan, skb);
                break;
  
        case L2CAP_SAR_START:
                if (chan->sdu->len != chan->sdu_len)
                        break;
  
 -              err = chan->ops->recv(chan->data, chan->sdu);
 +              err = chan->ops->recv(chan, chan->sdu);
  
                if (!err) {
                        /* Reassembly complete */
        return err;
  }
  
 -static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 +void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
  {
 -      BT_DBG("chan %p, Enter local busy", chan);
 +      u8 event;
  
 -      set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 -      l2cap_seq_list_clear(&chan->srej_list);
 +      if (chan->mode != L2CAP_MODE_ERTM)
 +              return;
  
 -      __set_ack_timer(chan);
 +      event = busy ? L2CAP_EV_LOCAL_BUSY_DETECTED : L2CAP_EV_LOCAL_BUSY_CLEAR;
 +      l2cap_tx(chan, NULL, NULL, event);
  }
  
 -static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 +static int l2cap_rx_queued_iframes(struct l2cap_chan *chan)
  {
 -      u32 control;
 -
 -      if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
 -              goto done;
 +      int err = 0;
 +      /* Pass sequential frames to l2cap_reassemble_sdu()
 +       * until a gap is encountered.
 +       */
  
 -      control = __set_reqseq(chan, chan->buffer_seq);
 -      control |= __set_ctrl_poll(chan);
 -      control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 -      l2cap_send_sframe(chan, control);
 -      chan->retry_count = 1;
 +      BT_DBG("chan %p", chan);
  
 -      __clear_retrans_timer(chan);
 -      __set_monitor_timer(chan);
 +      while (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 +              struct sk_buff *skb;
 +              BT_DBG("Searching for skb with txseq %d (queue len %d)",
 +                     chan->buffer_seq, skb_queue_len(&chan->srej_q));
  
 -      set_bit(CONN_WAIT_F, &chan->conn_state);
 +              skb = l2cap_ertm_seq_in_queue(&chan->srej_q, chan->buffer_seq);
  
 -done:
 -      clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 -      clear_bit(CONN_RNR_SENT, &chan->conn_state);
 +              if (!skb)
 +                      break;
  
 -      BT_DBG("chan %p, Exit local busy", chan);
 -}
 +              skb_unlink(skb, &chan->srej_q);
 +              chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
 +              err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->control);
 +              if (err)
 +                      break;
 +      }
  
 -void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 -{
 -      if (chan->mode == L2CAP_MODE_ERTM) {
 -              if (busy)
 -                      l2cap_ertm_enter_local_busy(chan);
 -              else
 -                      l2cap_ertm_exit_local_busy(chan);
 +      if (skb_queue_empty(&chan->srej_q)) {
 +              chan->rx_state = L2CAP_RX_STATE_RECV;
 +              l2cap_send_ack(chan);
        }
 +
 +      return err;
  }
  
 -static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 +static void l2cap_handle_srej(struct l2cap_chan *chan,
 +                            struct l2cap_ctrl *control)
  {
        struct sk_buff *skb;
 -      u32 control;
  
 -      while ((skb = skb_peek(&chan->srej_q)) &&
 -                      !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 -              int err;
 +      BT_DBG("chan %p, control %p", chan, control);
  
 -              if (bt_cb(skb)->control.txseq != tx_seq)
 -                      break;
 +      if (control->reqseq == chan->next_tx_seq) {
 +              BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
 +              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +              return;
 +      }
  
 -              skb = skb_dequeue(&chan->srej_q);
 -              control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
 -              err = l2cap_reassemble_sdu(chan, skb, control);
 +      skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
  
 -              if (err < 0) {
 -                      l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 -                      break;
 -              }
 +      if (skb == NULL) {
 +              BT_DBG("Seq %d not available for retransmission",
 +                     control->reqseq);
 +              return;
 +      }
  
 -              chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
 -              tx_seq = __next_seq(chan, tx_seq);
 +      if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
 +              BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
 +              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +              return;
        }
 -}
  
 -static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 -{
 -      struct srej_list *l, *tmp;
 -      u32 control;
 +      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
 -      list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
 -              if (l->tx_seq == tx_seq) {
 -                      list_del(&l->list);
 -                      kfree(l);
 -                      return;
 +      if (control->poll) {
 +              l2cap_pass_to_tx(chan, control);
 +
 +              set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +              l2cap_retransmit(chan, control);
 +              l2cap_ertm_send(chan);
 +
 +              if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
 +                      set_bit(CONN_SREJ_ACT, &chan->conn_state);
 +                      chan->srej_save_reqseq = control->reqseq;
 +              }
 +      } else {
 +              l2cap_pass_to_tx_fbit(chan, control);
 +
 +              if (control->final) {
 +                      if (chan->srej_save_reqseq != control->reqseq ||
 +                          !test_and_clear_bit(CONN_SREJ_ACT,
 +                                              &chan->conn_state))
 +                              l2cap_retransmit(chan, control);
 +              } else {
 +                      l2cap_retransmit(chan, control);
 +                      if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
 +                              set_bit(CONN_SREJ_ACT, &chan->conn_state);
 +                              chan->srej_save_reqseq = control->reqseq;
 +                      }
                }
 -              control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
 -              control |= __set_reqseq(chan, l->tx_seq);
 -              l2cap_send_sframe(chan, control);
 -              list_del(&l->list);
 -              list_add_tail(&l->list, &chan->srej_l);
        }
  }
  
 -static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 +static void l2cap_handle_rej(struct l2cap_chan *chan,
 +                           struct l2cap_ctrl *control)
  {
 -      struct srej_list *new;
 -      u32 control;
 -
 -      while (tx_seq != chan->expected_tx_seq) {
 -              control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
 -              control |= __set_reqseq(chan, chan->expected_tx_seq);
 -              l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq);
 -              l2cap_send_sframe(chan, control);
 +      struct sk_buff *skb;
  
 -              new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
 -              if (!new)
 -                      return -ENOMEM;
 +      BT_DBG("chan %p, control %p", chan, control);
  
 -              new->tx_seq = chan->expected_tx_seq;
 +      if (control->reqseq == chan->next_tx_seq) {
 +              BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
 +              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +              return;
 +      }
  
 -              chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 +      skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
  
 -              list_add_tail(&new->list, &chan->srej_l);
 +      if (chan->max_tx && skb &&
 +          bt_cb(skb)->control.retries >= chan->max_tx) {
 +              BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
 +              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +              return;
        }
  
 -      chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 +      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 +
 +      l2cap_pass_to_tx(chan, control);
  
 -      return 0;
 +      if (control->final) {
 +              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 +                      l2cap_retransmit_all(chan, control);
 +      } else {
 +              l2cap_retransmit_all(chan, control);
 +              l2cap_ertm_send(chan);
 +              if (chan->tx_state == L2CAP_TX_STATE_WAIT_F)
 +                      set_bit(CONN_REJ_ACT, &chan->conn_state);
 +      }
  }
  
 -static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 +static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
  {
 -      u16 tx_seq = __get_txseq(chan, rx_control);
 -      u16 req_seq = __get_reqseq(chan, rx_control);
 -      u8 sar = __get_ctrl_sar(chan, rx_control);
 -      int tx_seq_offset, expected_tx_seq_offset;
 -      int num_to_ack = (chan->tx_win/6) + 1;
 -      int err = 0;
 +      BT_DBG("chan %p, txseq %d", chan, txseq);
  
 -      BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
 -                                                      tx_seq, rx_control);
 +      BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq,
 +             chan->expected_tx_seq);
  
 -      if (__is_ctrl_final(chan, rx_control) &&
 -                      test_bit(CONN_WAIT_F, &chan->conn_state)) {
 -              __clear_monitor_timer(chan);
 -              if (chan->unacked_frames > 0)
 -                      __set_retrans_timer(chan);
 -              clear_bit(CONN_WAIT_F, &chan->conn_state);
 -      }
 +      if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
 +              if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
 +                                                              chan->tx_win) {
 +                      /* See notes below regarding "double poll" and
 +                       * invalid packets.
 +                       */
 +                      if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
 +                              BT_DBG("Invalid/Ignore - after SREJ");
 +                              return L2CAP_TXSEQ_INVALID_IGNORE;
 +                      } else {
 +                              BT_DBG("Invalid - in window after SREJ sent");
 +                              return L2CAP_TXSEQ_INVALID;
 +                      }
 +              }
  
 -      chan->expected_ack_seq = req_seq;
 -      l2cap_drop_acked_frames(chan);
 +              if (chan->srej_list.head == txseq) {
 +                      BT_DBG("Expected SREJ");
 +                      return L2CAP_TXSEQ_EXPECTED_SREJ;
 +              }
  
 -      tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 +              if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) {
 +                      BT_DBG("Duplicate SREJ - txseq already stored");
 +                      return L2CAP_TXSEQ_DUPLICATE_SREJ;
 +              }
  
 -      /* invalid tx_seq */
 -      if (tx_seq_offset >= chan->tx_win) {
 -              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 -              goto drop;
 +              if (l2cap_seq_list_contains(&chan->srej_list, txseq)) {
 +                      BT_DBG("Unexpected SREJ - not requested");
 +                      return L2CAP_TXSEQ_UNEXPECTED_SREJ;
 +              }
        }
  
 -      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 -              if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
 -                      l2cap_send_ack(chan);
 -              goto drop;
 +      if (chan->expected_tx_seq == txseq) {
 +              if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
 +                  chan->tx_win) {
 +                      BT_DBG("Invalid - txseq outside tx window");
 +                      return L2CAP_TXSEQ_INVALID;
 +              } else {
 +                      BT_DBG("Expected");
 +                      return L2CAP_TXSEQ_EXPECTED;
 +              }
        }
  
 -      if (tx_seq == chan->expected_tx_seq)
 -              goto expected;
 +      if (__seq_offset(chan, txseq, chan->last_acked_seq) <
 +              __seq_offset(chan, chan->expected_tx_seq,
 +                           chan->last_acked_seq)){
 +              BT_DBG("Duplicate - expected_tx_seq later than txseq");
 +              return L2CAP_TXSEQ_DUPLICATE;
 +      }
 +
 +      if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) {
 +              /* A source of invalid packets is a "double poll" condition,
 +               * where delays cause us to send multiple poll packets.  If
 +               * the remote stack receives and processes both polls,
 +               * sequence numbers can wrap around in such a way that a
 +               * resent frame has a sequence number that looks like new data
 +               * with a sequence gap.  This would trigger an erroneous SREJ
 +               * request.
 +               *
 +               * Fortunately, this is impossible with a tx window that's
 +               * less than half of the maximum sequence number, which allows
 +               * invalid frames to be safely ignored.
 +               *
 +               * With tx window sizes greater than half of the tx window
 +               * maximum, the frame is invalid and cannot be ignored.  This
 +               * causes a disconnect.
 +               */
  
 -      if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 -              struct srej_list *first;
 +              if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
 +                      BT_DBG("Invalid/Ignore - txseq outside tx window");
 +                      return L2CAP_TXSEQ_INVALID_IGNORE;
 +              } else {
 +                      BT_DBG("Invalid - txseq outside tx window");
 +                      return L2CAP_TXSEQ_INVALID;
 +              }
 +      } else {
 +              BT_DBG("Unexpected - txseq indicates missing frames");
 +              return L2CAP_TXSEQ_UNEXPECTED;
 +      }
 +}
  
 -              first = list_first_entry(&chan->srej_l,
 -                              struct srej_list, list);
 -              if (tx_seq == first->tx_seq) {
 -                      l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 -                      l2cap_check_srej_gap(chan, tx_seq);
 +static int l2cap_rx_state_recv(struct l2cap_chan *chan,
 +                             struct l2cap_ctrl *control,
 +                             struct sk_buff *skb, u8 event)
 +{
 +      int err = 0;
 +      bool skb_in_use = 0;
  
 -                      list_del(&first->list);
 -                      kfree(first);
 +      BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
 +             event);
  
 -                      if (list_empty(&chan->srej_l)) {
 -                              chan->buffer_seq = chan->buffer_seq_srej;
 -                              clear_bit(CONN_SREJ_SENT, &chan->conn_state);
 -                              l2cap_send_ack(chan);
 -                              BT_DBG("chan %p, Exit SREJ_SENT", chan);
 +      switch (event) {
 +      case L2CAP_EV_RECV_IFRAME:
 +              switch (l2cap_classify_txseq(chan, control->txseq)) {
 +              case L2CAP_TXSEQ_EXPECTED:
 +                      l2cap_pass_to_tx(chan, control);
 +
 +                      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 +                              BT_DBG("Busy, discarding expected seq %d",
 +                                     control->txseq);
 +                              break;
                        }
 -              } else {
 -                      struct srej_list *l;
  
 -                      /* duplicated tx_seq */
 -                      if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
 -                              goto drop;
 +                      chan->expected_tx_seq = __next_seq(chan,
 +                                                         control->txseq);
 +
 +                      chan->buffer_seq = chan->expected_tx_seq;
 +                      skb_in_use = 1;
  
 -                      list_for_each_entry(l, &chan->srej_l, list) {
 -                              if (l->tx_seq == tx_seq) {
 -                                      l2cap_resend_srejframe(chan, tx_seq);
 -                                      return 0;
 +                      err = l2cap_reassemble_sdu(chan, skb, control);
 +                      if (err)
 +                              break;
 +
 +                      if (control->final) {
 +                              if (!test_and_clear_bit(CONN_REJ_ACT,
 +                                                      &chan->conn_state)) {
 +                                      control->final = 0;
 +                                      l2cap_retransmit_all(chan, control);
 +                                      l2cap_ertm_send(chan);
                                }
                        }
  
 -                      err = l2cap_send_srejframe(chan, tx_seq);
 -                      if (err < 0) {
 -                              l2cap_send_disconn_req(chan->conn, chan, -err);
 -                              return err;
 +                      if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
 +                              l2cap_send_ack(chan);
 +                      break;
 +              case L2CAP_TXSEQ_UNEXPECTED:
 +                      l2cap_pass_to_tx(chan, control);
 +
 +                      /* Can't issue SREJ frames in the local busy state.
 +                       * Drop this frame, it will be seen as missing
 +                       * when local busy is exited.
 +                       */
 +                      if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
 +                              BT_DBG("Busy, discarding unexpected seq %d",
 +                                     control->txseq);
 +                              break;
                        }
 -              }
 -      } else {
 -              expected_tx_seq_offset = __seq_offset(chan,
 -                              chan->expected_tx_seq, chan->buffer_seq);
  
 -              /* duplicated tx_seq */
 -              if (tx_seq_offset < expected_tx_seq_offset)
 -                      goto drop;
 -
 -              set_bit(CONN_SREJ_SENT, &chan->conn_state);
 +                      /* There was a gap in the sequence, so an SREJ
 +                       * must be sent for each missing frame.  The
 +                       * current frame is stored for later use.
 +                       */
 +                      skb_queue_tail(&chan->srej_q, skb);
 +                      skb_in_use = 1;
 +                      BT_DBG("Queued %p (queue len %d)", skb,
 +                             skb_queue_len(&chan->srej_q));
  
 -              BT_DBG("chan %p, Enter SREJ", chan);
 +                      clear_bit(CONN_SREJ_ACT, &chan->conn_state);
 +                      l2cap_seq_list_clear(&chan->srej_list);
 +                      l2cap_send_srej(chan, control->txseq);
  
 -              INIT_LIST_HEAD(&chan->srej_l);
 -              chan->buffer_seq_srej = chan->buffer_seq;
 +                      chan->rx_state = L2CAP_RX_STATE_SREJ_SENT;
 +                      break;
 +              case L2CAP_TXSEQ_DUPLICATE:
 +                      l2cap_pass_to_tx(chan, control);
 +                      break;
 +              case L2CAP_TXSEQ_INVALID_IGNORE:
 +                      break;
 +              case L2CAP_TXSEQ_INVALID:
 +              default:
 +                      l2cap_send_disconn_req(chan->conn, chan,
 +                                             ECONNRESET);
 +                      break;
 +              }
 +              break;
 +      case L2CAP_EV_RECV_RR:
 +              l2cap_pass_to_tx(chan, control);
 +              if (control->final) {
 +                      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
 -              __skb_queue_head_init(&chan->srej_q);
 -              l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 +                      if (!test_and_clear_bit(CONN_REJ_ACT,
 +                                              &chan->conn_state)) {
 +                              control->final = 0;
 +                              l2cap_retransmit_all(chan, control);
 +                      }
  
 -              /* Set P-bit only if there are some I-frames to ack. */
 -              if (__clear_ack_timer(chan))
 -                      set_bit(CONN_SEND_PBIT, &chan->conn_state);
 +                      l2cap_ertm_send(chan);
 +              } else if (control->poll) {
 +                      l2cap_send_i_or_rr_or_rnr(chan);
 +              } else {
 +                      if (test_and_clear_bit(CONN_REMOTE_BUSY,
 +                                             &chan->conn_state) &&
 +                          chan->unacked_frames)
 +                              __set_retrans_timer(chan);
  
 -              err = l2cap_send_srejframe(chan, tx_seq);
 -              if (err < 0) {
 -                      l2cap_send_disconn_req(chan->conn, chan, -err);
 -                      return err;
 +                      l2cap_ertm_send(chan);
                }
 -      }
 -      return 0;
 -
 -expected:
 -      chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 -
 -      if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 -              bt_cb(skb)->control.txseq = tx_seq;
 -              bt_cb(skb)->control.sar = sar;
 -              __skb_queue_tail(&chan->srej_q, skb);
 -              return 0;
 +              break;
 +      case L2CAP_EV_RECV_RNR:
 +              set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 +              l2cap_pass_to_tx(chan, control);
 +              if (control && control->poll) {
 +                      set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +                      l2cap_send_rr_or_rnr(chan, 0);
 +              }
 +              __clear_retrans_timer(chan);
 +              l2cap_seq_list_clear(&chan->retrans_list);
 +              break;
 +      case L2CAP_EV_RECV_REJ:
 +              l2cap_handle_rej(chan, control);
 +              break;
 +      case L2CAP_EV_RECV_SREJ:
 +              l2cap_handle_srej(chan, control);
 +              break;
 +      default:
 +              break;
        }
  
 -      err = l2cap_reassemble_sdu(chan, skb, rx_control);
 -      chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
 -
 -      if (err < 0) {
 -              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 -              return err;
 +      if (skb && !skb_in_use) {
 +              BT_DBG("Freeing %p", skb);
 +              kfree_skb(skb);
        }
  
 -      if (__is_ctrl_final(chan, rx_control)) {
 -              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 -                      l2cap_retransmit_frames(chan);
 -      }
 +      return err;
 +}
  
 +static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
 +                                  struct l2cap_ctrl *control,
 +                                  struct sk_buff *skb, u8 event)
 +{
 +      int err = 0;
 +      u16 txseq = control->txseq;
 +      bool skb_in_use = 0;
 +
 +      BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
 +             event);
 +
 +      switch (event) {
 +      case L2CAP_EV_RECV_IFRAME:
 +              switch (l2cap_classify_txseq(chan, txseq)) {
 +              case L2CAP_TXSEQ_EXPECTED:
 +                      /* Keep frame for reassembly later */
 +                      l2cap_pass_to_tx(chan, control);
 +                      skb_queue_tail(&chan->srej_q, skb);
 +                      skb_in_use = 1;
 +                      BT_DBG("Queued %p (queue len %d)", skb,
 +                             skb_queue_len(&chan->srej_q));
 +
 +                      chan->expected_tx_seq = __next_seq(chan, txseq);
 +                      break;
 +              case L2CAP_TXSEQ_EXPECTED_SREJ:
 +                      l2cap_seq_list_pop(&chan->srej_list);
  
 -      chan->num_acked = (chan->num_acked + 1) % num_to_ack;
 -      if (chan->num_acked == num_to_ack - 1)
 -              l2cap_send_ack(chan);
 -      else
 -              __set_ack_timer(chan);
 +                      l2cap_pass_to_tx(chan, control);
 +                      skb_queue_tail(&chan->srej_q, skb);
 +                      skb_in_use = 1;
 +                      BT_DBG("Queued %p (queue len %d)", skb,
 +                             skb_queue_len(&chan->srej_q));
  
 -      return 0;
 +                      err = l2cap_rx_queued_iframes(chan);
 +                      if (err)
 +                              break;
  
 -drop:
 -      kfree_skb(skb);
 -      return 0;
 -}
 +                      break;
 +              case L2CAP_TXSEQ_UNEXPECTED:
 +                      /* Got a frame that can't be reassembled yet.
 +                       * Save it for later, and send SREJs to cover
 +                       * the missing frames.
 +                       */
 +                      skb_queue_tail(&chan->srej_q, skb);
 +                      skb_in_use = 1;
 +                      BT_DBG("Queued %p (queue len %d)", skb,
 +                             skb_queue_len(&chan->srej_q));
 +
 +                      l2cap_pass_to_tx(chan, control);
 +                      l2cap_send_srej(chan, control->txseq);
 +                      break;
 +              case L2CAP_TXSEQ_UNEXPECTED_SREJ:
 +                      /* This frame was requested with an SREJ, but
 +                       * some expected retransmitted frames are
 +                       * missing.  Request retransmission of missing
 +                       * SREJ'd frames.
 +                       */
 +                      skb_queue_tail(&chan->srej_q, skb);
 +                      skb_in_use = 1;
 +                      BT_DBG("Queued %p (queue len %d)", skb,
 +                             skb_queue_len(&chan->srej_q));
 +
 +                      l2cap_pass_to_tx(chan, control);
 +                      l2cap_send_srej_list(chan, control->txseq);
 +                      break;
 +              case L2CAP_TXSEQ_DUPLICATE_SREJ:
 +                      /* We've already queued this frame.  Drop this copy. */
 +                      l2cap_pass_to_tx(chan, control);
 +                      break;
 +              case L2CAP_TXSEQ_DUPLICATE:
 +                      /* Expecting a later sequence number, so this frame
 +                       * was already received.  Ignore it completely.
 +                       */
 +                      break;
 +              case L2CAP_TXSEQ_INVALID_IGNORE:
 +                      break;
 +              case L2CAP_TXSEQ_INVALID:
 +              default:
 +                      l2cap_send_disconn_req(chan->conn, chan,
 +                                             ECONNRESET);
 +                      break;
 +              }
 +              break;
 +      case L2CAP_EV_RECV_RR:
 +              l2cap_pass_to_tx(chan, control);
 +              if (control->final) {
 +                      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
  
 -static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
 -{
 -      BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
 -                              __get_reqseq(chan, rx_control), rx_control);
 +                      if (!test_and_clear_bit(CONN_REJ_ACT,
 +                                              &chan->conn_state)) {
 +                              control->final = 0;
 +                              l2cap_retransmit_all(chan, control);
 +                      }
  
 -      chan->expected_ack_seq = __get_reqseq(chan, rx_control);
 -      l2cap_drop_acked_frames(chan);
 +                      l2cap_ertm_send(chan);
 +              } else if (control->poll) {
 +                      if (test_and_clear_bit(CONN_REMOTE_BUSY,
 +                                             &chan->conn_state) &&
 +                          chan->unacked_frames) {
 +                              __set_retrans_timer(chan);
 +                      }
  
 -      if (__is_ctrl_poll(chan, rx_control)) {
 -              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))
 +                      set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +                      l2cap_send_srej_tail(chan);
 +              } else {
 +                      if (test_and_clear_bit(CONN_REMOTE_BUSY,
 +                                             &chan->conn_state) &&
 +                          chan->unacked_frames)
                                __set_retrans_timer(chan);
  
 -                      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 -                      l2cap_send_srejtail(chan);
 +                      l2cap_send_ack(chan);
 +              }
 +              break;
 +      case L2CAP_EV_RECV_RNR:
 +              set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 +              l2cap_pass_to_tx(chan, control);
 +              if (control->poll) {
 +                      l2cap_send_srej_tail(chan);
                } else {
 -                      l2cap_send_i_or_rr_or_rnr(chan);
 +                      struct l2cap_ctrl rr_control;
 +                      memset(&rr_control, 0, sizeof(rr_control));
 +                      rr_control.sframe = 1;
 +                      rr_control.super = L2CAP_SUPER_RR;
 +                      rr_control.reqseq = chan->buffer_seq;
 +                      l2cap_send_sframe(chan, &rr_control);
                }
  
 -      } else if (__is_ctrl_final(chan, rx_control)) {
 -              clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 -
 -              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 -                      l2cap_retransmit_frames(chan);
 -
 -      } else {
 -              if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
 -                              (chan->unacked_frames > 0))
 -                      __set_retrans_timer(chan);
 +              break;
 +      case L2CAP_EV_RECV_REJ:
 +              l2cap_handle_rej(chan, control);
 +              break;
 +      case L2CAP_EV_RECV_SREJ:
 +              l2cap_handle_srej(chan, control);
 +              break;
 +      }
  
 -              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);
 +      if (skb && !skb_in_use) {
 +              BT_DBG("Freeing %p", skb);
 +              kfree_skb(skb);
        }
 +
 +      return err;
  }
  
 -static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
 +static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
  {
 -      u16 tx_seq = __get_reqseq(chan, rx_control);
 -
 -      BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 -
 -      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 -
 -      chan->expected_ack_seq = tx_seq;
 -      l2cap_drop_acked_frames(chan);
 +      /* Make sure reqseq is for a packet that has been sent but not acked */
 +      u16 unacked;
  
 -      if (__is_ctrl_final(chan, rx_control)) {
 -              if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
 -                      l2cap_retransmit_frames(chan);
 -      } else {
 -              l2cap_retransmit_frames(chan);
 -
 -              if (test_bit(CONN_WAIT_F, &chan->conn_state))
 -                      set_bit(CONN_REJ_ACT, &chan->conn_state);
 -      }
 +      unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq);
 +      return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked;
  }
 -static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
 -{
 -      u16 tx_seq = __get_reqseq(chan, rx_control);
  
 -      BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 -
 -      clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 -
 -      if (__is_ctrl_poll(chan, rx_control)) {
 -              chan->expected_ack_seq = tx_seq;
 -              l2cap_drop_acked_frames(chan);
 -
 -              set_bit(CONN_SEND_FBIT, &chan->conn_state);
 -              l2cap_retransmit_one_frame(chan, tx_seq);
 +static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 +                  struct sk_buff *skb, u8 event)
 +{
 +      int err = 0;
  
 -              l2cap_ertm_send(chan);
 +      BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan,
 +             control, skb, event, chan->rx_state);
  
 -              if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
 -                      chan->srej_save_reqseq = tx_seq;
 -                      set_bit(CONN_SREJ_ACT, &chan->conn_state);
 +      if (__valid_reqseq(chan, control->reqseq)) {
 +              switch (chan->rx_state) {
 +              case L2CAP_RX_STATE_RECV:
 +                      err = l2cap_rx_state_recv(chan, control, skb, event);
 +                      break;
 +              case L2CAP_RX_STATE_SREJ_SENT:
 +                      err = l2cap_rx_state_srej_sent(chan, control, skb,
 +                                                     event);
 +                      break;
 +              default:
 +                      /* shut it down */
 +                      break;
                }
 -      } else if (__is_ctrl_final(chan, rx_control)) {
 -              if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
 -                              chan->srej_save_reqseq == tx_seq)
 -                      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 (test_bit(CONN_WAIT_F, &chan->conn_state)) {
 -                      chan->srej_save_reqseq = tx_seq;
 -                      set_bit(CONN_SREJ_ACT, &chan->conn_state);
 -              }
 +              BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
 +                     control->reqseq, chan->next_tx_seq,
 +                     chan->expected_ack_seq);
 +              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
        }
 +
 +      return err;
  }
  
 -static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
 +static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 +                         struct sk_buff *skb)
  {
 -      u16 tx_seq = __get_reqseq(chan, rx_control);
 +      int err = 0;
  
 -      BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 +      BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb,
 +             chan->rx_state);
  
 -      set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 -      chan->expected_ack_seq = tx_seq;
 -      l2cap_drop_acked_frames(chan);
 +      if (l2cap_classify_txseq(chan, control->txseq) ==
 +          L2CAP_TXSEQ_EXPECTED) {
 +              l2cap_pass_to_tx(chan, control);
  
 -      if (__is_ctrl_poll(chan, rx_control))
 -              set_bit(CONN_SEND_FBIT, &chan->conn_state);
 +              BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
 +                     __next_seq(chan, chan->buffer_seq));
  
 -      if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
 -              __clear_retrans_timer(chan);
 -              if (__is_ctrl_poll(chan, rx_control))
 -                      l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
 -              return;
 -      }
 +              chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
  
 -      if (__is_ctrl_poll(chan, rx_control)) {
 -              l2cap_send_srejtail(chan);
 +              l2cap_reassemble_sdu(chan, skb, control);
        } else {
 -              rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
 -              l2cap_send_sframe(chan, rx_control);
 -      }
 -}
 -
 -static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 -{
 -      BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
 +              if (chan->sdu) {
 +                      kfree_skb(chan->sdu);
 +                      chan->sdu = NULL;
 +              }
 +              chan->sdu_last_frag = NULL;
 +              chan->sdu_len = 0;
  
 -      if (__is_ctrl_final(chan, rx_control) &&
 -                      test_bit(CONN_WAIT_F, &chan->conn_state)) {
 -              __clear_monitor_timer(chan);
 -              if (chan->unacked_frames > 0)
 -                      __set_retrans_timer(chan);
 -              clear_bit(CONN_WAIT_F, &chan->conn_state);
 +              if (skb) {
 +                      BT_DBG("Freeing %p", skb);
 +                      kfree_skb(skb);
 +              }
        }
  
 -      switch (__get_ctrl_super(chan, rx_control)) {
 -      case L2CAP_SUPER_RR:
 -              l2cap_data_channel_rrframe(chan, rx_control);
 -              break;
 -
 -      case L2CAP_SUPER_REJ:
 -              l2cap_data_channel_rejframe(chan, rx_control);
 -              break;
 -
 -      case L2CAP_SUPER_SREJ:
 -              l2cap_data_channel_srejframe(chan, rx_control);
 -              break;
 -
 -      case L2CAP_SUPER_RNR:
 -              l2cap_data_channel_rnrframe(chan, rx_control);
 -              break;
 -      }
 +      chan->last_acked_seq = control->txseq;
 +      chan->expected_tx_seq = __next_seq(chan, control->txseq);
  
 -      kfree_skb(skb);
 -      return 0;
 +      return err;
  }
  
 -static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 +static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
  {
 -      u32 control;
 -      u16 req_seq;
 -      int len, next_tx_seq_offset, req_seq_offset;
 +      struct l2cap_ctrl *control = &bt_cb(skb)->control;
 +      u16 len;
 +      u8 event;
  
        __unpack_control(chan, skb);
  
 -      control = __get_control(chan, skb->data);
 -      skb_pull(skb, __ctrl_size(chan));
        len = skb->len;
  
        /*
         * We can just drop the corrupted I-frame here.
         * Receiver will miss it and start proper recovery
 -       * procedures and ask retransmission.
 +       * procedures and ask for retransmission.
         */
        if (l2cap_check_fcs(chan, skb))
                goto drop;
  
 -      if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
 +      if (!control->sframe && control->sar == L2CAP_SAR_START)
                len -= L2CAP_SDULEN_SIZE;
  
        if (chan->fcs == L2CAP_FCS_CRC16)
                goto drop;
        }
  
 -      req_seq = __get_reqseq(chan, control);
 -
 -      req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
 -
 -      next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
 -                                              chan->expected_ack_seq);
 +      if (!control->sframe) {
 +              int err;
  
 -      /* check for invalid req-seq */
 -      if (req_seq_offset > next_tx_seq_offset) {
 -              l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 -              goto drop;
 -      }
 +              BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d",
 +                     control->sar, control->reqseq, control->final,
 +                     control->txseq);
  
 -      if (!__is_sframe(chan, control)) {
 -              if (len < 0) {
 -                      l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 +              /* Validate F-bit - F=0 always valid, F=1 only
 +               * valid in TX WAIT_F
 +               */
 +              if (control->final && chan->tx_state != L2CAP_TX_STATE_WAIT_F)
                        goto drop;
 +
 +              if (chan->mode != L2CAP_MODE_STREAMING) {
 +                      event = L2CAP_EV_RECV_IFRAME;
 +                      err = l2cap_rx(chan, control, skb, event);
 +              } else {
 +                      err = l2cap_stream_rx(chan, control, skb);
                }
  
 -              l2cap_data_channel_iframe(chan, control, skb);
 +              if (err)
 +                      l2cap_send_disconn_req(chan->conn, chan,
 +                                             ECONNRESET);
        } else {
 +              const u8 rx_func_to_event[4] = {
 +                      L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
 +                      L2CAP_EV_RECV_RNR, L2CAP_EV_RECV_SREJ
 +              };
 +
 +              /* Only I-frames are expected in streaming mode */
 +              if (chan->mode == L2CAP_MODE_STREAMING)
 +                      goto drop;
 +
 +              BT_DBG("sframe reqseq %d, final %d, poll %d, super %d",
 +                     control->reqseq, control->final, control->poll,
 +                     control->super);
 +
                if (len != 0) {
                        BT_ERR("%d", len);
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
                }
  
 -              l2cap_data_channel_sframe(chan, control, skb);
 +              /* Validate F and P bits */
 +              if (control->final && (control->poll ||
 +                                     chan->tx_state != L2CAP_TX_STATE_WAIT_F))
 +                      goto drop;
 +
 +              event = rx_func_to_event[control->super];
 +              if (l2cap_rx(chan, control, skb, event))
 +                      l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
        }
  
        return 0;
@@@ -5124,27 -4620,19 +5129,27 @@@ drop
        return 0;
  }
  
 -static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
 +static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
 +                             struct sk_buff *skb)
  {
        struct l2cap_chan *chan;
 -      u32 control;
 -      u16 tx_seq;
 -      int len;
  
        chan = l2cap_get_chan_by_scid(conn, cid);
        if (!chan) {
 -              BT_DBG("unknown cid 0x%4.4x", cid);
 -              /* Drop packet and return */
 -              kfree_skb(skb);
 -              return 0;
 +              if (cid == L2CAP_CID_A2MP) {
 +                      chan = a2mp_channel_create(conn, skb);
 +                      if (!chan) {
 +                              kfree_skb(skb);
 +                              return;
 +                      }
 +
 +                      l2cap_chan_lock(chan);
 +              } else {
 +                      BT_DBG("unknown cid 0x%4.4x", cid);
 +                      /* Drop packet and return */
 +                      kfree_skb(skb);
 +                      return;
 +              }
        }
  
        BT_DBG("chan %p, len %d", chan, skb->len);
                if (chan->imtu < skb->len)
                        goto drop;
  
 -              if (!chan->ops->recv(chan->data, skb))
 +              if (!chan->ops->recv(chan, skb))
                        goto done;
                break;
  
        case L2CAP_MODE_ERTM:
 -              l2cap_ertm_data_rcv(chan, skb);
 -
 -              goto done;
 -
        case L2CAP_MODE_STREAMING:
 -              control = __get_control(chan, skb->data);
 -              skb_pull(skb, __ctrl_size(chan));
 -              len = skb->len;
 -
 -              if (l2cap_check_fcs(chan, skb))
 -                      goto drop;
 -
 -              if (__is_sar_start(chan, control))
 -                      len -= L2CAP_SDULEN_SIZE;
 -
 -              if (chan->fcs == L2CAP_FCS_CRC16)
 -                      len -= L2CAP_FCS_SIZE;
 -
 -              if (len > chan->mps || len < 0 || __is_sframe(chan, control))
 -                      goto drop;
 -
 -              tx_seq = __get_txseq(chan, control);
 -
 -              if (chan->expected_tx_seq != tx_seq) {
 -                      /* Frame(s) missing - must discard partial SDU */
 -                      kfree_skb(chan->sdu);
 -                      chan->sdu = NULL;
 -                      chan->sdu_last_frag = NULL;
 -                      chan->sdu_len = 0;
 -
 -                      /* TODO: Notify userland of missing data */
 -              }
 -
 -              chan->expected_tx_seq = __next_seq(chan, tx_seq);
 -
 -              if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
 -                      l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
 -
 +              l2cap_data_rcv(chan, skb);
                goto done;
  
        default:
@@@ -5181,10 -4705,11 +5186,10 @@@ drop
  
  done:
        l2cap_chan_unlock(chan);
 -
 -      return 0;
  }
  
 -static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 +static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
 +                                struct sk_buff *skb)
  {
        struct l2cap_chan *chan;
  
        if (chan->imtu < skb->len)
                goto drop;
  
 -      if (!chan->ops->recv(chan->data, skb))
 -              return 0;
 +      if (!chan->ops->recv(chan, skb))
 +              return;
  
  drop:
        kfree_skb(skb);
 -
 -      return 0;
  }
  
 -static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
 -                                  struct sk_buff *skb)
 +static void l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
 +                            struct sk_buff *skb)
  {
        struct l2cap_chan *chan;
  
        if (chan->imtu < skb->len)
                goto drop;
  
 -      if (!chan->ops->recv(chan->data, skb))
 -              return 0;
 +      if (!chan->ops->recv(chan, skb))
 +              return;
  
  drop:
        kfree_skb(skb);
 -
 -      return 0;
  }
  
  static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
  
        case L2CAP_CID_CONN_LESS:
                psm = get_unaligned((__le16 *) skb->data);
 -              skb_pull(skb, 2);
 +              skb_pull(skb, L2CAP_PSMLEN_SIZE);
                l2cap_conless_channel(conn, psm, skb);
                break;
  
@@@ -5450,17 -4979,6 +5455,17 @@@ int l2cap_security_cfm(struct hci_conn 
                        rsp.status = cpu_to_le16(stat);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
                                                        sizeof(rsp), &rsp);
 +
 +                      if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
 +                          res == L2CAP_CR_SUCCESS) {
 +                              char buf[128];
 +                              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++;
 +                      }
                }
  
                l2cap_chan_unlock(chan);
diff --combined net/bluetooth/mgmt.c
index 958f764cc6ab6d8c5f8ddb9b70548deb6d06a106,991d5b6676747f55e42b805171ece9ecd441c745..c72307cc25fc7af2fc679203ef19f29142d17a2f
@@@ -24,6 -24,8 +24,6 @@@
  
  /* Bluetooth HCI Management interface */
  
 -#include <linux/kernel.h>
 -#include <linux/uaccess.h>
  #include <linux/module.h>
  #include <asm/unaligned.h>
  
@@@ -712,8 -714,7 +712,8 @@@ static struct pending_cmd *mgmt_pending
  }
  
  static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
 -                               void (*cb)(struct pending_cmd *cmd, void *data),
 +                               void (*cb)(struct pending_cmd *cmd,
 +                                          void *data),
                                 void *data)
  {
        struct list_head *p, *n;
@@@ -870,7 -871,7 +870,7 @@@ static int set_discoverable(struct soc
        }
  
        if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 -                      mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 +          mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
                                 MGMT_STATUS_BUSY);
                goto failed;
@@@ -977,7 -978,7 +977,7 @@@ static int set_connectable(struct sock 
        }
  
        if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
 -                      mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
 +          mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
                                 MGMT_STATUS_BUSY);
                goto failed;
                scan = 0;
  
                if (test_bit(HCI_ISCAN, &hdev->flags) &&
 -                                              hdev->discov_timeout > 0)
 +                  hdev->discov_timeout > 0)
                        cancel_delayed_work(&hdev->discov_off);
        }
  
@@@ -1055,7 -1056,7 +1055,7 @@@ static int set_link_security(struct soc
                bool changed = false;
  
                if (!!cp->val != test_bit(HCI_LINK_SECURITY,
 -                                                      &hdev->dev_flags)) {
 +                                        &hdev->dev_flags)) {
                        change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
                        changed = true;
                }
@@@ -1316,7 -1317,7 +1316,7 @@@ static bool enable_service_cache(struc
  }
  
  static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
 -                                                              u16 len)
 +                     u16 len)
  {
        struct mgmt_cp_remove_uuid *cp = data;
        struct pending_cmd *cmd;
@@@ -1441,7 -1442,7 +1441,7 @@@ unlock
  }
  
  static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
 -                                                              u16 len)
 +                        u16 len)
  {
        struct mgmt_cp_load_link_keys *cp = data;
        u16 key_count, expected_len;
                                        sizeof(struct mgmt_link_key_info);
        if (expected_len != len) {
                BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
 -                                                      len, expected_len);
 +                     len, expected_len);
                return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
                                  MGMT_STATUS_INVALID_PARAMS);
        }
  
        BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
 -                                                              key_count);
 +             key_count);
  
        hci_dev_lock(hdev);
  
@@@ -1534,10 -1535,10 +1534,10 @@@ static int unpair_device(struct sock *s
        if (cp->disconnect) {
                if (cp->addr.type == BDADDR_BREDR)
                        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
 -                                                      &cp->addr.bdaddr);
 +                                                     &cp->addr.bdaddr);
                else
                        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
 -                                                      &cp->addr.bdaddr);
 +                                                     &cp->addr.bdaddr);
        } else {
                conn = NULL;
        }
@@@ -1593,8 -1594,7 +1593,8 @@@ static int disconnect(struct sock *sk, 
        }
  
        if (cp->addr.type == BDADDR_BREDR)
 -              conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
 +              conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
 +                                             &cp->addr.bdaddr);
        else
                conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
  
@@@ -1813,7 -1813,7 +1813,7 @@@ static int set_io_capability(struct soc
        hdev->io_capability = cp->io_capability;
  
        BT_DBG("%s IO capability set to 0x%02x", hdev->name,
 -                                                      hdev->io_capability);
 +             hdev->io_capability);
  
        hci_dev_unlock(hdev);
  
                            0);
  }
  
 -static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
 +static struct pending_cmd *find_pairing(struct hci_conn *conn)
  {
        struct hci_dev *hdev = conn->hdev;
        struct pending_cmd *cmd;
@@@ -1873,6 -1873,22 +1873,22 @@@ static void pairing_complete_cb(struct 
                pairing_complete(cmd, mgmt_status(status));
  }
  
+ static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
+ {
+       struct pending_cmd *cmd;
+       BT_DBG("status %u", status);
+       if (!status)
+               return;
+       cmd = find_pairing(conn);
+       if (!cmd)
+               BT_DBG("Unable to find a pending command");
+       else
+               pairing_complete(cmd, mgmt_status(status));
+ }
  static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                       u16 len)
  {
        rp.addr.type = cp->addr.type;
  
        if (IS_ERR(conn)) {
 +              int status;
 +
 +              if (PTR_ERR(conn) == -EBUSY)
 +                      status = MGMT_STATUS_BUSY;
 +              else
 +                      status = MGMT_STATUS_CONNECT_FAILED;
 +
                err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
 -                                 MGMT_STATUS_CONNECT_FAILED, &rp,
 +                                 status, &rp,
                                   sizeof(rp));
                goto unlock;
        }
        /* For LE, just connecting isn't a proof that the pairing finished */
        if (cp->addr.type == BDADDR_BREDR)
                conn->connect_cfm_cb = pairing_complete_cb;
+       else
+               conn->connect_cfm_cb = le_connect_complete_cb;
  
        conn->security_cfm_cb = pairing_complete_cb;
        conn->disconn_cfm_cb = pairing_complete_cb;
        cmd->user_data = conn;
  
        if (conn->state == BT_CONNECTED &&
 -                              hci_conn_security(conn, sec_level, auth_type))
 +          hci_conn_security(conn, sec_level, auth_type))
                pairing_complete(cmd, 0);
  
        err = 0;
@@@ -2245,7 -2256,7 +2263,7 @@@ unlock
  }
  
  static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 -                                              void *data, u16 len)
 +                                void *data, u16 len)
  {
        struct mgmt_cp_remove_remote_oob_data *cp = data;
        u8 status;
@@@ -2414,7 -2425,7 +2432,7 @@@ static int stop_discovery(struct sock *
  
        case DISCOVERY_RESOLVING:
                e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
 -                                                      NAME_PENDING);
 +                                                   NAME_PENDING);
                if (!e) {
                        mgmt_pending_remove(cmd);
                        err = cmd_complete(sk, hdev->id,
@@@ -2636,7 -2647,7 +2654,7 @@@ static int load_long_term_keys(struct s
                                        sizeof(struct mgmt_ltk_info);
        if (expected_len != len) {
                BT_ERR("load_keys: expected %u bytes, got %u bytes",
 -                                                      len, expected_len);
 +                     len, expected_len);
                return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
                                  EINVAL);
        }
@@@ -2761,7 -2772,7 +2779,7 @@@ int mgmt_control(struct sock *sk, struc
        }
  
        if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
 -                                      mgmt_handlers[opcode].func == NULL) {
 +          mgmt_handlers[opcode].func == NULL) {
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_UNKNOWN_COMMAND);
        }
  
        if ((hdev && opcode < MGMT_OP_READ_INFO) ||
 -                      (!hdev && opcode >= MGMT_OP_READ_INFO)) {
 +          (!hdev && opcode >= MGMT_OP_READ_INFO)) {
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_INVALID_INDEX);
                goto done;
        handler = &mgmt_handlers[opcode];
  
        if ((handler->var_len && len < handler->data_len) ||
 -                      (!handler->var_len && len != handler->data_len)) {
 +          (!handler->var_len && len != handler->data_len)) {
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_INVALID_PARAMS);
                goto done;
@@@ -2962,7 -2973,7 +2980,7 @@@ int mgmt_new_link_key(struct hci_dev *h
        bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
        ev.key.addr.type = BDADDR_BREDR;
        ev.key.type = key->type;
 -      memcpy(ev.key.val, key->val, 16);
 +      memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
        ev.key.pin_len = key->pin_len;
  
        return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
@@@ -3097,7 -3108,7 +3115,7 @@@ int mgmt_disconnect_failed(struct hci_d
        mgmt_pending_remove(cmd);
  
        mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
 -                                                                      hdev);
 +                           hdev);
        return err;
  }
  
@@@ -3187,7 -3198,7 +3205,7 @@@ int mgmt_user_confirm_request(struct hc
  }
  
  int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 -                                              u8 link_type, u8 addr_type)
 +                            u8 link_type, u8 addr_type)
  {
        struct mgmt_ev_user_passkey_request ev;
  
  }
  
  static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 -                                      u8 link_type, u8 addr_type, u8 status,
 -                                      u8 opcode)
 +                                    u8 link_type, u8 addr_type, u8 status,
 +                                    u8 opcode)
  {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
@@@ -3233,8 -3244,7 +3251,8 @@@ int mgmt_user_confirm_neg_reply_complet
                                         u8 link_type, u8 addr_type, u8 status)
  {
        return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
 -                                        status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
 +                                        status,
 +                                        MGMT_OP_USER_CONFIRM_NEG_REPLY);
  }
  
  int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@@ -3248,8 -3258,7 +3266,8 @@@ int mgmt_user_passkey_neg_reply_complet
                                         u8 link_type, u8 addr_type, u8 status)
  {
        return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
 -                                        status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
 +                                        status,
 +                                        MGMT_OP_USER_PASSKEY_NEG_REPLY);
  }
  
  int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
diff --combined net/bluetooth/smp.c
index ff4835b61de9dfc300a04ad574da0f5ef72419eb,37df4e9b3896435164adf36a0c52b8ab8c08030c..16ef0dc85a0a87580c311563028cc567fa826bce
     SOFTWARE IS DISCLAIMED.
  */
  
 +#include <linux/crypto.h>
 +#include <linux/scatterlist.h>
 +#include <crypto/b128ops.h>
 +
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  #include <net/bluetooth/l2cap.h>
  #include <net/bluetooth/mgmt.h>
  #include <net/bluetooth/smp.h>
 -#include <linux/crypto.h>
 -#include <linux/scatterlist.h>
 -#include <crypto/b128ops.h>
  
  #define SMP_TIMEOUT   msecs_to_jiffies(30000)
  
@@@ -649,7 -648,7 +649,7 @@@ static u8 smp_cmd_pairing_rsp(struct l2
  
        auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
  
-       ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability);
+       ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
        if (ret)
                return SMP_UNSPECIFIED;
  
@@@ -704,7 -703,7 +704,7 @@@ static u8 smp_cmd_pairing_random(struc
        return 0;
  }
  
- static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
+ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
  {
        struct smp_ltk *key;
        struct hci_conn *hcon = conn->hcon;
        if (!key)
                return 0;
  
+       if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
+               return 0;
        if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
                return 1;
  
@@@ -733,7 -735,7 +736,7 @@@ static u8 smp_cmd_security_req(struct l
  
        hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
  
-       if (smp_ltk_encrypt(conn))
+       if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
                return 0;
  
        if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
@@@ -772,7 -774,7 +775,7 @@@ int smp_conn_security(struct l2cap_con
                return 1;
  
        if (hcon->link_mode & HCI_LM_MASTER)
-               if (smp_ltk_encrypt(conn))
+               if (smp_ltk_encrypt(conn, sec_level))
                        goto done;
  
        if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
diff --combined net/mac80211/cfg.c
index 498c94e344274cde556be0af87bb1df68a1cbfb1,7d5108a867ad9ec5341fc5122a2b65cd792846c3..85ac364f4636010128d997ad58fe93fea50e58a4
@@@ -674,48 -674,6 +674,48 @@@ static int ieee80211_get_station(struc
        return ret;
  }
  
 +static int ieee80211_set_channel(struct wiphy *wiphy,
 +                               struct net_device *netdev,
 +                               struct ieee80211_channel *chan,
 +                               enum nl80211_channel_type channel_type)
 +{
 +      struct ieee80211_local *local = wiphy_priv(wiphy);
 +      struct ieee80211_sub_if_data *sdata = NULL;
 +
 +      if (netdev)
 +              sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
 +
 +      switch (ieee80211_get_channel_mode(local, NULL)) {
 +      case CHAN_MODE_HOPPING:
 +              return -EBUSY;
 +      case CHAN_MODE_FIXED:
 +              if (local->oper_channel != chan)
 +                      return -EBUSY;
 +              if (!sdata && local->_oper_channel_type == channel_type)
 +                      return 0;
 +              break;
 +      case CHAN_MODE_UNDEFINED:
 +              break;
 +      }
 +
 +      if (!ieee80211_set_channel_type(local, sdata, channel_type))
 +              return -EBUSY;
 +
 +      local->oper_channel = chan;
 +
 +      /* auto-detects changes */
 +      ieee80211_hw_config(local, 0);
 +
 +      return 0;
 +}
 +
 +static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
 +                                       struct ieee80211_channel *chan,
 +                                       enum nl80211_channel_type channel_type)
 +{
 +      return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
 +}
 +
  static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
                                    const u8 *resp, size_t resp_len)
  {
@@@ -830,11 -788,6 +830,11 @@@ static int ieee80211_start_ap(struct wi
        if (old)
                return -EALREADY;
  
 +      err = ieee80211_set_channel(wiphy, dev, params->channel,
 +                                  params->channel_type);
 +      if (err)
 +              return err;
 +
        /*
         * Apply control port protocol, this allows us to
         * not encrypt dynamic WEP control frames.
@@@ -1605,12 -1558,6 +1605,12 @@@ static int ieee80211_join_mesh(struct w
        err = copy_mesh_setup(ifmsh, setup);
        if (err)
                return err;
 +
 +      err = ieee80211_set_channel(wiphy, dev, setup->channel,
 +                                  setup->channel_type);
 +      if (err)
 +              return err;
 +
        ieee80211_start_mesh(sdata);
  
        return 0;
@@@ -1730,6 -1677,55 +1730,6 @@@ static int ieee80211_set_txq_params(str
        return 0;
  }
  
 -static int ieee80211_set_channel(struct wiphy *wiphy,
 -                               struct net_device *netdev,
 -                               struct ieee80211_channel *chan,
 -                               enum nl80211_channel_type channel_type)
 -{
 -      struct ieee80211_local *local = wiphy_priv(wiphy);
 -      struct ieee80211_sub_if_data *sdata = NULL;
 -      struct ieee80211_channel *old_oper;
 -      enum nl80211_channel_type old_oper_type;
 -      enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
 -
 -      if (netdev)
 -              sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
 -
 -      switch (ieee80211_get_channel_mode(local, NULL)) {
 -      case CHAN_MODE_HOPPING:
 -              return -EBUSY;
 -      case CHAN_MODE_FIXED:
 -              if (local->oper_channel != chan)
 -                      return -EBUSY;
 -              if (!sdata && local->_oper_channel_type == channel_type)
 -                      return 0;
 -              break;
 -      case CHAN_MODE_UNDEFINED:
 -              break;
 -      }
 -
 -      if (sdata)
 -              old_vif_oper_type = sdata->vif.bss_conf.channel_type;
 -      old_oper_type = local->_oper_channel_type;
 -
 -      if (!ieee80211_set_channel_type(local, sdata, channel_type))
 -              return -EBUSY;
 -
 -      old_oper = local->oper_channel;
 -      local->oper_channel = chan;
 -
 -      /* Update driver if changes were actually made. */
 -      if ((old_oper != local->oper_channel) ||
 -          (old_oper_type != local->_oper_channel_type))
 -              ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 -
 -      if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
 -          old_vif_oper_type != sdata->vif.bss_conf.channel_type)
 -              ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 -
 -      return 0;
 -}
 -
  #ifdef CONFIG_PM
  static int ieee80211_suspend(struct wiphy *wiphy,
                             struct cfg80211_wowlan *wowlan)
@@@ -2097,6 -2093,9 +2097,9 @@@ static int ieee80211_set_bitrate_mask(s
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        int i, ret;
  
+       if (!ieee80211_sdata_running(sdata))
+               return -ENETDOWN;
        if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
                ret = drv_set_bitrate_mask(local, sdata, mask);
                if (ret)
        return 0;
  }
  
 -static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
 -                                        struct net_device *dev,
 -                                        struct ieee80211_channel *chan,
 -                                        enum nl80211_channel_type chantype,
 -                                        unsigned int duration, u64 *cookie)
 +static int ieee80211_start_roc_work(struct ieee80211_local *local,
 +                                  struct ieee80211_sub_if_data *sdata,
 +                                  struct ieee80211_channel *channel,
 +                                  enum nl80211_channel_type channel_type,
 +                                  unsigned int duration, u64 *cookie,
 +                                  struct sk_buff *txskb)
  {
 +      struct ieee80211_roc_work *roc, *tmp;
 +      bool queued = false;
        int ret;
 -      u32 random_cookie;
  
        lockdep_assert_held(&local->mtx);
  
 -      if (local->hw_roc_cookie)
 -              return -EBUSY;
 -      /* must be nonzero */
 -      random_cookie = random32() | 1;
 -
 -      *cookie = random_cookie;
 -      local->hw_roc_dev = dev;
 -      local->hw_roc_cookie = random_cookie;
 -      local->hw_roc_channel = chan;
 -      local->hw_roc_channel_type = chantype;
 -      local->hw_roc_duration = duration;
 -      ret = drv_remain_on_channel(local, chan, chantype, duration);
 +      roc = kzalloc(sizeof(*roc), GFP_KERNEL);
 +      if (!roc)
 +              return -ENOMEM;
 +
 +      roc->chan = channel;
 +      roc->chan_type = channel_type;
 +      roc->duration = duration;
 +      roc->req_duration = duration;
 +      roc->frame = txskb;
 +      roc->mgmt_tx_cookie = (unsigned long)txskb;
 +      roc->sdata = sdata;
 +      INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
 +      INIT_LIST_HEAD(&roc->dependents);
 +
 +      /* if there's one pending or we're scanning, queue this one */
 +      if (!list_empty(&local->roc_list) || local->scanning)
 +              goto out_check_combine;
 +
 +      /* if not HW assist, just queue & schedule work */
 +      if (!local->ops->remain_on_channel) {
 +              ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
 +              goto out_queue;
 +      }
 +
 +      /* otherwise actually kick it off here (for error handling) */
 +
 +      /*
 +       * If the duration is zero, then the driver
 +       * wouldn't actually do anything. Set it to
 +       * 10 for now.
 +       *
 +       * TODO: cancel the off-channel operation
 +       *       when we get the SKB's TX status and
 +       *       the wait time was zero before.
 +       */
 +      if (!duration)
 +              duration = 10;
 +
 +      ret = drv_remain_on_channel(local, channel, channel_type, duration);
        if (ret) {
 -              local->hw_roc_channel = NULL;
 -              local->hw_roc_cookie = 0;
 +              kfree(roc);
 +              return ret;
        }
  
 -      return ret;
 +      roc->started = true;
 +      goto out_queue;
 +
 + out_check_combine:
 +      list_for_each_entry(tmp, &local->roc_list, list) {
 +              if (tmp->chan != channel || tmp->chan_type != channel_type)
 +                      continue;
 +
 +              /*
 +               * Extend this ROC if possible:
 +               *
 +               * If it hasn't started yet, just increase the duration
 +               * and add the new one to the list of dependents.
 +               */
 +              if (!tmp->started) {
 +                      list_add_tail(&roc->list, &tmp->dependents);
 +                      tmp->duration = max(tmp->duration, roc->duration);
 +                      queued = true;
 +                      break;
 +              }
 +
 +              /* If it has already started, it's more difficult ... */
 +              if (local->ops->remain_on_channel) {
 +                      unsigned long j = jiffies;
 +
 +                      /*
 +                       * In the offloaded ROC case, if it hasn't begun, add
 +                       * this new one to the dependent list to be handled
 +                       * when the the master one begins. If it has begun,
 +                       * check that there's still a minimum time left and
 +                       * if so, start this one, transmitting the frame, but
 +                       * add it to the list directly after this one with a
 +                       * a reduced time so we'll ask the driver to execute
 +                       * it right after finishing the previous one, in the
 +                       * hope that it'll also be executed right afterwards,
 +                       * effectively extending the old one.
 +                       * If there's no minimum time left, just add it to the
 +                       * normal list.
 +                       */
 +                      if (!tmp->hw_begun) {
 +                              list_add_tail(&roc->list, &tmp->dependents);
 +                              queued = true;
 +                              break;
 +                      }
 +
 +                      if (time_before(j + IEEE80211_ROC_MIN_LEFT,
 +                                      tmp->hw_start_time +
 +                                      msecs_to_jiffies(tmp->duration))) {
 +                              int new_dur;
 +
 +                              ieee80211_handle_roc_started(roc);
 +
 +                              new_dur = roc->duration -
 +                                        jiffies_to_msecs(tmp->hw_start_time +
 +                                                         msecs_to_jiffies(
 +                                                              tmp->duration) -
 +                                                         j);
 +
 +                              if (new_dur > 0) {
 +                                      /* add right after tmp */
 +                                      list_add(&roc->list, &tmp->list);
 +                              } else {
 +                                      list_add_tail(&roc->list,
 +                                                    &tmp->dependents);
 +                              }
 +                              queued = true;
 +                      }
 +              } else if (del_timer_sync(&tmp->work.timer)) {
 +                      unsigned long new_end;
 +
 +                      /*
 +                       * In the software ROC case, cancel the timer, if
 +                       * that fails then the finish work is already
 +                       * queued/pending and thus we queue the new ROC
 +                       * normally, if that succeeds then we can extend
 +                       * the timer duration and TX the frame (if any.)
 +                       */
 +
 +                      list_add_tail(&roc->list, &tmp->dependents);
 +                      queued = true;
 +
 +                      new_end = jiffies + msecs_to_jiffies(roc->duration);
 +
 +                      /* ok, it was started & we canceled timer */
 +                      if (time_after(new_end, tmp->work.timer.expires))
 +                              mod_timer(&tmp->work.timer, new_end);
 +                      else
 +                              add_timer(&tmp->work.timer);
 +
 +                      ieee80211_handle_roc_started(roc);
 +              }
 +              break;
 +      }
 +
 + out_queue:
 +      if (!queued)
 +              list_add_tail(&roc->list, &local->roc_list);
 +
 +      /*
 +       * cookie is either the roc (for normal roc)
 +       * or the SKB (for mgmt TX)
 +       */
 +      if (txskb)
 +              *cookie = (unsigned long)txskb;
 +      else
 +              *cookie = (unsigned long)roc;
 +
 +      return 0;
  }
  
  static int ieee80211_remain_on_channel(struct wiphy *wiphy,
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
 +      int ret;
  
 -      if (local->ops->remain_on_channel) {
 -              int ret;
 -
 -              mutex_lock(&local->mtx);
 -              ret = ieee80211_remain_on_channel_hw(local, dev,
 -                                                   chan, channel_type,
 -                                                   duration, cookie);
 -              local->hw_roc_for_tx = false;
 -              mutex_unlock(&local->mtx);
 -
 -              return ret;
 -      }
 +      mutex_lock(&local->mtx);
 +      ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
 +                                     duration, cookie, NULL);
 +      mutex_unlock(&local->mtx);
  
 -      return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
 -                                            duration, cookie);
 +      return ret;
  }
  
 -static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
 -                                               u64 cookie)
 +static int ieee80211_cancel_roc(struct ieee80211_local *local,
 +                              u64 cookie, bool mgmt_tx)
  {
 +      struct ieee80211_roc_work *roc, *tmp, *found = NULL;
        int ret;
  
 -      lockdep_assert_held(&local->mtx);
 +      mutex_lock(&local->mtx);
 +      list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
 +              if (!mgmt_tx && (unsigned long)roc != cookie)
 +                      continue;
 +              else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
 +                      continue;
 +
 +              found = roc;
 +              break;
 +      }
  
 -      if (local->hw_roc_cookie != cookie)
 +      if (!found) {
 +              mutex_unlock(&local->mtx);
                return -ENOENT;
 +      }
  
 -      ret = drv_cancel_remain_on_channel(local);
 -      if (ret)
 -              return ret;
 +      if (local->ops->remain_on_channel) {
 +              if (found->started) {
 +                      ret = drv_cancel_remain_on_channel(local);
 +                      if (WARN_ON_ONCE(ret)) {
 +                              mutex_unlock(&local->mtx);
 +                              return ret;
 +                      }
 +              }
  
 -      local->hw_roc_cookie = 0;
 -      local->hw_roc_channel = NULL;
 +              list_del(&found->list);
  
 -      ieee80211_recalc_idle(local);
 +              ieee80211_run_deferred_scan(local);
 +              ieee80211_start_next_roc(local);
 +              mutex_unlock(&local->mtx);
 +
 +              ieee80211_roc_notify_destroy(found);
 +      } else {
 +              /* work may be pending so use it all the time */
 +              found->abort = true;
 +              ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
 +
 +              mutex_unlock(&local->mtx);
 +
 +              /* work will clean up etc */
 +              flush_delayed_work(&found->work);
 +      }
  
        return 0;
  }
@@@ -2357,7 -2198,39 +2360,7 @@@ static int ieee80211_cancel_remain_on_c
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
  
 -      if (local->ops->cancel_remain_on_channel) {
 -              int ret;
 -
 -              mutex_lock(&local->mtx);
 -              ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
 -              mutex_unlock(&local->mtx);
 -
 -              return ret;
 -      }
 -
 -      return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 -}
 -
 -static enum work_done_result
 -ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
 -{
 -      /*
 -       * Use the data embedded in the work struct for reporting
 -       * here so if the driver mangled the SKB before dropping
 -       * it (which is the only way we really should get here)
 -       * then we don't report mangled data.
 -       *
 -       * If there was no wait time, then by the time we get here
 -       * the driver will likely not have reported the status yet,
 -       * so in that case userspace will have to deal with it.
 -       */
 -
 -      if (wk->offchan_tx.wait && !wk->offchan_tx.status)
 -              cfg80211_mgmt_tx_status(wk->sdata->dev,
 -                                      (unsigned long) wk->offchan_tx.frame,
 -                                      wk->data, wk->data_len, false, GFP_KERNEL);
 -
 -      return WORK_DONE_DESTROY;
 +      return ieee80211_cancel_roc(local, cookie, false);
  }
  
  static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct sta_info *sta;
 -      struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
 +      bool need_offchan = false;
        u32 flags;
 -      bool is_offchan = false;
 +      int ret;
  
        if (dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
                flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
                        IEEE80211_TX_CTL_REQ_TX_STATUS;
  
 -      /* Check that we are on the requested channel for transmission */
 -      if (chan != local->tmp_channel &&
 -          chan != local->oper_channel)
 -              is_offchan = true;
 -      if (channel_type_valid &&
 -          (channel_type != local->tmp_channel_type &&
 -           channel_type != local->_oper_channel_type))
 -              is_offchan = true;
 -
 -      if (chan == local->hw_roc_channel) {
 -              /* TODO: check channel type? */
 -              is_offchan = false;
 -              flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
 -      }
 -
        if (no_cck)
                flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
  
 -      if (is_offchan && !offchan)
 -              return -EBUSY;
 -
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_ADHOC:
 +              if (!sdata->vif.bss_conf.ibss_joined)
 +                      need_offchan = true;
 +              /* fall through */
 +#ifdef CONFIG_MAC80211_MESH
 +      case NL80211_IFTYPE_MESH_POINT:
 +              if (ieee80211_vif_is_mesh(&sdata->vif) &&
 +                  !sdata->u.mesh.mesh_id_len)
 +                      need_offchan = true;
 +              /* fall through */
 +#endif
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_P2P_GO:
 -      case NL80211_IFTYPE_MESH_POINT:
 +              if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 +                  !ieee80211_vif_is_mesh(&sdata->vif) &&
 +                  !rcu_access_pointer(sdata->bss->beacon))
 +                      need_offchan = true;
                if (!ieee80211_is_action(mgmt->frame_control) ||
                    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
                        break;
                break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
 +              if (!sdata->u.mgd.associated)
 +                      need_offchan = true;
                break;
        default:
                return -EOPNOTSUPP;
        }
  
 +      mutex_lock(&local->mtx);
 +
 +      /* Check if the operating channel is the requested channel */
 +      if (!need_offchan) {
 +              need_offchan = chan != local->oper_channel;
 +              if (channel_type_valid &&
 +                  channel_type != local->_oper_channel_type)
 +                      need_offchan = true;
 +      }
 +
 +      if (need_offchan && !offchan) {
 +              ret = -EBUSY;
 +              goto out_unlock;
 +      }
 +
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
 -      if (!skb)
 -              return -ENOMEM;
 +      if (!skb) {
 +              ret = -ENOMEM;
 +              goto out_unlock;
 +      }
        skb_reserve(skb, local->hw.extra_tx_headroom);
  
        memcpy(skb_put(skb, len), buf, len);
  
        IEEE80211_SKB_CB(skb)->flags = flags;
  
 -      if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
 -              IEEE80211_SKB_CB(skb)->hw_queue =
 -                      local->hw.offchannel_tx_hw_queue;
 -
        skb->dev = sdata->dev;
  
 -      *cookie = (unsigned long) skb;
 -
 -      if (is_offchan && local->ops->remain_on_channel) {
 -              unsigned int duration;
 -              int ret;
 -
 -              mutex_lock(&local->mtx);
 -              /*
 -               * If the duration is zero, then the driver
 -               * wouldn't actually do anything. Set it to
 -               * 100 for now.
 -               *
 -               * TODO: cancel the off-channel operation
 -               *       when we get the SKB's TX status and
 -               *       the wait time was zero before.
 -               */
 -              duration = 100;
 -              if (wait)
 -                      duration = wait;
 -              ret = ieee80211_remain_on_channel_hw(local, dev, chan,
 -                                                   channel_type,
 -                                                   duration, cookie);
 -              if (ret) {
 -                      kfree_skb(skb);
 -                      mutex_unlock(&local->mtx);
 -                      return ret;
 -              }
 -
 -              local->hw_roc_for_tx = true;
 -              local->hw_roc_duration = wait;
 -
 -              /*
 -               * queue up frame for transmission after
 -               * ieee80211_ready_on_channel call
 -               */
 +      if (!need_offchan) {
 +              ieee80211_tx_skb(sdata, skb);
 +              ret = 0;
 +              goto out_unlock;
 +      }
  
 -              /* modify cookie to prevent API mismatches */
 -              *cookie ^= 2;
 -              IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
 +      IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
 +      if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
                IEEE80211_SKB_CB(skb)->hw_queue =
                        local->hw.offchannel_tx_hw_queue;
 -              local->hw_roc_skb = skb;
 -              local->hw_roc_skb_for_status = skb;
 -              mutex_unlock(&local->mtx);
 -
 -              return 0;
 -      }
 -
 -      /*
 -       * Can transmit right away if the channel was the
 -       * right one and there's no wait involved... If a
 -       * wait is involved, we might otherwise not be on
 -       * the right channel for long enough!
 -       */
 -      if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
 -              ieee80211_tx_skb(sdata, skb);
 -              return 0;
 -      }
  
 -      wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
 -      if (!wk) {
 +      /* This will handle all kinds of coalescing and immediate TX */
 +      ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
 +                                     wait, cookie, skb);
 +      if (ret)
                kfree_skb(skb);
 -              return -ENOMEM;
 -      }
 -
 -      wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
 -      wk->chan = chan;
 -      wk->chan_type = channel_type;
 -      wk->sdata = sdata;
 -      wk->done = ieee80211_offchan_tx_done;
 -      wk->offchan_tx.frame = skb;
 -      wk->offchan_tx.wait = wait;
 -      wk->data_len = len;
 -      memcpy(wk->data, buf, len);
 -
 -      ieee80211_add_work(wk);
 -      return 0;
 + out_unlock:
 +      mutex_unlock(&local->mtx);
 +      return ret;
  }
  
  static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
 -      struct ieee80211_work *wk;
 -      int ret = -ENOENT;
 -
 -      mutex_lock(&local->mtx);
 -
 -      if (local->ops->cancel_remain_on_channel) {
 -              cookie ^= 2;
 -              ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
 -
 -              if (ret == 0) {
 -                      kfree_skb(local->hw_roc_skb);
 -                      local->hw_roc_skb = NULL;
 -                      local->hw_roc_skb_for_status = NULL;
 -              }
 -
 -              mutex_unlock(&local->mtx);
  
 -              return ret;
 -      }
 -
 -      list_for_each_entry(wk, &local->work_list, list) {
 -              if (wk->sdata != sdata)
 -                      continue;
 -
 -              if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
 -                      continue;
 -
 -              if (cookie != (unsigned long) wk->offchan_tx.frame)
 -                      continue;
 -
 -              wk->timeout = jiffies;
 -
 -              ieee80211_queue_work(&local->hw, &local->work_work);
 -              ret = 0;
 -              break;
 -      }
 -      mutex_unlock(&local->mtx);
 -
 -      return ret;
 +      return ieee80211_cancel_roc(local, cookie, true);
  }
  
  static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
@@@ -2722,7 -2680,7 +2725,7 @@@ static int ieee80211_tdls_mgmt(struct w
                return -EINVAL;
  
  #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
 -      printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
 +      pr_debug("TDLS mgmt action %d peer %pM\n", action_code, peer);
  #endif
  
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
@@@ -2833,7 -2791,7 +2836,7 @@@ static int ieee80211_tdls_oper(struct w
                return -EINVAL;
  
  #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
 -      printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
 +      pr_debug("TDLS oper %d peer %pM\n", oper, peer);
  #endif
  
        switch (oper) {
@@@ -2978,7 -2936,7 +2981,7 @@@ struct cfg80211_ops mac80211_config_op
  #endif
        .change_bss = ieee80211_change_bss,
        .set_txq_params = ieee80211_set_txq_params,
 -      .set_channel = ieee80211_set_channel,
 +      .set_monitor_channel = ieee80211_set_monitor_channel,
        .suspend = ieee80211_suspend,
        .resume = ieee80211_resume,
        .scan = ieee80211_scan,
diff --combined net/mac80211/mlme.c
index d7134c17033600fcb06219619c1209d1dce12ebc,66e4fcdd1c6b4a6a07a7d26f3a66bc7e43183807..079038d26a1433848853a5d8aca17d3e5a741145
@@@ -258,11 -258,12 +258,11 @@@ static int ieee80211_compatible_rates(c
  }
  
  static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
 -                              struct sk_buff *skb, const u8 *ht_oper_ie,
 +                              struct sk_buff *skb, u8 ap_ht_param,
                                struct ieee80211_supported_band *sband,
                                struct ieee80211_channel *channel,
                                enum ieee80211_smps_mode smps)
  {
 -      struct ieee80211_ht_operation *ht_oper;
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap;
  
        BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
  
 -      if (!ht_oper_ie)
 -              return;
 -
 -      if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
 -              return;
 -
        memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
        ieee80211_apply_htcap_overrides(sdata, &ht_cap);
  
 -      ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
 -
        /* determine capability flags */
        cap = ht_cap.cap;
  
 -      switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 +      switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
                        cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@@ -500,7 -509,7 +500,7 @@@ static void ieee80211_send_assoc(struc
        }
  
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 -              ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
 +              ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
                                    sband, local->oper_channel, ifmgd->ap_smps);
  
        /* if present, add any custom non-vendor IEs that go after HT */
@@@ -930,6 -939,11 +930,6 @@@ void ieee80211_recalc_ps(struct ieee802
                return;
        }
  
 -      if (!list_empty(&local->work_list)) {
 -              local->ps_sdata = NULL;
 -              goto change;
 -      }
 -
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
                local->ps_sdata = NULL;
        }
  
 - change:
        ieee80211_change_ps(local);
  }
  
@@@ -1337,6 -1352,8 +1337,8 @@@ static void ieee80211_set_disassoc(stru
        if (WARN_ON(!ifmgd->associated))
                return;
  
+       ieee80211_stop_poll(sdata);
        memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
  
        ifmgd->associated = NULL;
@@@ -1570,8 -1587,6 +1572,8 @@@ static void ieee80211_mgd_probe_ap(stru
                net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n",
                                    sdata->name);
  #endif
 +      ieee80211_cqm_rssi_notify(&sdata->vif,
 +              NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
  
        /*
         * The driver/our work has already reported this event or the
@@@ -1654,7 -1669,8 +1656,7 @@@ static void __ieee80211_connection_loss
  
        memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
  
 -      printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
 -             sdata->name, bssid);
 +      pr_debug("%s: Connection to AP %pM lost\n", sdata->name, bssid);
  
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
@@@ -1788,10 -1804,9 +1790,10 @@@ ieee80211_rx_mgmt_auth(struct ieee80211
                return RX_MGMT_NONE;
  
        if (status_code != WLAN_STATUS_SUCCESS) {
 -              printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
 -                     sdata->name, mgmt->sa, status_code);
 -              goto out;
 +              pr_debug("%s: %pM denied authentication (status %d)\n",
 +                       sdata->name, mgmt->sa, status_code);
 +              ieee80211_destroy_auth_data(sdata, false);
 +              return RX_MGMT_CFG80211_RX_AUTH;
        }
  
        switch (ifmgd->auth_data->algorithm) {
                return RX_MGMT_NONE;
        }
  
 -      printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
 - out:
 +      pr_debug("%s: authenticated\n", sdata->name);
        ifmgd->auth_data->done = true;
        ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
        run_again(ifmgd, ifmgd->auth_data->timeout);
                goto out_err;
        }
        if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
 -              printk(KERN_DEBUG "%s: failed moving %pM to auth\n",
 -                     sdata->name, bssid);
 +              pr_debug("%s: failed moving %pM to auth\n", sdata->name, bssid);
                goto out_err;
        }
        mutex_unlock(&sdata->local->sta_mtx);
@@@ -1859,8 -1876,8 +1861,8 @@@ ieee80211_rx_mgmt_deauth(struct ieee802
  
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
  
 -      printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
 -                      sdata->name, bssid, reason_code);
 +      pr_debug("%s: deauthenticated from %pM (Reason: %u)\n",
 +               sdata->name, bssid, reason_code);
  
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
  
@@@ -1890,8 -1907,8 +1892,8 @@@ ieee80211_rx_mgmt_disassoc(struct ieee8
  
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
  
 -      printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
 -                      sdata->name, mgmt->sa, reason_code);
 +      pr_debug("%s: disassociated from %pM (Reason: %u)\n",
 +               sdata->name, mgmt->sa, reason_code);
  
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
  
@@@ -1983,15 -2000,17 +1985,15 @@@ static bool ieee80211_assoc_success(str
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
  
        if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
 -              printk(KERN_DEBUG
 -                     "%s: invalid AID value 0x%x; bits 15:14 not set\n",
 -                     sdata->name, aid);
 +              pr_debug("%s: invalid AID value 0x%x; bits 15:14 not set\n",
 +                       sdata->name, aid);
        aid &= ~(BIT(15) | BIT(14));
  
        ifmgd->broken_ap = false;
  
        if (aid == 0 || aid > IEEE80211_MAX_AID) {
 -              printk(KERN_DEBUG
 -                     "%s: invalid AID value %d (out of range), turn off PS\n",
 -                     sdata->name, aid);
 +              pr_debug("%s: invalid AID value %d (out of range), turn off PS\n",
 +                       sdata->name, aid);
                aid = 0;
                ifmgd->broken_ap = true;
        }
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
  
        if (!elems.supp_rates) {
 -              printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
 -                     sdata->name);
 +              pr_debug("%s: no SuppRates element in AssocResp\n",
 +                       sdata->name);
                return false;
        }
  
        if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
                err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
        if (err) {
 -              printk(KERN_DEBUG
 -                     "%s: failed to move station %pM to desired state\n",
 -                     sdata->name, sta->sta.addr);
 +              pr_debug("%s: failed to move station %pM to desired state\n",
 +                       sdata->name, sta->sta.addr);
                WARN_ON(__sta_info_destroy(sta));
                mutex_unlock(&sdata->local->sta_mtx);
                return false;
@@@ -2125,9 -2145,10 +2127,9 @@@ ieee80211_rx_mgmt_assoc_resp(struct iee
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
        aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
  
 -      printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
 -             "status=%d aid=%d)\n",
 -             sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
 -             capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 +      pr_debug("%s: RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
 +               sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
 +               capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
  
        pos = mgmt->u.assoc_resp.variable;
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
                u32 tu, ms;
                tu = get_unaligned_le32(elems.timeout_int + 1);
                ms = tu * 1024 / 1000;
 -              printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
 -                     "comeback duration %u TU (%u ms)\n",
 -                     sdata->name, mgmt->sa, tu, ms);
 +              pr_debug("%s: %pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
 +                       sdata->name, mgmt->sa, tu, ms);
                assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
                        run_again(ifmgd, assoc_data->timeout);
        *bss = assoc_data->bss;
  
        if (status_code != WLAN_STATUS_SUCCESS) {
 -              printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
 -                     sdata->name, mgmt->sa, status_code);
 +              pr_debug("%s: %pM denied association (code=%d)\n",
 +                       sdata->name, mgmt->sa, status_code);
                ieee80211_destroy_assoc_data(sdata, false);
        } else {
 -              printk(KERN_DEBUG "%s: associated\n", sdata->name);
 +              pr_debug("%s: associated\n", sdata->name);
  
                if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
                        /* oops -- internal error -- send timeout for now */
@@@ -2261,7 -2283,7 +2263,7 @@@ static void ieee80211_rx_mgmt_probe_res
        if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
            ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
                /* got probe response, continue with auth */
 -              printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
 +              pr_debug("%s: direct probe responded\n", sdata->name);
                ifmgd->auth_data->tries = 0;
                ifmgd->auth_data->timeout = jiffies;
                run_again(ifmgd, ifmgd->auth_data->timeout);
@@@ -2592,8 -2614,6 +2594,6 @@@ static void ieee80211_sta_connection_lo
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[DEAUTH_DISASSOC_LEN];
  
-       ieee80211_stop_poll(sdata);
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
                               false, frame_buf);
        mutex_unlock(&ifmgd->mtx);
@@@ -2625,8 -2645,8 +2625,8 @@@ static int ieee80211_probe_auth(struct 
        auth_data->tries++;
  
        if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
 -              printk(KERN_DEBUG "%s: authentication with %pM timed out\n",
 -                     sdata->name, auth_data->bss->bssid);
 +              pr_debug("%s: authentication with %pM timed out\n",
 +                       sdata->name, auth_data->bss->bssid);
  
                /*
                 * Most likely AP is not in the range so remove the
        }
  
        if (auth_data->bss->proberesp_ies) {
 -              printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n",
 -                     sdata->name, auth_data->bss->bssid, auth_data->tries,
 -                     IEEE80211_AUTH_MAX_TRIES);
 +              pr_debug("%s: send auth to %pM (try %d/%d)\n",
 +                       sdata->name, auth_data->bss->bssid, auth_data->tries,
 +                       IEEE80211_AUTH_MAX_TRIES);
  
                auth_data->expected_transaction = 2;
                ieee80211_send_auth(sdata, 1, auth_data->algorithm,
        } else {
                const u8 *ssidie;
  
 -              printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
 -                     sdata->name, auth_data->bss->bssid, auth_data->tries,
 -                     IEEE80211_AUTH_MAX_TRIES);
 +              pr_debug("%s: direct probe to %pM (try %d/%i)\n",
 +                       sdata->name, auth_data->bss->bssid, auth_data->tries,
 +                       IEEE80211_AUTH_MAX_TRIES);
  
                ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
                if (!ssidie)
@@@ -2680,8 -2700,8 +2680,8 @@@ static int ieee80211_do_assoc(struct ie
  
        assoc_data->tries++;
        if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
 -              printk(KERN_DEBUG "%s: association with %pM timed out\n",
 -                     sdata->name, assoc_data->bss->bssid);
 +              pr_debug("%s: association with %pM timed out\n",
 +                       sdata->name, assoc_data->bss->bssid);
  
                /*
                 * Most likely AP is not in the range so remove the
                return -ETIMEDOUT;
        }
  
 -      printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n",
 -             sdata->name, assoc_data->bss->bssid, assoc_data->tries,
 -             IEEE80211_ASSOC_MAX_TRIES);
 +      pr_debug("%s: associate with %pM (try %d/%d)\n",
 +               sdata->name, assoc_data->bss->bssid, assoc_data->tries,
 +               IEEE80211_ASSOC_MAX_TRIES);
        ieee80211_send_assoc(sdata);
  
        assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@@ -3065,10 -3085,13 +3065,10 @@@ static int ieee80211_prep_connection(st
                         * since we look at probe response/beacon data here
                         * it should be OK.
                         */
 -                      printk(KERN_DEBUG
 -                             "%s: Wrong control channel: center-freq: %d"
 -                             " ht-cfreq: %d ht->primary_chan: %d"
 -                             " band: %d. Disabling HT.\n",
 -                             sdata->name, cbss->channel->center_freq,
 -                             ht_cfreq, ht_oper->primary_chan,
 -                             cbss->channel->band);
 +                      pr_debug("%s: Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
 +                               sdata->name, cbss->channel->center_freq,
 +                               ht_cfreq, ht_oper->primary_chan,
 +                               cbss->channel->band);
                        ht_oper = NULL;
                }
        }
        if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
                /* can only fail due to HT40+/- mismatch */
                channel_type = NL80211_CHAN_HT20;
 -              printk(KERN_DEBUG
 -                     "%s: disabling 40 MHz due to multi-vif mismatch\n",
 -                     sdata->name);
 +              pr_debug("%s: disabling 40 MHz due to multi-vif mismatch\n",
 +                       sdata->name);
                ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
                WARN_ON(!ieee80211_set_channel_type(local, sdata,
                                                    channel_type));
                 * we can connect -- with a warning.
                 */
                if (!basic_rates && min_rate_index >= 0) {
 -                      printk(KERN_DEBUG
 -                             "%s: No basic rates, using min rate instead.\n",
 -                             sdata->name);
 +                      pr_debug("%s: No basic rates, using min rate instead\n",
 +                               sdata->name);
                        basic_rates = BIT(min_rate_index);
                }
  
                err = sta_info_insert(sta);
                sta = NULL;
                if (err) {
 -                      printk(KERN_DEBUG
 -                             "%s: failed to insert STA entry for the AP (error %d)\n",
 -                             sdata->name, err);
 +                      pr_debug("%s: failed to insert STA entry for the AP (error %d)\n",
 +                               sdata->name, err);
                        return err;
                }
        } else
@@@ -3228,7 -3254,8 +3228,7 @@@ int ieee80211_mgd_auth(struct ieee80211
        if (ifmgd->associated)
                ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
  
 -      printk(KERN_DEBUG "%s: authenticate with %pM\n",
 -             sdata->name, req->bss->bssid);
 +      pr_debug("%s: authenticate with %pM\n", sdata->name, req->bss->bssid);
  
        err = ieee80211_prep_connection(sdata, req->bss, false);
        if (err)
@@@ -3263,7 -3290,7 +3263,7 @@@ int ieee80211_mgd_assoc(struct ieee8021
        struct ieee80211_bss *bss = (void *)req->bss->priv;
        struct ieee80211_mgd_assoc_data *assoc_data;
        struct ieee80211_supported_band *sband;
 -      const u8 *ssidie;
 +      const u8 *ssidie, *ht_ie;
        int i, err;
  
        ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
         * We can set this to true for non-11n hardware, that'll be checked
         * separately along with the peer capabilities.
         */
 -      for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
 +      for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
                if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
 -                  req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
 +                  req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
                        ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 +                      netdev_info(sdata->dev,
 +                                  "disabling HT due to WEP/TKIP use\n");
 +              }
 +      }
  
        if (req->flags & ASSOC_REQ_DISABLE_HT)
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
 -          local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
 +          local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 +              netdev_info(sdata->dev,
 +                          "disabling HT as WMM/QoS is not supported\n");
 +      }
  
        memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
        memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
                          (local->hw.queues >= IEEE80211_NUM_ACS);
        assoc_data->supp_rates = bss->supp_rates;
        assoc_data->supp_rates_len = bss->supp_rates_len;
 -      assoc_data->ht_operation_ie =
 -              ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
 +
 +      ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
 +      if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
 +              assoc_data->ap_ht_param =
 +                      ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
 +      else
 +              ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
  
        if (bss->wmm_used && bss->uapsd_supported &&
            (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
                 * Wait up to one beacon interval ...
                 * should this be more if we miss one?
                 */
 -              printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
 -                     sdata->name, ifmgd->bssid);
 +              pr_debug("%s: waiting for beacon from %pM\n",
 +                       sdata->name, ifmgd->bssid);
                assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
        } else {
                assoc_data->have_beacon = true;
                                corrupt_type = "beacon";
                } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
                        corrupt_type = "probe response";
 -              printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
 -                     sdata->name, corrupt_type);
 +              pr_debug("%s: associating with AP with corrupt %s\n",
 +                       sdata->name, corrupt_type);
        }
  
        err = 0;
@@@ -3460,8 -3475,9 +3460,8 @@@ int ieee80211_mgd_deauth(struct ieee802
                return 0;
        }
  
 -      printk(KERN_DEBUG
 -             "%s: deauthenticating from %pM by local choice (reason=%d)\n",
 -             sdata->name, req->bssid, req->reason_code);
 +      pr_debug("%s: deauthenticating from %pM by local choice (reason=%d)\n",
 +               sdata->name, req->bssid, req->reason_code);
  
        if (ifmgd->associated &&
            ether_addr_equal(ifmgd->associated->bssid, req->bssid))
@@@ -3503,8 -3519,8 +3503,8 @@@ int ieee80211_mgd_disassoc(struct ieee8
                return -ENOLINK;
        }
  
 -      printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
 -             sdata->name, req->bss->bssid, req->reason_code);
 +      pr_debug("%s: disassociating from %pM by local choice (reason=%d)\n",
 +               sdata->name, req->bss->bssid, req->reason_code);
  
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
@@@ -3545,3 -3561,10 +3545,3 @@@ void ieee80211_cqm_rssi_notify(struct i
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
  }
  EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
 -
 -unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif)
 -{
 -      struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 -      return sdata->dev->operstate;
 -}
 -EXPORT_SYMBOL(ieee80211_get_operstate);
This page took 0.350432 seconds and 4 git commands to generate.