Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 20 Jun 2012 18:40:26 +0000 (14:40 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 20 Jun 2012 18:40:26 +0000 (14:40 -0400)
77 files changed:
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/rndis_wlan.c
include/net/bluetooth/a2mp.h [new file with mode: 0644]
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/mac80211.h
net/bluetooth/Makefile
net/bluetooth/a2mp.c [new file with mode: 0644]
net/bluetooth/af_bluetooth.c
net/bluetooth/bnep/core.c
net/bluetooth/bnep/netdev.c
net/bluetooth/bnep/sock.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/hidp/sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/mac80211/cfg.c
net/mac80211/mlme.c
net/mac80211/sta_info.h
net/wireless/reg.c
net/wireless/util.c

index 1fcd92380356bb70571a573cb105778d06712237..585c88e018932fa9d9b6c46048be42678c535cec 100644 (file)
@@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
-               register unsigned int offset;
-               register unsigned char command;
-               register unsigned long ready_bit;
+               unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int offset;
+               unsigned char command;
+               unsigned long ready_bit;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index 609861a53c28445ef90670788e6a45b43c81949f..29caaed2d715bd6de4f8b355bc8bc11b9580a7b6 100644 (file)
@@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        hdev->flush    = bpa10x_flush;
        hdev->send     = bpa10x_send_frame;
 
-       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+       set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        err = hci_register_dev(hdev);
        if (err < 0) {
index 308c8599ab55ca480c364cab3b40bc6f41d94faf..b2b0fbbb43b5dd152878747b9befdf6fc27f5418 100644 (file)
@@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
                return;
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                if (!pcmcia_dev_present(info->p_dev))
                        break;
index a853244e7fd7b59b1689c0281a1d44534b1e708c..2867499f7256988c4a8587b0022ac77aed5ba25f 100644 (file)
@@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
        /* Marvell SD8787 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
                        .driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
+       /* Marvell SD8787 Bluetooth AMP device */
+       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
+                       .driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
        /* Marvell SD8797 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
                        .driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
index c4fc2f3fc32cad477afb98051100f4bc9d023b3f..65b8d996840c286ab69ac2434f699c6eff015b2e 100644 (file)
@@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index c9463af8e564e8707bab12374e5324b0739d5994..a45e717f5f842afa27b7706ae948a8eead43ba96 100644 (file)
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/skbuff.h>
-
 #include <linux/usb.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -1026,7 +1018,7 @@ static int btusb_probe(struct usb_interface *intf,
        data->isoc = usb_ifnum_to_if(data->udev, 1);
 
        if (!reset)
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
                if (!disable_scofix)
@@ -1038,7 +1030,7 @@ static int btusb_probe(struct usb_interface *intf,
 
        if (id->driver_info & BTUSB_DIGIANSWER) {
                data->cmdreq_type = USB_TYPE_VENDOR;
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
        }
 
        if (id->driver_info & BTUSB_CSR) {
@@ -1046,7 +1038,7 @@ static int btusb_probe(struct usb_interface *intf,
 
                /* Old firmware would otherwise execute USB reset */
                if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
-                       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+                       set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
        }
 
        if (id->driver_info & BTUSB_SNIFFER) {
index 6e8d9618968443df06710d52666aaf5e5c2af3bd..b1b37ccd3cd489ad41117e2293040df4784eed31 100644 (file)
@@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index 661a8dc4d2f8b346e390053ee45d63cb7249346e..57e502e0608058ca9943b7cf5c14613339562729 100644 (file)
@@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp)
 static int bcsp_recv(struct hci_uart *hu, void *data, int count)
 {
        struct bcsp_struct *bcsp = hu->priv;
-       register unsigned char *ptr;
+       unsigned char *ptr;
 
        BT_DBG("hu %p count %d rx_state %d rx_count %ld", 
                hu, count, bcsp->rx_state, bcsp->rx_count);
index 748329468d26ca6432f6e04dc2d2ab92afd62e4f..c60623f206d4d255b59a29ea4de209a014e28421 100644 (file)
@@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
 {
-       register int room = skb_tailroom(h4->rx_skb);
+       int room = skb_tailroom(h4->rx_skb);
 
        BT_DBG("len %d room %d", len, room);
 
index e564579a6115989cb7857ca298eaee4ab43ca2ec..2f9b796e106e501ab0c2cbf243c2d52977ec6d0f 100644 (file)
@@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
                set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
        if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
                hdev->dev_type = HCI_AMP;
index b874c0efde247be90f38d0a2772813ea56fd6afa..ff6d589c34a5e900eff0eb498782f5597a6a8bee 100644 (file)
@@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int ll_check_data_len(struct ll_struct *ll, int len)
 {
-       register int room = skb_tailroom(ll->rx_skb);
+       int room = skb_tailroom(ll->rx_skb);
 
        BT_DBG("len %d room %d", len, room);
 
@@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len)
 static int ll_recv(struct hci_uart *hu, void *data, int count)
 {
        struct ll_struct *ll = hu->priv;
-       register char *ptr;
+       char *ptr;
        struct hci_event_hdr *eh;
        struct hci_acl_hdr   *ah;
        struct hci_sco_hdr   *sh;
-       register int len, type, dlen;
+       int len, type, dlen;
 
        BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
 
index f27e9732951d1f48819c3e88510e0f01b782770c..fd7dbd4609df3c6da9595a7bf5239cd7932d57fd 100644 (file)
 
 #define DEFAULT_BG_SCAN_PERIOD 60
 
+struct ath6kl_cfg80211_match_probe_ssid {
+       struct cfg80211_ssid ssid;
+       u8 flag;
+};
+
 static struct ieee80211_rate ath6kl_rates[] = {
        RATETAB_ENT(10, 0x1, 0),
        RATETAB_ENT(20, 0x2, 0),
@@ -576,6 +581,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
        vif->nw_type = vif->next_mode;
 
+       /* enable enhanced bmiss detection if applicable */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
                nw_subtype = SUBTYPE_P2PCLIENT;
 
@@ -852,20 +860,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                }
        }
 
-       /*
-        * Send a disconnect command to target when a disconnect event is
-        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
-        * request from host) to make the firmware stop trying to connect even
-        * after giving disconnect event. There will be one more disconnect
-        * event for this disconnect command with reason code DISCONNECT_CMD
-        * which will be notified to cfg80211.
-        */
-
-       if (reason != DISCONNECT_CMD) {
-               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
-               return;
-       }
-
        clear_bit(CONNECT_PEND, &vif->flags);
 
        if (vif->sme_state == SME_CONNECTING) {
@@ -875,32 +869,96 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
                                        GFP_KERNEL);
        } else if (vif->sme_state == SME_CONNECTED) {
-               cfg80211_disconnected(vif->ndev, reason,
+               cfg80211_disconnected(vif->ndev, proto_reason,
                                      NULL, 0, GFP_KERNEL);
        }
 
        vif->sme_state = SME_DISCONNECTED;
+
+       /*
+        * Send a disconnect command to target when a disconnect event is
+        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
+        * request from host) to make the firmware stop trying to connect even
+        * after giving disconnect event. There will be one more disconnect
+        * event for this disconnect command with reason code DISCONNECT_CMD
+        * which won't be notified to cfg80211.
+        */
+       if (reason != DISCONNECT_CMD)
+               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
 }
 
 static int ath6kl_set_probed_ssids(struct ath6kl *ar,
                                   struct ath6kl_vif *vif,
-                                  struct cfg80211_ssid *ssids, int n_ssids)
+                                  struct cfg80211_ssid *ssids, int n_ssids,
+                                  struct cfg80211_match_set *match_set,
+                                  int n_match_ssid)
 {
-       u8 i;
+       u8 i, j, index_to_add, ssid_found = false;
+       struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
+
+       memset(ssid_list, 0, sizeof(ssid_list));
 
-       if (n_ssids > MAX_PROBED_SSID_INDEX)
+       if (n_ssids > MAX_PROBED_SSIDS ||
+           n_match_ssid > MAX_PROBED_SSIDS)
                return -EINVAL;
 
        for (i = 0; i < n_ssids; i++) {
+               memcpy(ssid_list[i].ssid.ssid,
+                      ssids[i].ssid,
+                      ssids[i].ssid_len);
+               ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
+
+               if (ssids[i].ssid_len)
+                       ssid_list[i].flag = SPECIFIC_SSID_FLAG;
+               else
+                       ssid_list[i].flag = ANY_SSID_FLAG;
+
+               if (n_match_ssid == 0)
+                       ssid_list[i].flag |= MATCH_SSID_FLAG;
+       }
+
+       index_to_add = i;
+
+       for (i = 0; i < n_match_ssid; i++) {
+               ssid_found = false;
+
+               for (j = 0; j < n_ssids; j++) {
+                       if ((match_set[i].ssid.ssid_len ==
+                            ssid_list[j].ssid.ssid_len) &&
+                           (!memcmp(ssid_list[j].ssid.ssid,
+                                    match_set[i].ssid.ssid,
+                                    match_set[i].ssid.ssid_len))) {
+                               ssid_list[j].flag |= MATCH_SSID_FLAG;
+                               ssid_found = true;
+                               break;
+                       }
+               }
+
+               if (ssid_found)
+                       continue;
+
+               if (index_to_add >= MAX_PROBED_SSIDS)
+                       continue;
+
+               ssid_list[index_to_add].ssid.ssid_len =
+                       match_set[i].ssid.ssid_len;
+               memcpy(ssid_list[index_to_add].ssid.ssid,
+                      match_set[i].ssid.ssid,
+                      match_set[i].ssid.ssid_len);
+               ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
+               index_to_add++;
+       }
+
+       for (i = 0; i < index_to_add; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
-                                         ssids[i].ssid_len ?
-                                         SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
-                                         ssids[i].ssid_len,
-                                         ssids[i].ssid);
+                                         ssid_list[i].flag,
+                                         ssid_list[i].ssid.ssid_len,
+                                         ssid_list[i].ssid.ssid);
+
        }
 
        /* Make sure no old entries are left behind */
-       for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
+       for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
                                          DISABLE_SSID_FLAG, 0, NULL);
        }
@@ -934,7 +992,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids, NULL, 0);
        if (ret < 0)
                return ret;
 
@@ -943,7 +1001,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_err("failed to set Probe Request appie for scan");
+               ath6kl_err("failed to set Probe Request appie for scan\n");
                return ret;
        }
 
@@ -1512,6 +1570,9 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
                }
        }
 
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+
 set_iface_type:
        switch (type) {
        case NL80211_IFTYPE_STATION:
@@ -2074,7 +2135,9 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
                return -EINVAL;
 
-       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                                vif->fw_vif_idx, false);
                if (ret)
@@ -2209,7 +2272,9 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
 
        ar->state = ATH6KL_STATE_ON;
 
-       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                        vif->fw_vif_idx, true);
                if (ret)
@@ -2475,7 +2540,7 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
 static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
                            bool ht_enable)
 {
-       struct ath6kl_htcap *htcap = &vif->htcap;
+       struct ath6kl_htcap *htcap = &vif->htcap[band];
 
        if (htcap->ht_enable == ht_enable)
                return 0;
@@ -2585,6 +2650,30 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
        return 0;
 }
 
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
+{
+       int err;
+
+       if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+               return;
+
+       if (vif->nw_type != INFRA_NETWORK)
+               return;
+
+       if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+                     vif->ar->fw_capabilities))
+               return;
+
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+                  enable ? "enable" : "disable");
+
+       err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+                                              vif->fw_vif_idx, enable);
+       if (err)
+               ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+                          enable ? "enable" : "disable", err);
+}
+
 static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
                                u8 *rsn_capab)
 {
@@ -2665,9 +2754,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        /* TODO:
         * info->interval
-        * info->dtim_period
         */
 
+       ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
+                                        info->dtim_period);
+
+       /* ignore error, just print a warning and continue normally */
+       if (ret)
+               ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
+
        if (info->beacon.head == NULL)
                return -EINVAL;
        mgmt = (struct ieee80211_mgmt *) info->beacon.head;
@@ -3131,10 +3226,24 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        ath6kl_cfg80211_scan_complete_event(vif, true);
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids,
+                                     request->match_sets,
+                                     request->n_match_sets);
        if (ret < 0)
                return ret;
 
+       if (!request->n_match_sets) {
+               ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                              ALL_BSS_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       } else {
+                ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                               MATCHED_SSID_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* fw uses seconds, also make sure that it's >0 */
        interval = max_t(u16, 1, request->interval / 1000);
 
@@ -3156,7 +3265,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
+               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
                            ret);
                return ret;
        }
@@ -3188,6 +3297,18 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
        return 0;
 }
 
+static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      const u8 *addr,
+                                      const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+
+       return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
+                                          mask);
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
@@ -3253,6 +3374,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .mgmt_frame_register = ath6kl_mgmt_frame_register,
        .sched_scan_start = ath6kl_cfg80211_sscan_start,
        .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
+       .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@@ -3380,7 +3502,8 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
        vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
        vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
        vif->bg_scan_period = 0;
-       vif->htcap.ht_enable = true;
+       vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true;
+       vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
 
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
        if (fw_vif_idx != 0)
@@ -3440,7 +3563,13 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        }
 
        /* max num of ssids that can be probed during scanning */
-       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
+
+       /* max num of ssids that can be matched after scan */
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+                    ar->fw_capabilities))
+               wiphy->max_match_sets = MAX_PROBED_SSIDS;
+
        wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
        switch (ar->hw.cap) {
        case WMI_11AN_CAP:
@@ -3477,6 +3606,17 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                ath6kl_band_5ghz.ht_cap.cap = 0;
                ath6kl_band_5ghz.ht_cap.ht_supported = false;
        }
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+       } else {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+       }
+
        if (band_2gig)
                wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
        if (band_5gig)
@@ -3497,7 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        wiphy->wowlan.pattern_min_len = 1;
        wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
 
-       wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
 
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME |
index 5ea8cbb79f43ac8dae52ab3f3f0a9b4aaa0104ee..b992046a1b0e83f4f37fc149dea2bbcee82b2f7d 100644 (file)
@@ -62,5 +62,7 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
 
 struct ath6kl *ath6kl_cfg80211_create(void);
 void ath6kl_cfg80211_destroy(struct ath6kl *ar);
+/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
 
 #endif /* ATH6KL_CFG80211_H */
index 8443b2a4133e007bb039ca103dc6c7baafe2867c..d38a31de344ca4eaecde32642fc8c8bf0f41c2d3 100644 (file)
@@ -100,6 +100,21 @@ enum ath6kl_fw_capability {
        /* Firmware has support to override rsn cap of rsn ie */
        ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
 
+       /*
+        * Multicast support in WOW and host awake mode.
+        * Allow all multicast in host awake mode.
+        * Apply multicast filter in WOW mode.
+        */
+       ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+
+       /* Firmware supports enhanced bmiss detection */
+       ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+
+       /*
+        * FW supports matching of ssid in schedule scan
+        */
+       ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+
        /* this needs to be last */
        ATH6KL_FW_CAPABILITY_MAX,
 };
@@ -112,6 +127,10 @@ struct ath6kl_fw_ie {
        u8 data[0];
 };
 
+enum ath6kl_hw_flags {
+       ATH6KL_HW_FLAG_64BIT_RATES      = BIT(0),
+};
+
 #define ATH6KL_FW_API2_FILE "fw-2.bin"
 #define ATH6KL_FW_API3_FILE "fw-3.bin"
 
@@ -196,7 +215,7 @@ struct ath6kl_fw_ie {
 
 #define AGGR_NUM_OF_FREE_NETBUFS    16
 
-#define AGGR_RX_TIMEOUT     400        /* in ms */
+#define AGGR_RX_TIMEOUT     100        /* in ms */
 
 #define WMI_TIMEOUT (2 * HZ)
 
@@ -245,7 +264,6 @@ struct skb_hold_q {
 
 struct rxtid {
        bool aggr;
-       bool progress;
        bool timer_mon;
        u16 win_sz;
        u16 seq_next;
@@ -254,9 +272,15 @@ struct rxtid {
        struct sk_buff_head q;
 
        /*
-        * FIXME: No clue what this should protect. Apparently it should
-        * protect some of the fields above but they are also accessed
-        * without taking the lock.
+        * lock mainly protects seq_next and hold_q. Movement of seq_next
+        * needs to be protected between aggr_timeout() and
+        * aggr_process_recv_frm(). hold_q will be holding the pending
+        * reorder frames and it's access should also be protected.
+        * Some of the other fields like hold_q_sz, win_sz and aggr are
+        * initialized/reset when receiving addba/delba req, also while
+        * deleting aggr state all the pending buffers are flushed before
+        * resetting these fields, so there should not be any race in accessing
+        * these fields.
         */
        spinlock_t lock;
 };
@@ -541,7 +565,7 @@ struct ath6kl_vif {
        struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
        struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
        struct aggr_info *aggr_cntxt;
-       struct ath6kl_htcap htcap;
+       struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS];
 
        struct timer_list disconnect_timer;
        struct timer_list sched_scan_timer;
@@ -684,6 +708,8 @@ struct ath6kl {
                u32 testscript_addr;
                enum wmi_phy_cap cap;
 
+               u32 flags;
+
                struct ath6kl_hw_fw {
                        const char *dir;
                        const char *otp;
index 2798624d3a9d28f9d3873cdbc8a52fa9bff68f44..cd0e1ba410d6ac3050fa5bb3fd35f99451492238 100644 (file)
@@ -1309,7 +1309,7 @@ static int ath6kl_htc_rx_packet(struct htc_target *target,
        }
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-                  "htc rx 0x%p hdr x%x len %d mbox 0x%x\n",
+                  "htc rx 0x%p hdr 0x%x len %d mbox 0x%x\n",
                   packet, packet->info.rx.exp_hdr,
                   padded_len, dev->ar->mbox_info.htc_addr);
 
index 7eb0515f458ab64528c16240358d5353b1f199c1..f90b5db741cf74c6784a9dc0a6a100d2b7a59f08 100644 (file)
@@ -42,6 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
                .reserved_ram_size              = 6912,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
+               .flags                          = 0,
 
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
@@ -67,6 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
                .testscript_addr                = 0x57ef74,
+               .flags                          = 0,
 
                .fw = {
                        .dir            = AR6003_HW_2_1_1_FW_DIR,
@@ -91,6 +93,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x433900,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_0_FW_DIR,
@@ -110,6 +113,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x43d400,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_1_FW_DIR,
@@ -129,6 +133,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x435c00,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_2_FW_DIR,
@@ -938,6 +943,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                }
 
                switch (ie_id) {
+               case ATH6KL_FW_IE_FW_VERSION:
+                       strlcpy(ar->wiphy->fw_version, data,
+                               sizeof(ar->wiphy->fw_version));
+
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found fw version %s\n",
+                                   ar->wiphy->fw_version);
+                       break;
                case ATH6KL_FW_IE_OTP_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
                                   ie_len);
@@ -991,9 +1004,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
-                       if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
-                               break;
-
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
                                   "found firmware capabilities ie (%zd B)\n",
                                   ie_len);
@@ -1002,6 +1012,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                index = i / 8;
                                bit = i % 8;
 
+                               if (index == ie_len)
+                                       break;
+
                                if (data[index] & (1 << bit))
                                        __set_bit(i, ar->fw_capabilities);
                        }
@@ -1392,6 +1405,12 @@ static int ath6kl_init_upload(struct ath6kl *ar)
            ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
+               param = 0x28;
+               address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS;
+               status = ath6kl_bmi_reg_write(ar, address, param);
+               if (status)
+                       return status;
+
                param = 0x20;
 
                address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
@@ -1659,6 +1678,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
                cfg80211_scan_done(vif->scan_req, true);
                vif->scan_req = NULL;
        }
+
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
 }
 
 void ath6kl_stop_txrx(struct ath6kl *ar)
index b836f27951145f5d562247bdcef4af1159b5e112..c189e28e86a9bbfaebb7f81a32291801d51fa1f7 100644 (file)
@@ -554,20 +554,24 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
        struct ath6kl *ar = devt;
 
        memcpy(ar->mac_addr, datap, ETH_ALEN);
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
-                  __func__, ar->mac_addr);
+
+       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                  "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n",
+                  ar->mac_addr, sw_ver, abi_ver, cap);
 
        ar->version.wlan_ver = sw_ver;
        ar->version.abi_ver = abi_ver;
        ar->hw.cap = cap;
 
-       snprintf(ar->wiphy->fw_version,
-                sizeof(ar->wiphy->fw_version),
-                "%u.%u.%u.%u",
-                (ar->version.wlan_ver & 0xf0000000) >> 28,
-                (ar->version.wlan_ver & 0x0f000000) >> 24,
-                (ar->version.wlan_ver & 0x00ff0000) >> 16,
-                (ar->version.wlan_ver & 0x0000ffff));
+       if (strlen(ar->wiphy->fw_version) == 0) {
+               snprintf(ar->wiphy->fw_version,
+                        sizeof(ar->wiphy->fw_version),
+                        "%u.%u.%u.%u",
+                        (ar->version.wlan_ver & 0xf0000000) >> 28,
+                        (ar->version.wlan_ver & 0x0f000000) >> 24,
+                        (ar->version.wlan_ver & 0x00ff0000) >> 16,
+                        (ar->version.wlan_ver & 0x0000ffff));
+       }
 
        /* indicate to the waiting thread that the ready event was received */
        set_bit(WMI_READY, &ar->flag);
@@ -1166,7 +1170,10 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
        else
                clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
 
-       mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    vif->ar->fw_capabilities)) {
+               mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       }
 
        if (!(ndev->flags & IFF_MULTICAST)) {
                mc_all_on = false;
index 78e0ef4567a5287d4755f2812d7e41b97e1e6ccf..a98c12ba70c1dfa32aa0d3fbd25a76852d5df22b 100644 (file)
@@ -45,6 +45,7 @@
 #define LPO_CAL_ENABLE_S               20
 #define LPO_CAL_ENABLE                 0x00100000
 
+#define GPIO_PIN9_ADDRESS              0x0000004c
 #define GPIO_PIN10_ADDRESS             0x00000050
 #define GPIO_PIN11_ADDRESS             0x00000054
 #define GPIO_PIN12_ADDRESS             0x00000058
index 67206aedea6cabada2a933a870e81065181c749e..7dfa0fd86d7b111ea06cbd1c85d673ba65717cb6 100644 (file)
@@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        rxtid = &agg_conn->rx_tid[tid];
        stats = &agg_conn->stat[tid];
 
+       spin_lock_bh(&rxtid->lock);
        idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
 
        /*
@@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        seq_end = seq_no ? seq_no : rxtid->seq_next;
        idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
 
-       spin_lock_bh(&rxtid->lock);
-
        do {
                node = &rxtid->hold_q[idx];
                if ((order == 1) && (!node->skb))
@@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
                    ((end > extended_end) && (cur > extended_end) &&
                     (cur < end))) {
                        aggr_deque_frms(agg_conn, tid, 0, 0);
+                       spin_lock_bh(&rxtid->lock);
                        if (cur >= rxtid->hold_q_sz - 1)
                                rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
                        else
                                rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
                                                  (rxtid->hold_q_sz - 2 - cur);
+                       spin_unlock_bh(&rxtid->lock);
                } else {
                        /*
                         * Dequeue only those frames that are outside the
@@ -1185,25 +1186,25 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
        aggr_deque_frms(agg_conn, tid, 0, 1);
 
        if (agg_conn->timer_scheduled)
-               rxtid->progress = true;
-       else
-               for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
-                       if (rxtid->hold_q[idx].skb) {
-                               /*
-                                * There is a frame in the queue and no
-                                * timer so start a timer to ensure that
-                                * the frame doesn't remain stuck
-                                * forever.
-                                */
-                               agg_conn->timer_scheduled = true;
-                               mod_timer(&agg_conn->timer,
-                                         (jiffies +
-                                          HZ * (AGGR_RX_TIMEOUT) / 1000));
-                               rxtid->progress = false;
-                               rxtid->timer_mon = true;
-                               break;
-                       }
+               return is_queued;
+
+       spin_lock_bh(&rxtid->lock);
+       for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+               if (rxtid->hold_q[idx].skb) {
+                       /*
+                        * There is a frame in the queue and no
+                        * timer so start a timer to ensure that
+                        * the frame doesn't remain stuck
+                        * forever.
+                        */
+                       agg_conn->timer_scheduled = true;
+                       mod_timer(&agg_conn->timer,
+                                 (jiffies + (HZ * AGGR_RX_TIMEOUT) / 1000));
+                       rxtid->timer_mon = true;
+                       break;
                }
+       }
+       spin_unlock_bh(&rxtid->lock);
 
        return is_queued;
 }
@@ -1608,7 +1609,7 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
                stats = &aggr_conn->stat[i];
 
-               if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+               if (!rxtid->aggr || !rxtid->timer_mon)
                        continue;
 
                stats->num_timeouts++;
@@ -1626,14 +1627,15 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
 
                if (rxtid->aggr && rxtid->hold_q) {
+                       spin_lock_bh(&rxtid->lock);
                        for (j = 0; j < rxtid->hold_q_sz; j++) {
                                if (rxtid->hold_q[j].skb) {
                                        aggr_conn->timer_scheduled = true;
                                        rxtid->timer_mon = true;
-                                       rxtid->progress = false;
                                        break;
                                }
                        }
+                       spin_unlock_bh(&rxtid->lock);
 
                        if (j >= rxtid->hold_q_sz)
                                rxtid->timer_mon = false;
@@ -1660,7 +1662,6 @@ static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid)
                aggr_deque_frms(aggr_conn, tid, 0, 0);
 
        rxtid->aggr = false;
-       rxtid->progress = false;
        rxtid->timer_mon = false;
        rxtid->win_sz = 0;
        rxtid->seq_next = 0;
@@ -1739,7 +1740,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
        for (i = 0; i < NUM_OF_TIDS; i++) {
                rxtid = &aggr_conn->rx_tid[i];
                rxtid->aggr = false;
-               rxtid->progress = false;
                rxtid->timer_mon = false;
                skb_queue_head_init(&rxtid->q);
                spin_lock_init(&rxtid->lock);
index ee8ec2394c2cc453962178d4cdf78dfa866cd689..a6caa673e8ad944fc41bb2c3b45e48c47bcfbd7f 100644 (file)
@@ -743,7 +743,6 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        memcpy(cmd->info.bssid, bssid, ETH_ALEN);
        cmd->roam_ctrl = WMI_FORCE_ROAM;
@@ -753,6 +752,22 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
+{
+       struct sk_buff *skb;
+       struct set_dtim_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct set_dtim_cmd *) skb->data;
+
+       cmd->dtim_period = cpu_to_le32(dtim_period);
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                  WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 {
        struct sk_buff *skb;
@@ -763,7 +778,6 @@ int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        cmd->info.roam_mode = mode;
        cmd->roam_ctrl = WMI_SET_ROAM_MODE;
@@ -1995,7 +2009,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
        struct wmi_probed_ssid_cmd *cmd;
        int ret;
 
-       if (index > MAX_PROBED_SSID_INDEX)
+       if (index >= MAX_PROBED_SSIDS)
                return -EINVAL;
 
        if (ssid_len > sizeof(cmd->ssid))
@@ -2599,6 +2613,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
        spin_unlock_bh(&wmi->lock);
 }
 
+static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates64_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[1];
+               mcsrate <<= 8;
+               mcsrate |= mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 28;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates32_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 20;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 32 bit: 2.4:%x 5:%x\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = wmi->parent_dev;
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
+               return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
+       else
+               return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
+}
+
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode)
 {
@@ -2997,6 +3120,25 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
+{
+       struct sk_buff *skb;
+       struct wmi_sta_bmiss_enhance_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
+       cmd->enable = enhance ? 1 : 0;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_STA_BMISS_ENHANCE_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
        if (rate_index == RATE_AUTO)
index 9076bec3a2ba29b430f42fc6607038420fcddbb0..43339aca585d96508cc9d2b7f87b4cf743cca3c9 100644 (file)
@@ -624,6 +624,10 @@ enum wmi_cmd_id {
        WMI_SEND_MGMT_CMDID,
        WMI_BEGIN_SCAN_CMDID,
 
+       WMI_SET_BLACK_LIST,
+       WMI_SET_MCASTRATE,
+
+       WMI_STA_BMISS_ENHANCE_CMDID,
 };
 
 enum wmi_mgmt_frame_type {
@@ -960,6 +964,9 @@ enum wmi_bss_filter {
        /* beacons matching probed ssid */
        PROBED_SSID_FILTER,
 
+       /* beacons matching matched ssid */
+       MATCHED_SSID_FILTER,
+
        /* marker only */
        LAST_BSS_FILTER,
 };
@@ -978,7 +985,7 @@ struct wmi_bss_filter_cmd {
 } __packed;
 
 /* WMI_SET_PROBED_SSID_CMDID */
-#define MAX_PROBED_SSID_INDEX   9
+#define MAX_PROBED_SSIDS   16
 
 enum wmi_ssid_flag {
        /* disables entry */
@@ -989,10 +996,13 @@ enum wmi_ssid_flag {
 
        /* probes for any ssid */
        ANY_SSID_FLAG = 0x02,
+
+       /* match for ssid */
+       MATCH_SSID_FLAG = 0x08,
 };
 
 struct wmi_probed_ssid_cmd {
-       /* 0 to MAX_PROBED_SSID_INDEX */
+       /* 0 to MAX_PROBED_SSIDS - 1 */
        u8 entry_index;
 
        /* see, enum wmi_ssid_flg */
@@ -1017,6 +1027,11 @@ struct wmi_bmiss_time_cmd {
        __le16 num_beacons;
 };
 
+/* WMI_STA_ENHANCE_BMISS_CMDID */
+struct wmi_sta_bmiss_enhance_cmd {
+       u8 enable;
+} __packed;
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
        REC_POWER = 0x01,
@@ -1048,6 +1063,36 @@ struct wmi_power_params_cmd {
        __le16 ps_fail_event_policy;
 } __packed;
 
+/*
+ * Ratemask for below modes should be passed
+ * to WMI_SET_TX_SELECT_RATES_CMDID.
+ * AR6003 has 32 bit mask for each modes.
+ * First 12 bits for legacy rates, 13 to 20
+ * bits for HT 20 rates and 21 to 28 bits for
+ * HT 40 rates
+ */
+enum wmi_mode_phy {
+       WMI_RATES_MODE_11A = 0,
+       WMI_RATES_MODE_11G,
+       WMI_RATES_MODE_11B,
+       WMI_RATES_MODE_11GONLY,
+       WMI_RATES_MODE_11A_HT20,
+       WMI_RATES_MODE_11G_HT20,
+       WMI_RATES_MODE_11A_HT40,
+       WMI_RATES_MODE_11G_HT40,
+       WMI_RATES_MODE_MAX
+};
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates32_cmd {
+       __le32 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates64_cmd {
+       __le64 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
 /* WMI_SET_DISC_TIMEOUT_CMDID */
 struct wmi_disc_timeout_cmd {
        /* seconds */
@@ -1572,6 +1617,10 @@ struct roam_ctrl_cmd {
        u8 roam_ctrl;
 } __packed;
 
+struct set_dtim_cmd {
+       __le32 dtim_period;
+} __packed;
+
 /* BSS INFO HDR version 2.0 */
 struct wmi_bss_info_hdr2 {
        __le16 ch; /* frequency in MHz */
@@ -2532,6 +2581,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
                          __be32 ips0, __be32 ips1);
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode);
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask);
 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
                                enum ath6kl_wow_mode wow_mode,
                                u32 filter, u16 host_req_delay);
@@ -2542,11 +2593,14 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   u16 list_id, u16 filter_id);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
                                        u8 *filter, bool add_filter);
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
+
 /* AP mode uAPSD */
 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
 
index d9e0824af0933ffc3d008eff856e504c508b5b2b..78816b8b2173cf8e238d56e1fcf981bf027ff009 100644 (file)
@@ -181,11 +181,14 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
        u32 mask2 = 0;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 sync_cause = 0, async_cause;
+       u32 sync_cause = 0, async_cause, async_mask = AR_INTR_MAC_IRQ;
+
+       if (ath9k_hw_mci_is_enabled(ah))
+               async_mask |= AR_INTR_ASYNC_MASK_MCI;
 
        async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
 
-       if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
+       if (async_cause & async_mask) {
                if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
                                == AR_RTC_STATUS_ON)
                        isr = REG_READ(ah, AR_ISR);
index b1ced2a76da33e462dafe789c812f2692a974d55..cc2853ade8f89cb7221f7b7a9f713d35bfdc6317 100644 (file)
@@ -321,7 +321,7 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE) &&
            (mci->bt_state != MCI_BT_SLEEP) &&
            !mci->halted_bt_gpm) {
                ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
@@ -484,7 +484,7 @@ static void ar9003_mci_sync_bt_state(struct ath_hw *ah)
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 cur_bt_state;
 
-       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
+       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP);
 
        if (mci->bt_state != cur_bt_state)
                mci->bt_state = cur_bt_state;
@@ -593,8 +593,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
                if (!time_out)
                        break;
 
-               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                         &more_data);
+               offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
 
                if (offset == MCI_GPM_INVALID)
                        continue;
@@ -658,8 +657,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
                time_out = 0;
 
        while (more_data == MCI_GPM_MORE) {
-               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                         &more_data);
+               offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
                if (offset == MCI_GPM_INVALID)
                        break;
 
@@ -893,13 +891,16 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                udelay(100);
        }
 
+       /* Check pending GPM msg before MCI Reset Rx */
+       ar9003_mci_check_gpm_offset(ah);
+
        regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
        REG_WRITE(ah, AR_MCI_COMMAND2, regval);
        udelay(1);
        regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
        REG_WRITE(ah, AR_MCI_COMMAND2, regval);
 
-       ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+       ar9003_mci_get_next_gpm_offset(ah, true, NULL);
 
        REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
                  (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
@@ -1010,38 +1011,32 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
        }
 }
 
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (!mci->update_2g5g)
+       if (!mci->update_2g5g && !force)
                return;
 
        if (mci->is_2g) {
                ar9003_mci_send_2g5g_status(ah, true);
-               ar9003_mci_send_lna_transfer(ah, true);
-               udelay(5);
 
-               REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+               REG_SET_BIT(ah, AR_MCI_TX_CTRL,
                            AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
                REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
                            AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
                if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
-                       REG_SET_BIT(ah, AR_BTCOEX_CTRL,
-                                   AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+                       ar9003_mci_osla_setup(ah, true);
        } else {
-               ar9003_mci_send_lna_take(ah, true);
-               udelay(5);
-
                REG_SET_BIT(ah, AR_MCI_TX_CTRL,
                            AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
                REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
                            AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-               REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
-                           AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
 
-               ar9003_mci_send_2g5g_status(ah, true);
+               ar9003_mci_osla_setup(ah, false);
+               if (!force)
+                       ar9003_mci_send_2g5g_status(ah, true);
        }
 }
 
@@ -1169,11 +1164,10 @@ void ar9003_mci_cleanup(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ar9003_mci_cleanup);
 
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 value = 0, more_gpm = 0, gpm_ptr;
+       u32 value = 0;
        u8 query_type;
 
        switch (state_type) {
@@ -1185,81 +1179,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                                value = 0;
                }
                value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
-               break;
-       case MCI_STATE_INIT_GPM_OFFSET:
-               value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-               mci->gpm_idx = value;
-               break;
-       case MCI_STATE_NEXT_GPM_OFFSET:
-       case MCI_STATE_LAST_GPM_OFFSET:
-               /*
-               * This could be useful to avoid new GPM message interrupt which
-               * may lead to spurious interrupt after power sleep, or multiple
-               * entry of ath_mci_intr().
-               * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
-               * alleviate this effect, but clearing GPM RX interrupt bit is
-               * safe, because whether this is called from hw or driver code
-               * there must be an interrupt bit set/triggered initially
-               */
-               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                         AR_MCI_INTERRUPT_RX_MSG_GPM);
-
-               gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-               value = gpm_ptr;
-
-               if (value == 0)
-                       value = mci->gpm_len - 1;
-               else if (value >= mci->gpm_len) {
-                       if (value != 0xFFFF)
-                               value = 0;
-               } else {
-                       value--;
-               }
-
-               if (value == 0xFFFF) {
-                       value = MCI_GPM_INVALID;
-                       more_gpm = MCI_GPM_NOMORE;
-               } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
-                       if (gpm_ptr == mci->gpm_idx) {
-                               value = MCI_GPM_INVALID;
-                               more_gpm = MCI_GPM_NOMORE;
-                       } else {
-                               for (;;) {
-                                       u32 temp_index;
-
-                                       /* skip reserved GPM if any */
-
-                                       if (value != mci->gpm_idx)
-                                               more_gpm = MCI_GPM_MORE;
-                                       else
-                                               more_gpm = MCI_GPM_NOMORE;
-
-                                       temp_index = mci->gpm_idx;
-                                       mci->gpm_idx++;
-
-                                       if (mci->gpm_idx >=
-                                           mci->gpm_len)
-                                               mci->gpm_idx = 0;
-
-                                       if (ar9003_mci_is_gpm_valid(ah,
-                                                                   temp_index)) {
-                                               value = temp_index;
-                                               break;
-                                       }
-
-                                       if (more_gpm == MCI_GPM_NOMORE) {
-                                               value = MCI_GPM_INVALID;
-                                               break;
-                                       }
-                               }
-                       }
-                       if (p_data)
-                               *p_data = more_gpm;
-               }
-
-               if (value != MCI_GPM_INVALID)
-                       value <<= 4;
-
                break;
        case MCI_STATE_LAST_SCHD_MSG_OFFSET:
                value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
@@ -1272,21 +1191,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                           AR_MCI_RX_REMOTE_SLEEP) ?
                        MCI_BT_SLEEP : MCI_BT_AWAKE;
                break;
-       case MCI_STATE_CONT_RSSI_POWER:
-               value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
-               break;
-       case MCI_STATE_CONT_PRIORITY:
-               value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
-               break;
-       case MCI_STATE_CONT_TXRX:
-               value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
-               break;
-       case MCI_STATE_BT:
-               value = mci->bt_state;
-               break;
-       case MCI_STATE_SET_BT_SLEEP:
-               mci->bt_state = MCI_BT_SLEEP;
-               break;
        case MCI_STATE_SET_BT_AWAKE:
                mci->bt_state = MCI_BT_AWAKE;
                ar9003_mci_send_coex_version_query(ah, true);
@@ -1295,7 +1199,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                if (mci->unhalt_bt_gpm)
                        ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
 
-               ar9003_mci_2g5g_switch(ah, true);
+               ar9003_mci_2g5g_switch(ah, false);
                break;
        case MCI_STATE_SET_BT_CAL_START:
                mci->bt_state = MCI_BT_CAL_START;
@@ -1319,34 +1223,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
        case MCI_STATE_SEND_WLAN_COEX_VERSION:
                ar9003_mci_send_coex_version_response(ah, true);
                break;
-       case MCI_STATE_SET_BT_COEX_VERSION:
-               if (!p_data)
-                       ath_dbg(common, MCI,
-                               "MCI Set BT Coex version with NULL data!!\n");
-               else {
-                       mci->bt_ver_major = (*p_data >> 8) & 0xff;
-                       mci->bt_ver_minor = (*p_data) & 0xff;
-                       mci->bt_version_known = true;
-                       ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
-                               mci->bt_ver_major, mci->bt_ver_minor);
-               }
-               break;
-       case MCI_STATE_SEND_WLAN_CHANNELS:
-               if (p_data) {
-                       if (((mci->wlan_channels[1] & 0xffff0000) ==
-                            (*(p_data + 1) & 0xffff0000)) &&
-                           (mci->wlan_channels[2] == *(p_data + 2)) &&
-                           (mci->wlan_channels[3] == *(p_data + 3)))
-                               break;
-
-                       mci->wlan_channels[0] = *p_data++;
-                       mci->wlan_channels[1] = *p_data++;
-                       mci->wlan_channels[2] = *p_data++;
-                       mci->wlan_channels[3] = *p_data++;
-               }
-               mci->wlan_channels_update = true;
-               ar9003_mci_send_coex_wlan_channels(ah, true);
-               break;
        case MCI_STATE_SEND_VERSION_QUERY:
                ar9003_mci_send_coex_version_query(ah, true);
                break;
@@ -1354,29 +1230,12 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
                ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
                break;
-       case MCI_STATE_NEED_FLUSH_BT_INFO:
-               /*
-                * btcoex_hw.mci.unhalt_bt_gpm means whether it's
-                * needed to send UNHALT message. It's set whenever
-                * there's a request to send HALT message.
-                * mci_halted_bt_gpm means whether HALT message is sent
-                * out successfully.
-                *
-                * Checking (mci_unhalt_bt_gpm == false) instead of
-                * checking (ah->mci_halted_bt_gpm == false) will make
-                * sure currently is in UNHALT-ed mode and BT can
-                * respond to status query.
-                */
-               value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
-               if (p_data)
-                       mci->need_flush_btinfo = (*p_data != 0) ? true : false;
-               break;
        case MCI_STATE_RECOVER_RX:
                ar9003_mci_prep_interface(ah);
                mci->query_bt = true;
                mci->need_flush_btinfo = true;
                ar9003_mci_send_coex_wlan_channels(ah, true);
-               ar9003_mci_2g5g_switch(ah, true);
+               ar9003_mci_2g5g_switch(ah, false);
                break;
        case MCI_STATE_NEED_FTP_STOMP:
                value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
@@ -1404,3 +1263,154 @@ void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
        /* Force another 2g5g update at next scanning */
        mci->update_2g5g = true;
 }
+
+void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+       u32 btcoex_ctrl2, diag_sw;
+       int i;
+       u8 lna_ctrl, bt_sleep;
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
+               if (btcoex_ctrl2 != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               diag_sw = REG_READ(ah, AR_DIAG_SW);
+               if (diag_sw != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
+       lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
+       bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
+
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
+       REG_WRITE(ah, AR_DIAG_SW, diag_sw);
+
+       if (bt_sleep && (lna_ctrl == 2)) {
+               REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
+               REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
+               udelay(50);
+       }
+}
+
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 offset;
+
+       /*
+        * This should only be called before "MAC Warm Reset" or "MCI Reset Rx".
+        */
+       offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+       if (mci->gpm_idx == offset)
+               return;
+       ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n",
+               mci->gpm_idx, offset);
+       mci->query_bt = true;
+       mci->need_flush_btinfo = true;
+       mci->gpm_idx = 0;
+}
+
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 offset, more_gpm = 0, gpm_ptr;
+
+       if (first) {
+               gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+               mci->gpm_idx = gpm_ptr;
+               return gpm_ptr;
+       }
+
+       /*
+        * This could be useful to avoid new GPM message interrupt which
+        * may lead to spurious interrupt after power sleep, or multiple
+        * entry of ath_mci_intr().
+        * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
+        * alleviate this effect, but clearing GPM RX interrupt bit is
+        * safe, because whether this is called from hw or driver code
+        * there must be an interrupt bit set/triggered initially
+        */
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                       AR_MCI_INTERRUPT_RX_MSG_GPM);
+
+       gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+       offset = gpm_ptr;
+
+       if (!offset)
+               offset = mci->gpm_len - 1;
+       else if (offset >= mci->gpm_len) {
+               if (offset != 0xFFFF)
+                       offset = 0;
+       } else {
+               offset--;
+       }
+
+       if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) {
+               offset = MCI_GPM_INVALID;
+               more_gpm = MCI_GPM_NOMORE;
+               goto out;
+       }
+       for (;;) {
+               u32 temp_index;
+
+               /* skip reserved GPM if any */
+
+               if (offset != mci->gpm_idx)
+                       more_gpm = MCI_GPM_MORE;
+               else
+                       more_gpm = MCI_GPM_NOMORE;
+
+               temp_index = mci->gpm_idx;
+               mci->gpm_idx++;
+
+               if (mci->gpm_idx >= mci->gpm_len)
+                       mci->gpm_idx = 0;
+
+               if (ar9003_mci_is_gpm_valid(ah, temp_index)) {
+                       offset = temp_index;
+                       break;
+               }
+
+               if (more_gpm == MCI_GPM_NOMORE) {
+                       offset = MCI_GPM_INVALID;
+                       break;
+               }
+       }
+
+       if (offset != MCI_GPM_INVALID)
+               offset <<= 4;
+out:
+       if (more)
+               *more = more_gpm;
+
+       return offset;
+}
+EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset);
+
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       mci->bt_ver_major = major;
+       mci->bt_ver_minor = minor;
+       mci->bt_version_known = true;
+       ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n",
+               mci->bt_ver_major, mci->bt_ver_minor);
+}
+EXPORT_SYMBOL(ar9003_mci_set_bt_version);
+
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       mci->wlan_channels_update = true;
+       ar9003_mci_send_coex_wlan_channels(ah, true);
+}
+EXPORT_SYMBOL(ar9003_mci_send_wlan_channels);
index 10282e2bcdc936ae8bd65690c62a67c18a4f27ab..d33b8e1288554dd502dc290d68c8c45684d2e1a8 100644 (file)
@@ -189,26 +189,15 @@ enum mci_bt_state {
 /* Type of state query */
 enum mci_state_type {
        MCI_STATE_ENABLE,
-       MCI_STATE_INIT_GPM_OFFSET,
-       MCI_STATE_NEXT_GPM_OFFSET,
-       MCI_STATE_LAST_GPM_OFFSET,
-       MCI_STATE_BT,
-       MCI_STATE_SET_BT_SLEEP,
        MCI_STATE_SET_BT_AWAKE,
        MCI_STATE_SET_BT_CAL_START,
        MCI_STATE_SET_BT_CAL,
        MCI_STATE_LAST_SCHD_MSG_OFFSET,
        MCI_STATE_REMOTE_SLEEP,
-       MCI_STATE_CONT_RSSI_POWER,
-       MCI_STATE_CONT_PRIORITY,
-       MCI_STATE_CONT_TXRX,
        MCI_STATE_RESET_REQ_WAKE,
        MCI_STATE_SEND_WLAN_COEX_VERSION,
-       MCI_STATE_SET_BT_COEX_VERSION,
-       MCI_STATE_SEND_WLAN_CHANNELS,
        MCI_STATE_SEND_VERSION_QUERY,
        MCI_STATE_SEND_STATUS_QUERY,
-       MCI_STATE_NEED_FLUSH_BT_INFO,
        MCI_STATE_SET_CONCUR_TX_PRI,
        MCI_STATE_RECOVER_RX,
        MCI_STATE_NEED_FTP_STOMP,
@@ -259,14 +248,15 @@ enum mci_gpm_coex_opcode {
 bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
                             u32 *payload, u8 len, bool wait_done,
                             bool check_bt);
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type);
 void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
                      u16 len, u32 sched_addr);
 void ar9003_mci_cleanup(struct ath_hw *ah);
 void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
                              u32 *rx_msg_intr);
-void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
-
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more);
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor);
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah);
 /*
  * These functions are used by ath9k_hw.
  */
@@ -277,7 +267,7 @@ void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
 void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
 void ar9003_mci_init_cal_done(struct ath_hw *ah);
 void ar9003_mci_set_full_sleep(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force);
 void ar9003_mci_check_bt(struct ath_hw *ah);
 bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
 int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
@@ -285,6 +275,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                      bool is_full_sleep);
 void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
+void ar9003_mci_set_power_awake(struct ath_hw *ah);
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah);
 
 #else
 
@@ -322,6 +315,15 @@ static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
 }
+static inline void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif
index 4a93e1534c1de1309b2fd19e572714b9c8dd3593..8f406ff2c95e929555190bb55e7ab5b50b63caf9 100644 (file)
@@ -52,7 +52,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
        {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
index 02fc1c1e5eeb05c2d99bca67ea16f45f91e32165..a8c050085648f1ad9bcd2c39c87ad95654f5fd37 100644 (file)
@@ -698,6 +698,7 @@ struct ath_softc {
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
        struct ath_mci_coex mci_coex;
+       struct work_struct mci_work;
 #endif
 
        struct ath_descdma txsdma;
index af6d27350291a7ed1c770c001acbf8823107f408..26032cb59b8ab7655c4fcdef2aece650e6bc9dc6 100644 (file)
@@ -202,7 +202,7 @@ static void ath_btcoex_period_timer(unsigned long data)
 
        btcoex->bt_wait_time += btcoex->btcoex_period;
        if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
-               if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP, NULL) &&
+               if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
                    (mci->num_pan || mci->num_other_acl))
                        ah->btcoex_hw.mci.stomp_ftp =
                                (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
@@ -232,7 +232,7 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
-       timer_period = btcoex->btcoex_period / 1000;
+       timer_period = btcoex->btcoex_period;
        mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
 }
 
@@ -267,10 +267,10 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
 
-       btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
-       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+       btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
+       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
                btcoex->btcoex_period / 100;
-       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
                                   btcoex->btcoex_period / 100;
 
        setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
index 45e670087e1c901fc62c0fac7ccc5b9459af0f93..784baee5db8456f506059a37769483b369b95e78 100644 (file)
@@ -1348,6 +1348,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                }
        }
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_check_gpm_offset(ah);
+
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
        REGWRITE_BUFFER_FLUSH(ah);
@@ -1708,7 +1711,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
        ath9k_hw_start_nfcal(ah, true);
 
        if (ath9k_hw_mci_is_enabled(ah))
-               ar9003_mci_2g5g_switch(ah, true);
+               ar9003_mci_2g5g_switch(ah, false);
 
        if (AR_SREV_9271(ah))
                ar9002_hw_load_ani_reg(ah, chan);
@@ -1912,7 +1915,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_set_dma(ah);
 
-       REG_WRITE(ah, AR_OBS, 8);
+       if (!ath9k_hw_mci_is_enabled(ah))
+               REG_WRITE(ah, AR_OBS, 8);
 
        if (ah->config.rx_intr_mitigation) {
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
@@ -2111,6 +2115,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
                    AR_RTC_FORCE_WAKE_EN);
        udelay(50);
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_set_power_awake(ah);
+
        for (i = POWER_UP_TIME / 50; i > 0; i--) {
                val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
                if (val == AR_RTC_STATUS_ON)
index 0cc4c70f7f0ca38220271baba696d13901bedcd9..a105c9426251f8a80d42bbdf273548476d186905 100644 (file)
@@ -136,6 +136,14 @@ void ath_hw_pll_work(struct work_struct *work)
        u32 pll_sqsum;
        struct ath_softc *sc = container_of(work, struct ath_softc,
                                            hw_pll_work.work);
+       /*
+        * 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 (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+               return;
 
        ath9k_ps_wakeup(sc);
        pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
index c0f478b0a9a271f29756f1f7ea89c4e7e8d8d7cd..52561b341d68798e55bbe8237e589da274b539b7 100644 (file)
@@ -150,6 +150,9 @@ static void __ath_cancel_work(struct ath_softc *sc)
        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)
@@ -1033,15 +1036,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                }
        }
 
-       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++;
@@ -1066,15 +1060,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
        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) {
@@ -1258,6 +1243,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                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;
                }
 
index 49137f477b05fe3f266a29c12f6306c101b519b8..7d34a504d6171b0370ede10581df1617c59ff5d0 100644 (file)
@@ -20,7 +20,7 @@
 #include "ath9k.h"
 #include "mci.h"
 
-static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+static const u8 ath_mci_duty_cycle[] = { 55, 50, 60, 70, 80, 85, 90, 95, 98 };
 
 static struct ath_mci_profile_info*
 ath_mci_find_profile(struct ath_mci_profile *mci,
@@ -28,11 +28,14 @@ ath_mci_find_profile(struct ath_mci_profile *mci,
 {
        struct ath_mci_profile_info *entry;
 
+       if (list_empty(&mci->info))
+               return NULL;
+
        list_for_each_entry(entry, &mci->info, list) {
                if (entry->conn_handle == info->conn_handle)
-                       break;
+                       return entry;
        }
-       return entry;
+       return NULL;
 }
 
 static bool ath_mci_add_profile(struct ath_common *common,
@@ -49,31 +52,21 @@ static bool ath_mci_add_profile(struct ath_common *common,
            (info->type != MCI_GPM_COEX_PROFILE_VOICE))
                return false;
 
-       entry = ath_mci_find_profile(mci, info);
-
-       if (entry) {
-               memcpy(entry, info, 10);
-       } else {
-               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-               if (!entry)
-                       return false;
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry)
+               return false;
 
-               memcpy(entry, info, 10);
-               INC_PROF(mci, info);
-               list_add_tail(&info->list, &mci->info);
-       }
+       memcpy(entry, info, 10);
+       INC_PROF(mci, info);
+       list_add_tail(&entry->list, &mci->info);
 
        return true;
 }
 
 static void ath_mci_del_profile(struct ath_common *common,
                                struct ath_mci_profile *mci,
-                               struct ath_mci_profile_info *info)
+                               struct ath_mci_profile_info *entry)
 {
-       struct ath_mci_profile_info *entry;
-
-       entry = ath_mci_find_profile(mci, info);
-
        if (!entry)
                return;
 
@@ -86,12 +79,16 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci)
 {
        struct ath_mci_profile_info *info, *tinfo;
 
+       mci->aggr_limit = 0;
+
+       if (list_empty(&mci->info))
+               return;
+
        list_for_each_entry_safe(info, tinfo, &mci->info, list) {
                list_del(&info->list);
                DEC_PROF(mci, info);
                kfree(info);
        }
-       mci->aggr_limit = 0;
 }
 
 static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
@@ -123,6 +120,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
        if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
                goto skip_tuning;
 
+       btcoex->duty_cycle = ath_mci_duty_cycle[num_profile];
+
        if (num_profile == 1) {
                info = list_first_entry(&mci->info,
                                        struct ath_mci_profile_info,
@@ -181,12 +180,11 @@ skip_tuning:
        if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
                return;
 
-       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_BDR_DUTY_CYCLE : 0);
        if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
                btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
 
-       btcoex->btcoex_period *= 1000;
-       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period * 1000 *
                (100 - btcoex->duty_cycle) / 100;
 
        ath9k_hw_btcoex_enable(sc->sc_ah);
@@ -197,20 +195,16 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
        switch (opcode) {
        case MCI_GPM_BT_CAL_REQ:
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
+               if (mci_hw->bt_state == MCI_BT_AWAKE) {
+                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-               } else {
-                       ath_dbg(common, MCI, "MCI State mismatch: %d\n",
-                               ar9003_mci_state(ah, MCI_STATE_BT, NULL));
                }
-               break;
-       case MCI_GPM_BT_CAL_DONE:
-               ar9003_mci_state(ah, MCI_STATE_BT, NULL);
+               ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
                break;
        case MCI_GPM_BT_CAL_GRANT:
                MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
@@ -223,32 +217,42 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        }
 }
 
+static void ath9k_mci_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc, mci_work);
+
+       ath_mci_update_scheme(sc);
+}
+
 static void ath_mci_process_profile(struct ath_softc *sc,
                                    struct ath_mci_profile_info *info)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info *entry = NULL;
+
+       entry = ath_mci_find_profile(mci, info);
+       if (entry)
+               memcpy(entry, info, 10);
 
        if (info->start) {
-               if (!ath_mci_add_profile(common, mci, info))
+               if (!entry && !ath_mci_add_profile(common, mci, info))
                        return;
        } else
-               ath_mci_del_profile(common, mci, info);
+               ath_mci_del_profile(common, mci, entry);
 
        btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
        mci->aggr_limit = mci->num_sco ? 6 : 0;
 
-       if (NUM_PROF(mci)) {
+       btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+       if (NUM_PROF(mci))
                btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-               btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
-       } else {
+       else
                btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
                                                        ATH_BTCOEX_STOMP_LOW;
-               btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
-       }
 
-       ath_mci_update_scheme(sc);
+       ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_process_status(struct ath_softc *sc,
@@ -263,8 +267,6 @@ static void ath_mci_process_status(struct ath_softc *sc,
        if (status->is_link)
                return;
 
-       memset(&info, 0, sizeof(struct ath_mci_profile_info));
-
        info.conn_handle = status->conn_handle;
        if (ath_mci_find_profile(mci, &info))
                return;
@@ -284,7 +286,7 @@ static void ath_mci_process_status(struct ath_softc *sc,
        } while (++i < ATH_MCI_MAX_PROFILE);
 
        if (old_num_mgmt != mci->num_mgmt)
-               ath_mci_update_scheme(sc);
+               ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
@@ -293,25 +295,20 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        struct ath_mci_profile_info profile_info;
        struct ath_mci_profile_status profile_status;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       u32 version;
-       u8 major;
-       u8 minor;
+       u8 major, minor;
        u32 seq_num;
 
        switch (opcode) {
        case MCI_GPM_COEX_VERSION_QUERY:
-               version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION,
-                                          NULL);
+               ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION);
                break;
        case MCI_GPM_COEX_VERSION_RESPONSE:
                major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
                minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
-               version = (major << 8) + minor;
-               version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION,
-                                          &version);
+               ar9003_mci_set_bt_version(ah, major, minor);
                break;
        case MCI_GPM_COEX_STATUS_QUERY:
-               ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+               ar9003_mci_send_wlan_channels(ah);
                break;
        case MCI_GPM_COEX_BT_PROFILE_INFO:
                memcpy(&profile_info,
@@ -378,6 +375,7 @@ int ath_mci_setup(struct ath_softc *sc)
                         mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
                         mci->sched_buf.bf_paddr);
 
+       INIT_WORK(&sc->mci_work, ath9k_mci_work);
        ath_dbg(common, MCI, "MCI Initialized\n");
 
        return 0;
@@ -405,6 +403,7 @@ void ath_mci_intr(struct ath_softc *sc)
        struct ath_mci_coex *mci = &sc->mci_coex;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 mci_int, mci_int_rxmsg;
        u32 offset, subtype, opcode;
        u32 *pgpm;
@@ -413,8 +412,8 @@ void ath_mci_intr(struct ath_softc *sc)
 
        ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
 
-       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
-               ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) {
+               ar9003_mci_get_next_gpm_offset(ah, true, NULL);
                return;
        }
 
@@ -433,46 +432,41 @@ void ath_mci_intr(struct ath_softc *sc)
                                        NULL, 0, true, false);
 
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
-               ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL);
+               ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE);
 
                /*
                 * always do this for recovery and 2G/5G toggling and LNA_TRANS
                 */
-               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
+               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
 
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-                           MCI_BT_SLEEP)
-                               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE,
-                                                NULL);
-               }
+               if ((mci_hw->bt_state == MCI_BT_SLEEP) &&
+                   (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+                    MCI_BT_SLEEP))
+                       ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
 
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-                           MCI_BT_AWAKE)
-                               ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
-                                                NULL);
-               }
+               if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+                   (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+                    MCI_BT_AWAKE))
+                       mci_hw->bt_state = MCI_BT_SLEEP;
        }
 
        if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
            (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
-               ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
+               ar9003_mci_state(ah, MCI_STATE_RECOVER_RX);
                skip_gpm = true;
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
-               offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
-                                         NULL);
+               offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
@@ -481,8 +475,8 @@ void ath_mci_intr(struct ath_softc *sc)
                while (more_data == MCI_GPM_MORE) {
 
                        pgpm = mci->gpm_buf.bf_addr;
-                       offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                                 &more_data);
+                       offset = ar9003_mci_get_next_gpm_offset(ah, false,
+                                                               &more_data);
 
                        if (offset == MCI_GPM_INVALID)
                                break;
@@ -523,23 +517,17 @@ void ath_mci_intr(struct ath_softc *sc)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
 
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
-                       int value_dbm = ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_RSSI_POWER, NULL);
+                       int value_dbm = MS(mci_hw->cont_status,
+                                          AR_MCI_CONT_RSSI_POWER);
 
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
 
-                       if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL))
-                               ath_dbg(common, MCI,
-                                       "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
-                                       ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_PRIORITY, NULL),
-                                       value_dbm);
-                       else
-                               ath_dbg(common, MCI,
-                                       "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n",
-                                       ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_PRIORITY, NULL),
-                                       value_dbm);
+                       ath_dbg(common, MCI,
+                               "MCI CONT_INFO: (%s) pri = %d pwr = %d dBm\n",
+                               MS(mci_hw->cont_status, AR_MCI_CONT_TXRX) ?
+                               "tx" : "rx",
+                               MS(mci_hw->cont_status, AR_MCI_CONT_PRIORITY),
+                               value_dbm);
                }
 
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
index 92a6c0a87f894167345a6c779e250de8388226ae..e034add9cd5a478a2dd085f5133a18898913b932 100644 (file)
@@ -770,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        struct ieee80211_tx_rate *rates = tx_info->control.rates;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
-       u8 try_per_rate, i = 0, rix, high_rix;
+       u8 try_per_rate, i = 0, rix;
        int is_probe = 0;
 
        if (rate_control_send_low(sta, priv_sta, txrc))
@@ -791,7 +791,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        rate_table = ath_rc_priv->rate_table;
        rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
                                     &is_probe, false);
-       high_rix = rix;
 
        /*
         * If we're in HT mode and both us and our peer supports LDPC.
@@ -839,16 +838,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        try_per_rate = 8;
 
        /*
-        * Use a legacy rate as last retry to ensure that the frame
-        * is tried in both MCS and legacy rates.
+        * If the last rate in the rate series is MCS and has
+        * more than 80% of per thresh, then use a legacy rate
+        * as last retry to ensure that the frame is tried in both
+        * MCS and legacy rate.
         */
-       if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
-           (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
-           (ath_rc_priv->per[high_rix] > 45)))
+       ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+       if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
+           (ath_rc_priv->per[rix] > 45))
                rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
                                &is_probe, true);
-       else
-               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
 
        /* All other rates in the series have RTS enabled */
        ath_rc_rate_set_series(rate_table, &rates[i], txrc,
index 560d6effac7a1473139fb3cc09633a17109f149f..75acefbd4937824f5e91a8a3c96cb357e5ddc294 100644 (file)
@@ -2098,8 +2098,8 @@ enum {
 #define AR_MCI_CONT_STATUS                     0x1848
 #define AR_MCI_CONT_RSSI_POWER                 0x000000FF
 #define AR_MCI_CONT_RSSI_POWER_S               0
-#define AR_MCI_CONT_RRIORITY                   0x0000FF00
-#define AR_MCI_CONT_RRIORITY_S                 8
+#define AR_MCI_CONT_PRIORITY                   0x0000FF00
+#define AR_MCI_CONT_PRIORITY_S                 8
 #define AR_MCI_CONT_TXRX                       0x00010000
 #define AR_MCI_CONT_TXRX_S                     16
 
index abb48032753b1d1b1a11ec1b1a67feb2a92c53f5..9d5170b6df50ec3f05902856684efab2149b09e8 100644 (file)
@@ -34,3 +34,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
                sdio_chip.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
                usb.o
+brcmfmac-$(CONFIG_BRCMDBG) += \
+               dhd_dbg.o
\ No newline at end of file
index 9f637014486e3d84b00a73cfd7fe5f8297761fd5..a11fe54f595091dbec82f57066a2be6bc29bf26c 100644 (file)
@@ -613,6 +613,9 @@ struct brcmf_pub {
        struct work_struct multicast_work;
        u8 macvalue[ETH_ALEN];
        atomic_t pend_8021x_cnt;
+#ifdef DEBUG
+       struct dentry *dbgfs_dir;
+#endif
 };
 
 struct brcmf_if_event {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
new file mode 100644 (file)
index 0000000..7f89540
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/debugfs.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/ieee80211.h>
+#include <linux/module.h>
+
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+
+static struct dentry *root_folder;
+
+void brcmf_debugfs_init(void)
+{
+       root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+       if (IS_ERR(root_folder))
+               root_folder = NULL;
+}
+
+void brcmf_debugfs_exit(void)
+{
+       if (!root_folder)
+               return;
+
+       debugfs_remove_recursive(root_folder);
+       root_folder = NULL;
+}
+
+int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+       if (!root_folder)
+               return -ENODEV;
+
+       drvr->dbgfs_dir = debugfs_create_dir(dev_name(drvr->dev), root_folder);
+       return PTR_RET(drvr->dbgfs_dir);
+}
+
+void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+       if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+               debugfs_remove_recursive(drvr->dbgfs_dir);
+}
+
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
+{
+       return drvr->dbgfs_dir;
+}
+
+static
+ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data,
+                                       size_t count, loff_t *ppos)
+{
+       struct brcmf_sdio_count *sdcnt = f->private_data;
+       char buf[750];
+       int res;
+
+       /* only allow read from start */
+       if (*ppos > 0)
+               return 0;
+
+       res = scnprintf(buf, sizeof(buf),
+                       "intrcount:    %u\nlastintrs:    %u\n"
+                       "pollcnt:      %u\nregfails:     %u\n"
+                       "tx_sderrs:    %u\nfcqueued:     %u\n"
+                       "rxrtx:        %u\nrx_toolong:   %u\n"
+                       "rxc_errors:   %u\nrx_hdrfail:   %u\n"
+                       "rx_badhdr:    %u\nrx_badseq:    %u\n"
+                       "fc_rcvd:      %u\nfc_xoff:      %u\n"
+                       "fc_xon:       %u\nrxglomfail:   %u\n"
+                       "rxglomframes: %u\nrxglompkts:   %u\n"
+                       "f2rxhdrs:     %u\nf2rxdata:     %u\n"
+                       "f2txdata:     %u\nf1regdata:    %u\n"
+                       "tickcnt:      %u\ntx_ctlerrs:   %lu\n"
+                       "tx_ctlpkts:   %lu\nrx_ctlerrs:   %lu\n"
+                       "rx_ctlpkts:   %lu\nrx_readahead: %lu\n",
+                       sdcnt->intrcount, sdcnt->lastintrs,
+                       sdcnt->pollcnt, sdcnt->regfails,
+                       sdcnt->tx_sderrs, sdcnt->fcqueued,
+                       sdcnt->rxrtx, sdcnt->rx_toolong,
+                       sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+                       sdcnt->rx_badhdr, sdcnt->rx_badseq,
+                       sdcnt->fc_rcvd, sdcnt->fc_xoff,
+                       sdcnt->fc_xon, sdcnt->rxglomfail,
+                       sdcnt->rxglomframes, sdcnt->rxglompkts,
+                       sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+                       sdcnt->f2txdata, sdcnt->f1regdata,
+                       sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+                       sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+                       sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+       return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_sdio_counter_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = brcmf_debugfs_sdio_counter_read
+};
+
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+                                    struct brcmf_sdio_count *sdcnt)
+{
+       struct dentry *dentry = drvr->dbgfs_dir;
+
+       if (!IS_ERR_OR_NULL(dentry))
+               debugfs_create_file("counters", S_IRUGO, dentry,
+                                   sdcnt, &brcmf_debugfs_sdio_counter_ops);
+}
index a2c4576cf9ff3fa50e303cf03d1c042a40b45f75..b784920532d31b3ae9deb1ca0453244efb010b39 100644 (file)
@@ -76,4 +76,63 @@ do {                                                                 \
 
 extern int brcmf_msg_level;
 
+/*
+ * hold counter variables used in brcmfmac sdio driver.
+ */
+struct brcmf_sdio_count {
+       uint intrcount;         /* Count of device interrupt callbacks */
+       uint lastintrs;         /* Count as of last watchdog timer */
+       uint pollcnt;           /* Count of active polls */
+       uint regfails;          /* Count of R_REG failures */
+       uint tx_sderrs;         /* Count of tx attempts with sd errors */
+       uint fcqueued;          /* Tx packets that got queued */
+       uint rxrtx;             /* Count of rtx requests (NAK to dongle) */
+       uint rx_toolong;        /* Receive frames too long to receive */
+       uint rxc_errors;        /* SDIO errors when reading control frames */
+       uint rx_hdrfail;        /* SDIO errors on header reads */
+       uint rx_badhdr;         /* Bad received headers (roosync?) */
+       uint rx_badseq;         /* Mismatched rx sequence number */
+       uint fc_rcvd;           /* Number of flow-control events received */
+       uint fc_xoff;           /* Number which turned on flow-control */
+       uint fc_xon;            /* Number which turned off flow-control */
+       uint rxglomfail;        /* Failed deglom attempts */
+       uint rxglomframes;      /* Number of glom frames (superframes) */
+       uint rxglompkts;        /* Number of packets from glom frames */
+       uint f2rxhdrs;          /* Number of header reads */
+       uint f2rxdata;          /* Number of frame data reads */
+       uint f2txdata;          /* Number of f2 frame writes */
+       uint f1regdata;         /* Number of f1 register accesses */
+       uint tickcnt;           /* Number of watchdog been schedule */
+       ulong tx_ctlerrs;       /* Err of sending ctrl frames */
+       ulong tx_ctlpkts;       /* Ctrl frames sent to dongle */
+       ulong rx_ctlerrs;       /* Err of processing rx ctrl frames */
+       ulong rx_ctlpkts;       /* Ctrl frames processed from dongle */
+       ulong rx_readahead_cnt; /* packets where header read-ahead was used */
+};
+
+struct brcmf_pub;
+#ifdef DEBUG
+void brcmf_debugfs_init(void);
+void brcmf_debugfs_exit(void);
+int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+void brcmf_debugfs_detach(struct brcmf_pub *drvr);
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+                                    struct brcmf_sdio_count *sdcnt);
+#else
+static inline void brcmf_debugfs_init(void)
+{
+}
+static inline void brcmf_debugfs_exit(void)
+{
+}
+static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+       return 0;
+}
+static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+}
+#endif
+
 #endif                         /* _BRCMF_DBG_H_ */
index 8933f9b31a9a64a7c2c3f5428aba47a4e85d88d5..01cf6c03390b1c68087e525c43e6203ade5a4d3a 100644 (file)
@@ -1007,6 +1007,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        drvr->bus_if->drvr = drvr;
        drvr->dev = dev;
 
+       /* create device debugfs folder */
+       brcmf_debugfs_attach(drvr);
+
        /* Attach and link in the protocol */
        ret = brcmf_proto_attach(drvr);
        if (ret != 0) {
@@ -1123,6 +1126,7 @@ void brcmf_detach(struct device *dev)
                brcmf_proto_detach(drvr);
        }
 
+       brcmf_debugfs_detach(drvr);
        bus_if->drvr = NULL;
        kfree(drvr);
 }
@@ -1192,6 +1196,8 @@ exit:
 
 static void brcmf_driver_init(struct work_struct *work)
 {
+       brcmf_debugfs_init();
+
 #ifdef CONFIG_BRCMFMAC_SDIO
        brcmf_sdio_init();
 #endif
@@ -1219,6 +1225,7 @@ static void __exit brcmfmac_module_exit(void)
 #ifdef CONFIG_BRCMFMAC_USB
        brcmf_usb_exit();
 #endif
+       brcmf_debugfs_exit();
 }
 
 module_init(brcmfmac_module_init);
index 1dbf2be478c82e4adcec6d95046dedac13e9d389..a07fb01bc36b82a01e9b11081f0253de589b5beb 100644 (file)
@@ -502,12 +502,9 @@ struct brcmf_sdio {
        bool intr;              /* Use interrupts */
        bool poll;              /* Use polling */
        bool ipend;             /* Device interrupt is pending */
-       uint intrcount;         /* Count of device interrupt callbacks */
-       uint lastintrs;         /* Count as of last watchdog timer */
        uint spurious;          /* Count of spurious interrupts */
        uint pollrate;          /* Ticks between device polls */
        uint polltick;          /* Tick counter */
-       uint pollcnt;           /* Count of active polls */
 
 #ifdef DEBUG
        uint console_interval;
@@ -515,8 +512,6 @@ struct brcmf_sdio {
        uint console_addr;      /* Console address from shared struct */
 #endif                         /* DEBUG */
 
-       uint regfails;          /* Count of R_REG failures */
-
        uint clkstate;          /* State of sd and backplane clock(s) */
        bool activity;          /* Activity flag for clock down */
        s32 idletime;           /* Control for activity timeout */
@@ -531,33 +526,6 @@ struct brcmf_sdio {
 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
        bool usebufpool;
 
-       /* Some additional counters */
-       uint tx_sderrs;         /* Count of tx attempts with sd errors */
-       uint fcqueued;          /* Tx packets that got queued */
-       uint rxrtx;             /* Count of rtx requests (NAK to dongle) */
-       uint rx_toolong;        /* Receive frames too long to receive */
-       uint rxc_errors;        /* SDIO errors when reading control frames */
-       uint rx_hdrfail;        /* SDIO errors on header reads */
-       uint rx_badhdr;         /* Bad received headers (roosync?) */
-       uint rx_badseq;         /* Mismatched rx sequence number */
-       uint fc_rcvd;           /* Number of flow-control events received */
-       uint fc_xoff;           /* Number which turned on flow-control */
-       uint fc_xon;            /* Number which turned off flow-control */
-       uint rxglomfail;        /* Failed deglom attempts */
-       uint rxglomframes;      /* Number of glom frames (superframes) */
-       uint rxglompkts;        /* Number of packets from glom frames */
-       uint f2rxhdrs;          /* Number of header reads */
-       uint f2rxdata;          /* Number of frame data reads */
-       uint f2txdata;          /* Number of f2 frame writes */
-       uint f1regdata;         /* Number of f1 register accesses */
-       uint tickcnt;           /* Number of watchdog been schedule */
-       unsigned long tx_ctlerrs;       /* Err of sending ctrl frames */
-       unsigned long tx_ctlpkts;       /* Ctrl frames sent to dongle */
-       unsigned long rx_ctlerrs;       /* Err of processing rx ctrl frames */
-       unsigned long rx_ctlpkts;       /* Ctrl frames processed from dongle */
-       unsigned long rx_readahead_cnt; /* Number of packets where header
-                                        * read-ahead was used. */
-
        u8 *ctrl_frame_buf;
        u32 ctrl_frame_len;
        bool ctrl_frame_stat;
@@ -583,6 +551,7 @@ struct brcmf_sdio {
        u32 fw_ptr;
 
        bool txoff;             /* Transmit flow-controlled */
+       struct brcmf_sdio_count sdcnt;
 };
 
 /* clkstate */
@@ -945,7 +914,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
        if (ret == 0)
                w_sdreg32(bus, SMB_INT_ACK,
                          offsetof(struct sdpcmd_regs, tosbmailbox));
-       bus->f1regdata += 2;
+       bus->sdcnt.f1regdata += 2;
 
        /* Dongle recomposed rx frames, accept them again */
        if (hmb_data & HMB_DATA_NAKHANDLED) {
@@ -984,12 +953,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
                                                        HMB_DATA_FCDATA_SHIFT;
 
                if (fcbits & ~bus->flowcontrol)
-                       bus->fc_xoff++;
+                       bus->sdcnt.fc_xoff++;
 
                if (bus->flowcontrol & ~fcbits)
-                       bus->fc_xon++;
+                       bus->sdcnt.fc_xon++;
 
-               bus->fc_rcvd++;
+               bus->sdcnt.fc_rcvd++;
                bus->flowcontrol = fcbits;
        }
 
@@ -1021,7 +990,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 
        brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                         SFC_RF_TERM, &err);
-       bus->f1regdata++;
+       bus->sdcnt.f1regdata++;
 
        /* Wait until the packet has been flushed (device/FIFO stable) */
        for (lastrbc = retries = 0xffff; retries > 0; retries--) {
@@ -1029,7 +998,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
                                      SBSDIO_FUNC1_RFRAMEBCHI, &err);
                lo = brcmf_sdio_regrb(bus->sdiodev,
                                      SBSDIO_FUNC1_RFRAMEBCLO, &err);
-               bus->f1regdata += 2;
+               bus->sdcnt.f1regdata += 2;
 
                if ((hi == 0) && (lo == 0))
                        break;
@@ -1047,11 +1016,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
                brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
 
        if (rtx) {
-               bus->rxrtx++;
+               bus->sdcnt.rxrtx++;
                err = w_sdreg32(bus, SMB_NAK,
                                offsetof(struct sdpcmd_regs, tosbmailbox));
 
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
                if (err == 0)
                        bus->rxskip = true;
        }
@@ -1243,7 +1212,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                  dlen);
                        errcode = -1;
                }
-               bus->f2rxdata++;
+               bus->sdcnt.f2rxdata++;
 
                /* On failure, kill the superframe, allow a couple retries */
                if (errcode < 0) {
@@ -1256,7 +1225,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               bus->rxglomfail++;
+                               bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
                        return 0;
@@ -1312,7 +1281,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                if (rxseq != seq) {
                        brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
                                  seq, rxseq);
-                       bus->rx_badseq++;
+                       bus->sdcnt.rx_badseq++;
                        rxseq = seq;
                }
 
@@ -1376,7 +1345,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               bus->rxglomfail++;
+                               bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
                        bus->nextlen = 0;
@@ -1402,7 +1371,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        if (rxseq != seq) {
                                brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
                                          seq, rxseq);
-                               bus->rx_badseq++;
+                               bus->sdcnt.rx_badseq++;
                                rxseq = seq;
                        }
                        rxseq++;
@@ -1441,8 +1410,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        down(&bus->sdsem);
                }
 
-               bus->rxglomframes++;
-               bus->rxglompkts += bus->glom.qlen;
+               bus->sdcnt.rxglomframes++;
+               bus->sdcnt.rxglompkts += bus->glom.qlen;
        }
        return num;
 }
@@ -1526,7 +1495,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
                          len, len - doff, bus->sdiodev->bus_if->maxctl);
                bus->sdiodev->bus_if->dstats.rx_errors++;
-               bus->rx_toolong++;
+               bus->sdcnt.rx_toolong++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                goto done;
        }
@@ -1536,13 +1505,13 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                                bus->sdiodev->sbwad,
                                SDIO_FUNC_2,
                                F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
-       bus->f2rxdata++;
+       bus->sdcnt.f2rxdata++;
 
        /* Control frame failures need retransmission */
        if (sdret < 0) {
                brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
                          rdlen, sdret);
-               bus->rxc_errors++;
+               bus->sdcnt.rxc_errors++;
                brcmf_sdbrcm_rxfail(bus, true, true);
                goto done;
        }
@@ -1589,7 +1558,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
        /* Read the entire frame */
        sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                      SDIO_FUNC_2, F2SYNC, *pkt);
-       bus->f2rxdata++;
+       bus->sdcnt.f2rxdata++;
 
        if (sdret < 0) {
                brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
@@ -1630,7 +1599,7 @@ brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
        if ((u16)~(*len ^ check)) {
                brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
                          nextlen, *len, check);
-               bus->rx_badhdr++;
+               bus->sdcnt.rx_badhdr++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                goto fail;
        }
@@ -1746,7 +1715,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                                bus->nextlen = 0;
                        }
 
-                       bus->rx_readahead_cnt++;
+                       bus->sdcnt.rx_readahead_cnt++;
 
                        /* Handle Flow Control */
                        fcbits = SDPCM_FCMASK_VALUE(
@@ -1754,12 +1723,12 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
                        if (bus->flowcontrol != fcbits) {
                                if (~bus->flowcontrol & fcbits)
-                                       bus->fc_xoff++;
+                                       bus->sdcnt.fc_xoff++;
 
                                if (bus->flowcontrol & ~fcbits)
-                                       bus->fc_xon++;
+                                       bus->sdcnt.fc_xon++;
 
-                               bus->fc_rcvd++;
+                               bus->sdcnt.fc_rcvd++;
                                bus->flowcontrol = fcbits;
                        }
 
@@ -1767,7 +1736,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                        if (rxseq != seq) {
                                brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
                                          seq, rxseq);
-                               bus->rx_badseq++;
+                               bus->sdcnt.rx_badseq++;
                                rxseq = seq;
                        }
 
@@ -1814,11 +1783,11 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, bus->rxhdr,
                                              BRCMF_FIRSTREAD);
-               bus->f2rxhdrs++;
+               bus->sdcnt.f2rxhdrs++;
 
                if (sdret < 0) {
                        brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
-                       bus->rx_hdrfail++;
+                       bus->sdcnt.rx_hdrfail++;
                        brcmf_sdbrcm_rxfail(bus, true, true);
                        continue;
                }
@@ -1840,7 +1809,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                if ((u16) ~(len ^ check)) {
                        brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
                                  len, check);
-                       bus->rx_badhdr++;
+                       bus->sdcnt.rx_badhdr++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1861,7 +1830,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                if ((doff < SDPCM_HDRLEN) || (doff > len)) {
                        brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
                                  doff, len, SDPCM_HDRLEN, seq);
-                       bus->rx_badhdr++;
+                       bus->sdcnt.rx_badhdr++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1880,19 +1849,19 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
                if (bus->flowcontrol != fcbits) {
                        if (~bus->flowcontrol & fcbits)
-                               bus->fc_xoff++;
+                               bus->sdcnt.fc_xoff++;
 
                        if (bus->flowcontrol & ~fcbits)
-                               bus->fc_xon++;
+                               bus->sdcnt.fc_xon++;
 
-                       bus->fc_rcvd++;
+                       bus->sdcnt.fc_rcvd++;
                        bus->flowcontrol = fcbits;
                }
 
                /* Check and update sequence number */
                if (rxseq != seq) {
                        brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
-                       bus->rx_badseq++;
+                       bus->sdcnt.rx_badseq++;
                        rxseq = seq;
                }
 
@@ -1937,7 +1906,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                        brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
                                  len, rdlen);
                        bus->sdiodev->bus_if->dstats.rx_errors++;
-                       bus->rx_toolong++;
+                       bus->sdcnt.rx_toolong++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1960,7 +1929,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                /* Read the remaining frame data */
                sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, pkt);
-               bus->f2rxdata++;
+               bus->sdcnt.f2rxdata++;
 
                if (sdret < 0) {
                        brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
@@ -2147,18 +2116,18 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 
        ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                    SDIO_FUNC_2, F2SYNC, pkt);
-       bus->f2txdata++;
+       bus->sdcnt.f2txdata++;
 
        if (ret < 0) {
                /* On failure, abort the command and terminate the frame */
                brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                          ret);
-               bus->tx_sderrs++;
+               bus->sdcnt.tx_sderrs++;
 
                brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
                brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                 SFC_WF_TERM, NULL);
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
@@ -2166,7 +2135,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
                        lo = brcmf_sdio_regrb(bus->sdiodev,
                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->f1regdata += 2;
+                       bus->sdcnt.f1regdata += 2;
                        if ((hi == 0) && (lo == 0))
                                break;
                }
@@ -2224,7 +2193,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                        ret = r_sdreg32(bus, &intstatus,
                                        offsetof(struct sdpcmd_regs,
                                                 intstatus));
-                       bus->f2txdata++;
+                       bus->sdcnt.f2txdata++;
                        if (ret != 0)
                                break;
                        if (intstatus & bus->hostintmask)
@@ -2417,7 +2386,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                bus->ipend = false;
                err = r_sdreg32(bus, &newstatus,
                                offsetof(struct sdpcmd_regs, intstatus));
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
                if (err != 0)
                        newstatus = 0;
                newstatus &= bus->hostintmask;
@@ -2426,7 +2395,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                        err = w_sdreg32(bus, newstatus,
                                        offsetof(struct sdpcmd_regs,
                                                 intstatus));
-                       bus->f1regdata++;
+                       bus->sdcnt.f1regdata++;
                }
        }
 
@@ -2445,7 +2414,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
                err = r_sdreg32(bus, &newstatus,
                                offsetof(struct sdpcmd_regs, intstatus));
-               bus->f1regdata += 2;
+               bus->sdcnt.f1regdata += 2;
                bus->fcstate =
                    !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
                intstatus |= (newstatus & bus->hostintmask);
@@ -2510,13 +2479,13 @@ clkwait:
                                terminate the frame */
                        brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                                  ret);
-                       bus->tx_sderrs++;
+                       bus->sdcnt.tx_sderrs++;
 
                        brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
                        brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                         SFC_WF_TERM, &err);
-                       bus->f1regdata++;
+                       bus->sdcnt.f1regdata++;
 
                        for (i = 0; i < 3; i++) {
                                u8 hi, lo;
@@ -2526,7 +2495,7 @@ clkwait:
                                lo = brcmf_sdio_regrb(bus->sdiodev,
                                                      SBSDIO_FUNC1_WFRAMEBCLO,
                                                      &err);
-                               bus->f1regdata += 2;
+                               bus->sdcnt.f1regdata += 2;
                                if ((hi == 0) && (lo == 0))
                                        break;
                        }
@@ -2657,7 +2626,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        /* Check for existing queue, current flow-control,
                         pending event, or pending clock */
        brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
-       bus->fcqueued++;
+       bus->sdcnt.fcqueued++;
 
        /* Priority based enq */
        spin_lock_bh(&bus->txqlock);
@@ -2845,13 +2814,13 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
                /* On failure, abort the command and terminate the frame */
                brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                          ret);
-               bus->tx_sderrs++;
+               bus->sdcnt.tx_sderrs++;
 
                brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
                brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                 SFC_WF_TERM, NULL);
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
@@ -2859,7 +2828,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
                        lo = brcmf_sdio_regrb(bus->sdiodev,
                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->f1regdata += 2;
+                       bus->sdcnt.f1regdata += 2;
                        if (hi == 0 && lo == 0)
                                break;
                }
@@ -2976,13 +2945,26 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
        up(&bus->sdsem);
 
        if (ret)
-               bus->tx_ctlerrs++;
+               bus->sdcnt.tx_ctlerrs++;
        else
-               bus->tx_ctlpkts++;
+               bus->sdcnt.tx_ctlpkts++;
 
        return ret ? -EIO : 0;
 }
 
+#ifdef DEBUG
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+       struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+
+       brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+}
+#else
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
 static int
 brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
@@ -3017,9 +2999,9 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        }
 
        if (rxlen)
-               bus->rx_ctlpkts++;
+               bus->sdcnt.rx_ctlpkts++;
        else
-               bus->rx_ctlerrs++;
+               bus->sdcnt.rx_ctlerrs++;
 
        return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
@@ -3419,7 +3401,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
                return 0;
 
        /* Start the watchdog timer */
-       bus->tickcnt = 0;
+       bus->sdcnt.tickcnt = 0;
        brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
 
        down(&bus->sdsem);
@@ -3512,7 +3494,7 @@ void brcmf_sdbrcm_isr(void *arg)
                return;
        }
        /* Count the interrupt call */
-       bus->intrcount++;
+       bus->sdcnt.intrcount++;
        bus->ipend = true;
 
        /* Shouldn't get this interrupt if we're sleeping? */
@@ -3554,7 +3536,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                bus->polltick = 0;
 
                /* Check device if no interrupts */
-               if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+               if (!bus->intr ||
+                   (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
 
                        if (!bus->dpc_sched) {
                                u8 devpend;
@@ -3569,7 +3552,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                        /* If there is something, make like the ISR and
                                 schedule the DPC */
                        if (intstatus) {
-                               bus->pollcnt++;
+                               bus->sdcnt.pollcnt++;
                                bus->ipend = true;
 
                                bus->dpc_sched = true;
@@ -3581,7 +3564,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                }
 
                /* Update interrupt tracking */
-               bus->lastintrs = bus->intrcount;
+               bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
        }
 #ifdef DEBUG
        /* Poll for console output periodically */
@@ -3793,7 +3776,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
                if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
                        brcmf_sdbrcm_bus_watchdog(bus);
                        /* Count the tick for reference */
-                       bus->tickcnt++;
+                       bus->sdcnt.tickcnt++;
                } else
                        break;
        }
@@ -3834,7 +3817,6 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
 static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
-
        if (bus) {
                /* De-register interrupt handler */
                brcmf_sdio_intr_unregister(bus->sdiodev);
@@ -3938,6 +3920,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
                goto fail;
        }
 
+       brcmf_sdio_debugfs_create(bus);
        brcmf_dbg(INFO, "completed!!\n");
 
        /* if firmware path present try to download and bring up bus */
index 95b5902bc4b3a3241f68cde20434b8592ba71ebc..01b190a25d947766ac2565ace38b6c9c096e7261 100644 (file)
@@ -735,10 +735,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                 * a candidate for aggregation
                 */
                p = pktq_ppeek(&qi->q, prec);
-               /* tx_info must be checked with current p */
-               tx_info = IEEE80211_SKB_CB(p);
-
                if (p) {
+                       tx_info = IEEE80211_SKB_CB(p);
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
                            ((u8) (p->priority) == tid)) {
                                plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
@@ -759,6 +757,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                                        p = NULL;
                                        continue;
                                }
+                               /* next packet fit for aggregation so dequeue */
                                p = brcmu_pktq_pdeq(&qi->q, prec);
                        } else {
                                p = NULL;
index 50f92a0b7c41408c0b4a416d9ffe82c69e3a70fd..341e06a0d6ec054e52485f2b411364fae9d7f47f 100644 (file)
@@ -721,14 +721,6 @@ static const struct ieee80211_ops brcms_ops = {
        .flush = brcms_ops_flush,
 };
 
-/*
- * is called in brcms_bcma_probe() context, therefore no locking required.
- */
-static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
-{
-       return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
-}
-
 void brcms_dpc(unsigned long data)
 {
        struct brcms_info *wl;
@@ -1068,9 +1060,9 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
                wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
                          "%d\n", __func__, err);
 
-       if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode))
-               wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
-                         __func__, err);
+       if (wl->pub->srom_ccode[0] &&
+           regulatory_hint(wl->wiphy, wl->pub->srom_ccode))
+               wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__);
 
        n_adapters_found++;
        return wl;
index 095547b37a274ac90e3615a8f7bf8c9275b2b776..a175997e782965022703e7850a2600f62b5da9ac 100644 (file)
@@ -911,8 +911,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                const struct iwl_op_mode_ops *ops = op->ops;
                drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
 
-               if (!drv->op_mode)
+               if (!drv->op_mode) {
+                       mutex_unlock(&iwlwifi_opmode_table_mtx);
                        goto out_unbind;
+               }
        } else {
                load_module = true;
        }
index 8173ab66066ddf3e83e402cc45f92f808f4f26c3..89f9a2a45de3f772e15cbd4084735e9bc7013d54 100644 (file)
@@ -27,6 +27,17 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                              struct cfg80211_ap_settings *params) {
        int i;
 
+       if (!params->privacy) {
+               bss_config->protocol = PROTOCOL_NO_SECURITY;
+               bss_config->key_mgmt = KEY_MGMT_NONE;
+               bss_config->wpa_cfg.length = 0;
+               priv->sec_info.wep_enabled = 0;
+               priv->sec_info.wpa_enabled = 0;
+               priv->sec_info.wpa2_enabled = 0;
+
+               return 0;
+       }
+
        switch (params->auth_type) {
        case NL80211_AUTHTYPE_OPEN_SYSTEM:
                bss_config->auth_mode = WLAN_AUTH_OPEN;
index 2e9e6af21362c1fe302d68e61cb4a83d229f5b24..dfcd02ab6cae5add70a2eb47c703d54b32c324ce 100644 (file)
@@ -2110,7 +2110,7 @@ resize_buf:
        while (check_bssid_list_item(bssid, bssid_len, buf, len)) {
                if (rndis_bss_info_update(usbdev, bssid) && match_bssid &&
                    matched) {
-                       if (!ether_addr_equal(bssid->mac, match_bssid))
+                       if (ether_addr_equal(bssid->mac, match_bssid))
                                *matched = true;
                }
 
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644 (file)
index 0000000..6a76e0a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef __A2MP_H
+#define __A2MP_H
+
+#include <net/bluetooth/l2cap.h>
+
+#define A2MP_FEAT_EXT  0x8000
+
+struct amp_mgr {
+       struct l2cap_conn       *l2cap_conn;
+       struct l2cap_chan       *a2mp_chan;
+       struct kref             kref;
+       __u8                    ident;
+       __u8                    handle;
+       unsigned long           flags;
+};
+
+struct a2mp_cmd {
+       __u8    code;
+       __u8    ident;
+       __le16  len;
+       __u8    data[0];
+} __packed;
+
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+       __le16  reason;
+       __u8    data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+       __le16  mtu;
+       __le16  ext_feat;
+} __packed;
+
+struct a2mp_cl {
+       __u8    id;
+       __u8    type;
+       __u8    status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+       __le16     mtu;
+       __le16     ext_feat;
+       struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+       __u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+       __u8    id;
+       __u8    status;
+       __le32  total_bw;
+       __le32  max_bw;
+       __le32  min_latency;
+       __le16  pal_cap;
+       __le16  assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+       __u8    id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+       __u8    id;
+       __u8    status;
+       __u8    amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+       __u8    local_id;
+       __u8    remote_id;
+       __u8    amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+       __u8    local_id;
+       __u8    remote_id;
+       __u8    status;
+} __packed;
+
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS                    0x00
+#define A2MP_STATUS_INVALID_CTRL_ID            0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS    0x02
+#define A2MP_STATUS_COLLISION_OCCURED          0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD          0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS           0x05
+#define A2MP_STATUS_SECURITY_VIOLATION         0x06
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+                                      struct sk_buff *skb);
+
+#endif /* __A2MP_H */
index 961669b648fddd259cc65b9f0771d5158b6f5917..565d4bee1e493bbaa145f5e3621bc27e4295727f 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 #ifndef __BLUETOOTH_H
 #define __BLUETOOTH_H
 
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#include <linux/list.h>
 #include <linux/poll.h>
 #include <net/sock.h>
 
@@ -168,8 +165,8 @@ typedef struct {
 #define BDADDR_LE_PUBLIC       0x01
 #define BDADDR_LE_RANDOM       0x02
 
-#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
 
 /* Copy, swap, convert BD Address */
 static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
@@ -215,7 +212,7 @@ int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                                struct msghdr *msg, size_t len, int flags);
 int  bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *msg, size_t len, int flags);
-uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
 int  bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int  bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
 
@@ -225,12 +222,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
 struct l2cap_ctrl {
-       unsigned int    sframe  : 1,
-                       poll    : 1,
-                       final   : 1,
-                       fcs     : 1,
-                       sar     : 2,
-                       super   : 2;
+       unsigned int    sframe:1,
+                       poll:1,
+                       final:1,
+                       fcs:1,
+                       sar:2,
+                       super:2;
        __u16           reqseq;
        __u16           txseq;
        __u8            retries;
@@ -249,7 +246,8 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
 {
        struct sk_buff *skb;
 
-       if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
+       skb = alloc_skb(len + BT_SKB_RESERVE, how);
+       if (skb) {
                skb_reserve(skb, BT_SKB_RESERVE);
                bt_cb(skb)->incoming  = 0;
        }
@@ -261,7 +259,8 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
 {
        struct sk_buff *skb;
 
-       if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
+       skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
+       if (skb) {
                skb_reserve(skb, BT_SKB_RESERVE);
                bt_cb(skb)->incoming  = 0;
        }
index 66a7b579e31c81912f635beb272cebf82a05ac57..2a6b0b8b71201dac383ee058a9df6f7f595a150e 100644 (file)
@@ -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
 };
@@ -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 */
@@ -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
@@ -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;
@@ -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];
@@ -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;
 
@@ -1144,6 +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;
@@ -1190,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;
@@ -1290,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;
@@ -1307,12 +1396,12 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 }
 
 /* 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)
 
index 9fc7728f94e4af3adaaed5944b5c665823363fc4..20fd57367ddcd90f4b3d7027d45af275a860cb41 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
-#include <linux/interrupt.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI priority */
@@ -65,7 +64,7 @@ struct discovery_state {
                DISCOVERY_RESOLVING,
                DISCOVERY_STOPPING,
        } state;
-       struct list_head        all;            /* All devices found during inquiry */
+       struct list_head        all;    /* All devices found during inquiry */
        struct list_head        unknown;        /* Name state not known */
        struct list_head        resolve;        /* Name needs to be resolved */
        __u32                   timestamp;
@@ -105,7 +104,7 @@ struct link_key {
        struct list_head list;
        bdaddr_t bdaddr;
        u8 type;
-       u8 val[16];
+       u8 val[HCI_LINK_KEY_SIZE];
        u8 pin_len;
 };
 
@@ -333,6 +332,7 @@ struct hci_conn {
        void            *l2cap_data;
        void            *sco_data;
        void            *smp_conn;
+       struct amp_mgr  *amp_mgr;
 
        struct hci_conn *link;
 
@@ -360,7 +360,8 @@ extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
 extern int l2cap_disconn_ind(struct hci_conn *hcon);
 extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
 extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
-extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
+extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
+                             u16 flags);
 
 extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
 extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
@@ -429,8 +430,8 @@ enum {
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
-       return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
-                               test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
+       return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+              test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -640,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
        dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+       uint8_t count = 0;
+       struct list_head *p;
+
+       list_for_each(p, &hci_dev_list) {
+               count++;
+       }
+
+       return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
@@ -661,7 +675,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
 int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
 int hci_inquiry(void __user *arg);
 
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
+                                        bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
index 1c7d1cd5e679fa1c6e4d94d29300d56807214f82..d80e3f0691b4982c38043dfd84d345ba2121a8cb 100644 (file)
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
-#define L2CAP_LE_DEFAULT_MTU           23
 #define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD                1019    /* 3-DH5 packet */
+#define L2CAP_LE_MIN_MTU               23
 
 #define L2CAP_DISC_TIMEOUT             msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT         msecs_to_jiffies(5000)
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT             msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT             msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU         670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
        sa_family_t     l2_family;
@@ -229,9 +231,14 @@ struct l2cap_conn_rsp {
        __le16     status;
 } __packed;
 
+/* protocol/service multiplexer (PSM) */
+#define L2CAP_PSM_SDP          0x0001
+#define L2CAP_PSM_RFCOMM       0x0003
+
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING    0x0001
 #define L2CAP_CID_CONN_LESS    0x0002
+#define L2CAP_CID_A2MP         0x0003
 #define L2CAP_CID_LE_DATA      0x0004
 #define L2CAP_CID_LE_SIGNALING 0x0005
 #define L2CAP_CID_SMP          0x0006
@@ -271,6 +278,9 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_PENDING     0x0004
 #define L2CAP_CONF_EFS_REJECT  0x0005
 
+/* configuration req/rsp continuation flag */
+#define L2CAP_CONF_FLAG_CONTINUATION   0x0001
+
 struct l2cap_conf_opt {
        __u8       type;
        __u8       len;
@@ -419,11 +429,6 @@ struct l2cap_seq_list {
 #define L2CAP_SEQ_LIST_CLEAR   0xFFFF
 #define L2CAP_SEQ_LIST_TAIL    0x8000
 
-struct srej_list {
-       __u16   tx_seq;
-       struct list_head list;
-};
-
 struct l2cap_chan {
        struct sock *sk;
 
@@ -475,14 +480,12 @@ struct l2cap_chan {
        __u16           expected_ack_seq;
        __u16           expected_tx_seq;
        __u16           buffer_seq;
-       __u16           buffer_seq_srej;
        __u16           srej_save_reqseq;
        __u16           last_acked_seq;
        __u16           frames_sent;
        __u16           unacked_frames;
        __u8            retry_count;
        __u16           srej_queue_next;
-       __u8            num_acked;
        __u16           sdu_len;
        struct sk_buff  *sdu;
        struct sk_buff  *sdu_last_frag;
@@ -515,7 +518,6 @@ struct l2cap_chan {
        struct sk_buff_head     srej_q;
        struct l2cap_seq_list   srej_list;
        struct l2cap_seq_list   retrans_list;
-       struct list_head        srej_l;
 
        struct list_head        list;
        struct list_head        global_l;
@@ -528,10 +530,14 @@ struct l2cap_chan {
 struct l2cap_ops {
        char                    *name;
 
-       struct l2cap_chan       *(*new_connection) (void *data);
-       int                     (*recv) (void *data, struct sk_buff *skb);
-       void                    (*close) (void *data);
-       void                    (*state_change) (void *data, int state);
+       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
+       int                     (*recv) (struct l2cap_chan * chan,
+                                        struct sk_buff *skb);
+       void                    (*teardown) (struct l2cap_chan *chan, int err);
+       void                    (*close) (struct l2cap_chan *chan);
+       void                    (*state_change) (struct l2cap_chan *chan,
+                                                int state);
+       void                    (*ready) (struct l2cap_chan *chan);
        struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
                                               unsigned long len, int nb);
 };
@@ -575,6 +581,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW                 1
 #define L2CAP_CHAN_CONN_LESS           2
 #define L2CAP_CHAN_CONN_ORIENTED       3
+#define L2CAP_CHAN_CONN_FIX_A2MP       4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
@@ -597,6 +604,7 @@ enum {
        CONF_EWS_RECV,
        CONF_LOC_CONF_PEND,
        CONF_REM_CONF_PEND,
+       CONF_NOT_COMPLETE,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -713,11 +721,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
-               msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
 #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
-#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
-               msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
 #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
 #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
                msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
@@ -736,173 +740,17 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
        return (seq + 1) % (chan->tx_win_max + 1);
 }
 
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
-       int sub;
-
-       sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-       if (sub < 0)
-               sub += 64;
-
-       return sub == ch->remote_tx_win;
-}
-
-static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
-                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
-}
-
-static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
-                                                       L2CAP_EXT_CTRL_REQSEQ;
-       else
-               return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+       return NULL;
 }
 
-static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
-                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
 }
 
-static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
-                                                       L2CAP_EXT_CTRL_TXSEQ;
-       else
-               return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
-}
-
-static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
-       else
-               return ctrl & L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u32 __set_sframe(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_FRAME_TYPE;
-       else
-               return L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
-}
-
-static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
-       else
-               return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
-}
-
-static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
-{
-       return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
-}
-
-static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_SAR;
-       else
-               return L2CAP_CTRL_SAR;
-}
-
-static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
-                                               L2CAP_EXT_CTRL_SUPER_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
-}
-
-static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
-                                               L2CAP_EXT_CTRL_SUPERVISE;
-       else
-               return (super << L2CAP_CTRL_SUPER_SHIFT) &
-                                                       L2CAP_CTRL_SUPERVISE;
-}
-
-static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_FINAL;
-       else
-               return L2CAP_CTRL_FINAL;
-}
-
-static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_FINAL;
-       else
-               return ctrl & L2CAP_CTRL_FINAL;
-}
-
-static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_POLL;
-       else
-               return L2CAP_CTRL_POLL;
-}
-
-static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_POLL;
-       else
-               return ctrl & L2CAP_CTRL_POLL;
-}
-
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return get_unaligned_le32(p);
-       else
-               return get_unaligned_le16(p);
-}
-
-static inline void __put_control(struct l2cap_chan *chan, __u32 control,
-                                                               void *p)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return put_unaligned_le32(control, p);
-       else
-               return put_unaligned_le16(control, p);
-}
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-       else
-               return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
 }
 
 extern bool disable_ertm;
@@ -926,5 +774,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
index d152f54064fd612bc6c95c2de3bf9a30c1a92919..6914f9978aea0347da19c485d296492624dc9a8b 100644 (file)
@@ -1945,6 +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.
@@ -2974,6 +2979,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
  * 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.
  *
index 2dc5a5700f533191558381d8bcc0b16016b185a6..fa6d94a4602a8352a6f2aa9ed13ed18ff7e6c08a 100644 (file)
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)   += cmtp/
 obj-$(CONFIG_BT_HIDP)  += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-       hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+       hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+       a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644 (file)
index 0000000..fb93250
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
+
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+       struct a2mp_cmd *cmd;
+       int plen;
+
+       plen = sizeof(*cmd) + len;
+       cmd = kzalloc(plen, GFP_KERNEL);
+       if (!cmd)
+               return NULL;
+
+       cmd->code = code;
+       cmd->ident = ident;
+       cmd->len = cpu_to_le16(len);
+
+       memcpy(cmd->data, data, len);
+
+       return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+                     void *data)
+{
+       struct l2cap_chan *chan = mgr->a2mp_chan;
+       struct a2mp_cmd *cmd;
+       u16 total_len = len + sizeof(*cmd);
+       struct kvec iv;
+       struct msghdr msg;
+
+       cmd = __a2mp_build(code, ident, len, data);
+       if (!cmd)
+               return;
+
+       iv.iov_base = cmd;
+       iv.iov_len = total_len;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.msg_iov = (struct iovec *) &iv;
+       msg.msg_iovlen = 1;
+
+       l2cap_chan_send(chan, &msg, total_len, 0);
+
+       kfree(cmd);
+}
+
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+       cl->id = 0;
+       cl->type = 0;
+       cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+       int i = 0;
+       struct hci_dev *hdev;
+
+       __a2mp_cl_bredr(cl);
+
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               /* Iterate through AMP controllers */
+               if (hdev->id == HCI_BREDR_ID)
+                       continue;
+
+               /* Starting from second entry */
+               if (++i >= num_ctrl)
+                       return;
+
+               cl[i].id = hdev->id;
+               cl[i].type = hdev->amp_type;
+               cl[i].status = hdev->amp_status;
+       }
+}
+
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_cmd_rej *rej = (void *) skb->data;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*rej))
+               return -EINVAL;
+
+       BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+       skb_pull(skb, sizeof(*rej));
+
+       return 0;
+}
+
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                            struct a2mp_cmd *hdr)
+{
+       struct a2mp_discov_req *req = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct a2mp_discov_rsp *rsp;
+       u16 ext_feat;
+       u8 num_ctrl;
+
+       if (len < sizeof(*req))
+               return -EINVAL;
+
+       skb_pull(skb, sizeof(*req));
+
+       ext_feat = le16_to_cpu(req->ext_feat);
+
+       BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+       /* check that packet is not broken for now */
+       while (ext_feat & A2MP_FEAT_EXT) {
+               if (len < sizeof(ext_feat))
+                       return -EINVAL;
+
+               ext_feat = get_unaligned_le16(skb->data);
+               BT_DBG("efm 0x%4.4x", ext_feat);
+               len -= sizeof(ext_feat);
+               skb_pull(skb, sizeof(ext_feat));
+       }
+
+       read_lock(&hci_dev_list_lock);
+
+       num_ctrl = __hci_num_ctrl();
+       len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+       rsp = kmalloc(len, GFP_ATOMIC);
+       if (!rsp) {
+               read_unlock(&hci_dev_list_lock);
+               return -ENOMEM;
+       }
+
+       rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+       rsp->ext_feat = 0;
+
+       __a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+       read_unlock(&hci_dev_list_lock);
+
+       a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+       kfree(rsp);
+       return 0;
+}
+
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+                             struct a2mp_cmd *hdr)
+{
+       struct a2mp_cl *cl = (void *) skb->data;
+
+       while (skb->len >= sizeof(*cl)) {
+               BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+                      cl->status);
+               cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+       }
+
+       /* TODO send A2MP_CHANGE_RSP */
+
+       return 0;
+}
+
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_info_req *req  = (void *) skb->data;
+       struct a2mp_info_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("id %d", req->id);
+
+       rsp.id = req->id;
+       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+       hdev = hci_dev_get(req->id);
+       if (hdev && hdev->amp_type != HCI_BREDR) {
+               rsp.status = 0;
+               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       }
+
+       if (hdev)
+               hci_dev_put(hdev);
+
+       a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                               struct a2mp_cmd *hdr)
+{
+       struct a2mp_amp_assoc_req *req = (void *) skb->data;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("id %d", req->id);
+
+       hdev = hci_dev_get(req->id);
+       if (!hdev || hdev->amp_type == HCI_BREDR) {
+               struct a2mp_amp_assoc_rsp rsp;
+               rsp.id = req->id;
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+                         &rsp);
+               goto clean;
+       }
+
+       /* Placeholder for HCI Read AMP Assoc */
+
+clean:
+       if (hdev)
+               hci_dev_put(hdev);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                                  struct a2mp_cmd *hdr)
+{
+       struct a2mp_physlink_req *req = (void *) skb->data;
+
+       struct a2mp_physlink_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+       rsp.local_id = req->remote_id;
+       rsp.remote_id = req->local_id;
+
+       hdev = hci_dev_get(req->remote_id);
+       if (!hdev || hdev->amp_type != HCI_AMP) {
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               goto send_rsp;
+       }
+
+       /* TODO process physlink create */
+
+       rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+       if (hdev)
+               hci_dev_put(hdev);
+
+       a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+                 &rsp);
+
+       skb_pull(skb, le16_to_cpu(hdr->len));
+       return 0;
+}
+
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                                struct a2mp_cmd *hdr)
+{
+       struct a2mp_physlink_req *req = (void *) skb->data;
+       struct a2mp_physlink_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+       rsp.local_id = req->remote_id;
+       rsp.remote_id = req->local_id;
+       rsp.status = A2MP_STATUS_SUCCESS;
+
+       hdev = hci_dev_get(req->local_id);
+       if (!hdev) {
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               goto send_rsp;
+       }
+
+       /* TODO Disconnect Phys Link here */
+
+       hci_dev_put(hdev);
+
+send_rsp:
+       a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                              struct a2mp_cmd *hdr)
+{
+       BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+       skb_pull(skb, le16_to_cpu(hdr->len));
+       return 0;
+}
+
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       struct a2mp_cmd *hdr = (void *) skb->data;
+       struct amp_mgr *mgr = chan->data;
+       int err = 0;
+
+       amp_mgr_get(mgr);
+
+       while (skb->len >= sizeof(*hdr)) {
+               struct a2mp_cmd *hdr = (void *) skb->data;
+               u16 len = le16_to_cpu(hdr->len);
+
+               BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+               skb_pull(skb, sizeof(*hdr));
+
+               if (len > skb->len || !hdr->ident) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               mgr->ident = hdr->ident;
+
+               switch (hdr->code) {
+               case A2MP_COMMAND_REJ:
+                       a2mp_command_rej(mgr, skb, hdr);
+                       break;
+
+               case A2MP_DISCOVER_REQ:
+                       err = a2mp_discover_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_NOTIFY:
+                       err = a2mp_change_notify(mgr, skb, hdr);
+                       break;
+
+               case A2MP_GETINFO_REQ:
+                       err = a2mp_getinfo_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_GETAMPASSOC_REQ:
+                       err = a2mp_getampassoc_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CREATEPHYSLINK_REQ:
+                       err = a2mp_createphyslink_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_DISCONNPHYSLINK_REQ:
+                       err = a2mp_discphyslink_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_RSP:
+               case A2MP_DISCOVER_RSP:
+               case A2MP_GETINFO_RSP:
+               case A2MP_GETAMPASSOC_RSP:
+               case A2MP_CREATEPHYSLINK_RSP:
+               case A2MP_DISCONNPHYSLINK_RSP:
+                       err = a2mp_cmd_rsp(mgr, skb, hdr);
+                       break;
+
+               default:
+                       BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+                       err = -EINVAL;
+                       break;
+               }
+       }
+
+       if (err) {
+               struct a2mp_cmd_rej rej;
+               rej.reason = __constant_cpu_to_le16(0);
+
+               BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+               a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+                         &rej);
+       }
+
+       /* Always free skb and return success error code to prevent
+          from sending L2CAP Disconnect over A2MP channel */
+       kfree_skb(skb);
+
+       amp_mgr_put(mgr);
+
+       return 0;
+}
+
+static void a2mp_chan_close_cb(struct l2cap_chan *chan)
+{
+       l2cap_chan_destroy(chan);
+}
+
+static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
+{
+       struct amp_mgr *mgr = chan->data;
+
+       if (!mgr)
+               return;
+
+       BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+       chan->state = state;
+
+       switch (state) {
+       case BT_CLOSED:
+               if (mgr)
+                       amp_mgr_put(mgr);
+               break;
+       }
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+                                             unsigned long len, int nb)
+{
+       return bt_skb_alloc(len, GFP_KERNEL);
+}
+
+static struct l2cap_ops a2mp_chan_ops = {
+       .name = "L2CAP A2MP channel",
+       .recv = a2mp_chan_recv_cb,
+       .close = a2mp_chan_close_cb,
+       .state_change = a2mp_chan_state_change_cb,
+       .alloc_skb = a2mp_chan_alloc_skb_cb,
+
+       /* Not implemented for A2MP */
+       .new_connection = l2cap_chan_no_new_connection,
+       .teardown = l2cap_chan_no_teardown,
+       .ready = l2cap_chan_no_ready,
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+       struct l2cap_chan *chan;
+       int err;
+
+       chan = l2cap_chan_create();
+       if (!chan)
+               return NULL;
+
+       BT_DBG("chan %p", chan);
+
+       chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
+       chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+       chan->ops = &a2mp_chan_ops;
+
+       l2cap_chan_set_defaults(chan);
+       chan->remote_max_tx = chan->max_tx;
+       chan->remote_tx_win = chan->tx_win;
+
+       chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+       chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+       skb_queue_head_init(&chan->tx_q);
+
+       chan->mode = L2CAP_MODE_ERTM;
+
+       err = l2cap_ertm_init(chan);
+       if (err < 0) {
+               l2cap_chan_del(chan, 0);
+               return NULL;
+       }
+
+       chan->conf_state = 0;
+
+       l2cap_chan_add(conn, chan);
+
+       chan->remote_mps = chan->omtu;
+       chan->mps = chan->omtu;
+
+       chan->state = BT_CONNECTED;
+
+       return chan;
+}
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+       BT_DBG("mgr %p", mgr);
+
+       kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+       struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+       BT_DBG("mgr %p", mgr);
+
+       kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+       BT_DBG("mgr %p", mgr);
+
+       return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+       struct amp_mgr *mgr;
+       struct l2cap_chan *chan;
+
+       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+       if (!mgr)
+               return NULL;
+
+       BT_DBG("conn %p mgr %p", conn, mgr);
+
+       mgr->l2cap_conn = conn;
+
+       chan = a2mp_chan_open(conn);
+       if (!chan) {
+               kfree(mgr);
+               return NULL;
+       }
+
+       mgr->a2mp_chan = chan;
+       chan->data = mgr;
+
+       conn->hcon->amp_mgr = mgr;
+
+       kref_init(&mgr->kref);
+
+       return mgr;
+}
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+                                      struct sk_buff *skb)
+{
+       struct amp_mgr *mgr;
+
+       mgr = amp_mgr_create(conn);
+       if (!mgr) {
+               BT_ERR("Could not create AMP manager");
+               return NULL;
+       }
+
+       BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+       return mgr->a2mp_chan;
+}
index 3e18af4dadc442573960b94abefed550212b9b47..f7db5792ec648d3078d047cb46d0b269a68028bf 100644 (file)
 /* Bluetooth address family and sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <net/sock.h>
 #include <asm/ioctls.h>
-#include <linux/kmod.h>
 
 #include <net/bluetooth/bluetooth.h>
 
@@ -418,7 +407,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
        return 0;
 }
 
-unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
+unsigned int bt_sock_poll(struct file *file, struct socket *sock,
+                         poll_table *wait)
 {
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
index 031d7d656754936ab6c43ae124b339a87fb8f534..4a6620bc1570901c34a1c406ffb83909c27d3348 100644 (file)
 */
 
 #include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/errno.h>
-#include <linux/net.h>
-#include <linux/slab.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/socket.h>
 #include <linux/file.h>
-
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -306,7 +289,7 @@ static u8 __bnep_rx_hlen[] = {
        ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
 };
 
-static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
        struct net_device *dev = s->dev;
        struct sk_buff *nskb;
@@ -404,7 +387,7 @@ static u8 __bnep_tx_types[] = {
        BNEP_COMPRESSED
 };
 
-static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
        struct ethhdr *eh = (void *) skb->data;
        struct socket *sock = s->sock;
index bc4086480d97fa7586c3f8b01e07cd1c8ebbc69d..98f86f91d47c691b9e6604b73e2e8248f29921cf 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/netdevice.h>
+#include <linux/export.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-
-#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -128,7 +120,7 @@ static void bnep_net_timeout(struct net_device *dev)
 }
 
 #ifdef CONFIG_BT_BNEP_MC_FILTER
-static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
        struct ethhdr *eh = (void *) skb->data;
 
@@ -140,7 +132,7 @@ static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
+static u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
        struct ethhdr *eh = (void *) skb->data;
        u16 proto = ntohs(eh->h_proto);
@@ -154,7 +146,7 @@ static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
        return ETH_P_802_2;
 }
 
-static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
        u16 proto = bnep_net_eth_proto(skb);
        struct bnep_proto_filter *f = s->proto_filter;
index 180bfc45810da0217e4639dbd6d154a91a63c128..5e5f5b410e0b24f751eb158ad235fe16bfa3ee6f 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
 
 #include "bnep.h"
 
index 3f18a6ed9731503baf07de27d510691d8e718a98..2fcced377e503ad2e9feded38ec5609748e7d2ff 100644 (file)
 
 /* Bluetooth HCI connection 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 <asm/unaligned.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -54,15 +41,15 @@ static void hci_le_connect(struct hci_conn *conn)
        conn->sec_level = BT_SECURITY_LOW;
 
        memset(&cp, 0, sizeof(cp));
-       cp.scan_interval = cpu_to_le16(0x0060);
-       cp.scan_window = cpu_to_le16(0x0030);
+       cp.scan_interval = __constant_cpu_to_le16(0x0060);
+       cp.scan_window = __constant_cpu_to_le16(0x0030);
        bacpy(&cp.peer_addr, &conn->dst);
        cp.peer_addr_type = conn->dst_type;
-       cp.conn_interval_min = cpu_to_le16(0x0028);
-       cp.conn_interval_max = cpu_to_le16(0x0038);
-       cp.supervision_timeout = cpu_to_le16(0x002a);
-       cp.min_ce_len = cpu_to_le16(0x0000);
-       cp.max_ce_len = cpu_to_le16(0x0000);
+       cp.conn_interval_min = __constant_cpu_to_le16(0x0028);
+       cp.conn_interval_max = __constant_cpu_to_le16(0x0038);
+       cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
+       cp.min_ce_len = __constant_cpu_to_le16(0x0000);
+       cp.max_ce_len = __constant_cpu_to_le16(0x0000);
 
        hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 }
@@ -99,7 +86,7 @@ void hci_acl_connect(struct hci_conn *conn)
                        cp.pscan_rep_mode = ie->data.pscan_rep_mode;
                        cp.pscan_mode     = ie->data.pscan_mode;
                        cp.clock_offset   = ie->data.clock_offset |
-                                                       cpu_to_le16(0x8000);
+                                           __constant_cpu_to_le16(0x8000);
                }
 
                memcpy(conn->dev_class, ie->data.dev_class, 3);
@@ -175,9 +162,9 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
        cp.handle   = cpu_to_le16(handle);
        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.voice_setting  = cpu_to_le16(hdev->voice_setting);
        cp.retrans_effort = 0xff;
 
@@ -185,7 +172,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 }
 
 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
-                                       u16 latency, u16 to_multiplier)
+                       u16 latency, u16 to_multiplier)
 {
        struct hci_cp_le_conn_update cp;
        struct hci_dev *hdev = conn->hdev;
@@ -197,15 +184,14 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
        cp.conn_interval_max    = cpu_to_le16(max);
        cp.conn_latency         = cpu_to_le16(latency);
        cp.supervision_timeout  = cpu_to_le16(to_multiplier);
-       cp.min_ce_len           = cpu_to_le16(0x0001);
-       cp.max_ce_len           = cpu_to_le16(0x0001);
+       cp.min_ce_len           = __constant_cpu_to_le16(0x0001);
+       cp.max_ce_len           = __constant_cpu_to_le16(0x0001);
 
        hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_conn_update);
 
 void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
-                                                       __u8 ltk[16])
+                     __u8 ltk[16])
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_le_start_enc cp;
@@ -221,7 +207,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 
        hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_start_enc);
 
 /* Device _must_ be locked */
 void hci_sco_setup(struct hci_conn *conn, __u8 status)
@@ -247,7 +232,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
 static void hci_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
-                                                       disc_work.work);
+                                            disc_work.work);
        __u8 reason;
 
        BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
@@ -295,9 +280,9 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
        if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
                struct hci_cp_sniff_subrate cp;
                cp.handle             = cpu_to_le16(conn->handle);
-               cp.max_latency        = cpu_to_le16(0);
-               cp.min_remote_timeout = cpu_to_le16(0);
-               cp.min_local_timeout  = cpu_to_le16(0);
+               cp.max_latency        = __constant_cpu_to_le16(0);
+               cp.min_remote_timeout = __constant_cpu_to_le16(0);
+               cp.min_local_timeout  = __constant_cpu_to_le16(0);
                hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
        }
 
@@ -306,8 +291,8 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.handle       = cpu_to_le16(conn->handle);
                cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
                cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
-               cp.attempt      = cpu_to_le16(4);
-               cp.timeout      = cpu_to_le16(1);
+               cp.attempt      = __constant_cpu_to_le16(4);
+               cp.timeout      = __constant_cpu_to_le16(1);
                hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
        }
 }
@@ -327,7 +312,7 @@ static void hci_conn_auto_accept(unsigned long arg)
        struct hci_dev *hdev = conn->hdev;
 
        hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
-                                                               &conn->dst);
+                    &conn->dst);
 }
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
@@ -376,7 +361,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
        setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
-                                                       (unsigned long) conn);
+                   (unsigned long) conn);
 
        atomic_set(&conn->refcnt, 0);
 
@@ -425,9 +410,11 @@ int hci_conn_del(struct hci_conn *conn)
                }
        }
 
-
        hci_chan_list_flush(conn);
 
+       if (conn->amp_mgr)
+               amp_mgr_put(conn->amp_mgr);
+
        hci_conn_hash_del(hdev, conn);
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -454,7 +441,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
        read_lock(&hci_dev_list_lock);
 
        list_for_each_entry(d, &hci_dev_list, list) {
-               if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
+               if (!test_bit(HCI_UP, &d->flags) ||
+                   test_bit(HCI_RAW, &d->flags))
                        continue;
 
                /* Simple routing:
@@ -495,6 +483,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        if (type == LE_LINK) {
                le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
                if (!le) {
+                       le = hci_conn_hash_lookup_state(hdev, LE_LINK,
+                                                       BT_CONNECT);
+                       if (le)
+                               return ERR_PTR(-EBUSY);
+
                        le = hci_conn_add(hdev, LE_LINK, dst);
                        if (!le)
                                return ERR_PTR(-ENOMEM);
@@ -545,7 +538,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        hci_conn_hold(sco);
 
        if (acl->state == BT_CONNECTED &&
-                       (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+           (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
                set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
                hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 
@@ -560,7 +553,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
 
        return sco;
 }
-EXPORT_SYMBOL(hci_connect);
 
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
@@ -572,7 +564,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 
        return 1;
 }
-EXPORT_SYMBOL(hci_conn_check_link_mode);
 
 /* Authenticate remote device */
 static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
@@ -600,7 +591,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
                if (conn->key_type != 0xff)
                        set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
        }
@@ -618,7 +609,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 0x01;
                hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-                                                                       &cp);
+                            &cp);
        }
 }
 
@@ -648,8 +639,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
        /* An unauthenticated combination key has sufficient security for
           security level 1 and 2. */
        if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
-                       (sec_level == BT_SECURITY_MEDIUM ||
-                       sec_level == BT_SECURITY_LOW))
+           (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
                goto encrypt;
 
        /* A combination key has always sufficient security for the security
@@ -657,8 +647,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
           is generated using maximum PIN code length (16).
           For pre 2.1 units. */
        if (conn->key_type == HCI_LK_COMBINATION &&
-                       (sec_level != BT_SECURITY_HIGH ||
-                       conn->pin_length == 16))
+           (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
                goto encrypt;
 
 auth:
@@ -701,12 +690,11 @@ int hci_conn_change_link_key(struct hci_conn *conn)
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
        }
 
        return 0;
 }
-EXPORT_SYMBOL(hci_conn_change_link_key);
 
 /* Switch role */
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
@@ -752,7 +740,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
 timer:
        if (hdev->idle_timeout > 0)
                mod_timer(&conn->idle_timer,
-                       jiffies + msecs_to_jiffies(hdev->idle_timeout));
+                         jiffies + msecs_to_jiffies(hdev->idle_timeout));
 }
 
 /* Drop all connection on the device */
@@ -802,7 +790,7 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
-       register struct hci_conn *c;
+       struct hci_conn *c;
        struct hci_conn_list_req req, *cl;
        struct hci_conn_info *ci;
        struct hci_dev *hdev;
index 411ace8e647be4fad7281f6e24c847ad18b28bb8..08994ecc3b6a5e7cc168ee7cd957a38c49d2e579 100644 (file)
 
 /* Bluetooth HCI core. */
 
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-
-#include <linux/types.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/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/rfkill.h>
-#include <linux/timer.h>
-#include <linux/crypto.h>
-#include <net/sock.h>
+#include <linux/export.h>
+#include <linux/idr.h>
 
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/rfkill.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -65,6 +47,9 @@ DEFINE_RWLOCK(hci_dev_list_lock);
 LIST_HEAD(hci_cb_list);
 DEFINE_RWLOCK(hci_cb_list_lock);
 
+/* HCI ID Numbering */
+static DEFINE_IDA(hci_index_ida);
+
 /* ---- HCI notifications ---- */
 
 static void hci_notify(struct hci_dev *hdev, int event)
@@ -124,8 +109,9 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
 }
 
 /* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-                                       unsigned long opt, __u32 timeout)
+static int __hci_request(struct hci_dev *hdev,
+                        void (*req)(struct hci_dev *hdev, unsigned long opt),
+                        unsigned long opt, __u32 timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
        int err = 0;
@@ -166,8 +152,9 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
        return err;
 }
 
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-                                       unsigned long opt, __u32 timeout)
+static int hci_request(struct hci_dev *hdev,
+                      void (*req)(struct hci_dev *hdev, unsigned long opt),
+                      unsigned long opt, __u32 timeout)
 {
        int ret;
 
@@ -202,7 +189,7 @@ static void bredr_init(struct hci_dev *hdev)
        /* Mandatory initialization */
 
        /* Reset */
-       if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
                set_bit(HCI_RESET, &hdev->flags);
                hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
        }
@@ -235,7 +222,7 @@ static void bredr_init(struct hci_dev *hdev)
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
        /* Connection accept timeout ~20 secs */
-       param = cpu_to_le16(0x7d00);
+       param = __constant_cpu_to_le16(0x7d00);
        hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 
        bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -417,7 +404,8 @@ static void inquiry_cache_flush(struct hci_dev *hdev)
        INIT_LIST_HEAD(&cache->resolve);
 }
 
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
+                                              bdaddr_t *bdaddr)
 {
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
@@ -478,7 +466,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
 
        list_for_each_entry(p, &cache->resolve, list) {
                if (p->name_state != NAME_PENDING &&
-                               abs(p->data.rssi) >= abs(ie->data.rssi))
+                   abs(p->data.rssi) >= abs(ie->data.rssi))
                        break;
                pos = &p->list;
        }
@@ -503,7 +491,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
                        *ssp = true;
 
                if (ie->name_state == NAME_NEEDED &&
-                                               data->rssi != ie->data.rssi) {
+                   data->rssi != ie->data.rssi) {
                        ie->data.rssi = data->rssi;
                        hci_inquiry_cache_update_resolve(hdev, ie);
                }
@@ -527,7 +515,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
 update:
        if (name_known && ie->name_state != NAME_KNOWN &&
-                                       ie->name_state != NAME_PENDING) {
+           ie->name_state != NAME_PENDING) {
                ie->name_state = NAME_KNOWN;
                list_del(&ie->list);
        }
@@ -605,8 +593,7 @@ int hci_inquiry(void __user *arg)
 
        hci_dev_lock(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-                               inquiry_cache_empty(hdev) ||
-                               ir.flags & IREQ_CACHE_FLUSH) {
+           inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
                do_inquiry = 1;
        }
@@ -620,7 +607,9 @@ int hci_inquiry(void __user *arg)
                        goto done;
        }
 
-       /* for unlimited number of responses we will use buffer with 255 entries */
+       /* for unlimited number of responses we will use buffer with
+        * 255 entries
+        */
        max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
 
        /* cache_dump can't sleep. Therefore we allocate temp buffer and then
@@ -641,7 +630,7 @@ int hci_inquiry(void __user *arg)
        if (!copy_to_user(ptr, &ir, sizeof(ir))) {
                ptr += sizeof(ir);
                if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
-                                       ir.num_rsp))
+                                ir.num_rsp))
                        err = -EFAULT;
        } else
                err = -EFAULT;
@@ -702,11 +691,11 @@ int hci_dev_open(__u16 dev)
                hdev->init_last_cmd = 0;
 
                ret = __hci_request(hdev, hci_init_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                   msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                if (lmp_host_le_capable(hdev))
                        ret = __hci_request(hdev, hci_le_init_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                           msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
@@ -791,10 +780,10 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        skb_queue_purge(&hdev->cmd_q);
        atomic_set(&hdev->cmd_cnt, 1);
        if (!test_bit(HCI_RAW, &hdev->flags) &&
-                               test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+           test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
                set_bit(HCI_INIT, &hdev->flags);
                __hci_request(hdev, hci_reset_req, 0,
-                                       msecs_to_jiffies(250));
+                             msecs_to_jiffies(250));
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
@@ -884,7 +873,7 @@ int hci_dev_reset(__u16 dev)
 
        if (!test_bit(HCI_RAW, &hdev->flags))
                ret = __hci_request(hdev, hci_reset_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                   msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
 done:
        hci_req_unlock(hdev);
@@ -924,7 +913,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
        switch (cmd) {
        case HCISETAUTH:
                err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETENCRYPT:
@@ -936,23 +925,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
                if (!test_bit(HCI_AUTH, &hdev->flags)) {
                        /* Auth must be enabled first */
                        err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                         msecs_to_jiffies(HCI_INIT_TIMEOUT));
                        if (err)
                                break;
                }
 
                err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETSCAN:
                err = hci_request(hdev, hci_scan_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKPOL:
                err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKMODE:
@@ -1103,7 +1092,7 @@ static void hci_power_on(struct work_struct *work)
 
        if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                schedule_delayed_work(&hdev->power_off,
-                                       msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+                                     msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
@@ -1112,7 +1101,7 @@ static void hci_power_on(struct work_struct *work)
 static void hci_power_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                                       power_off.work);
+                                           power_off.work);
 
        BT_DBG("%s", hdev->name);
 
@@ -1193,7 +1182,7 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 }
 
 static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
-                                               u8 key_type, u8 old_key_type)
+                              u8 key_type, u8 old_key_type)
 {
        /* Legacy key */
        if (key_type < 0x03)
@@ -1234,7 +1223,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
        list_for_each_entry(k, &hdev->long_term_keys, list) {
                if (k->ediv != ediv ||
-                               memcmp(rand, k->rand, sizeof(k->rand)))
+                   memcmp(rand, k->rand, sizeof(k->rand)))
                        continue;
 
                return k;
@@ -1242,7 +1231,6 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
        return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk);
 
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                     u8 addr_type)
@@ -1251,12 +1239,11 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
        list_for_each_entry(k, &hdev->long_term_keys, list)
                if (addr_type == k->bdaddr_type &&
-                                       bacmp(bdaddr, &k->bdaddr) == 0)
+                   bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
 
        return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk_by_addr);
 
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
@@ -1283,15 +1270,14 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
         * combination key for legacy pairing even when there's no
         * previous key */
        if (type == HCI_LK_CHANGED_COMBINATION &&
-                                       (!conn || conn->remote_auth == 0xff) &&
-                                       old_key_type == 0xff) {
+           (!conn || conn->remote_auth == 0xff) && old_key_type == 0xff) {
                type = HCI_LK_COMBINATION;
                if (conn)
                        conn->key_type = type;
        }
 
        bacpy(&key->bdaddr, bdaddr);
-       memcpy(key->val, val, 16);
+       memcpy(key->val, val, HCI_LINK_KEY_SIZE);
        key->pin_len = pin_len;
 
        if (type == HCI_LK_CHANGED_COMBINATION)
@@ -1540,6 +1526,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
 
        memset(&cp, 0, sizeof(cp));
        cp.enable = 1;
+       cp.filter_dup = 1;
 
        hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 }
@@ -1707,41 +1694,39 @@ EXPORT_SYMBOL(hci_free_dev);
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
-       struct list_head *head, *p;
        int id, error;
 
        if (!hdev->open || !hdev->close)
                return -EINVAL;
 
-       write_lock(&hci_dev_list_lock);
-
        /* Do not allow HCI_AMP devices to register at index 0,
         * so the index can be used as the AMP controller ID.
         */
-       id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-       head = &hci_dev_list;
-
-       /* Find first available device id */
-       list_for_each(p, &hci_dev_list) {
-               int nid = list_entry(p, struct hci_dev, list)->id;
-               if (nid > id)
-                       break;
-               if (nid == id)
-                       id++;
-               head = p;
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL);
+               break;
+       case HCI_AMP:
+               id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL);
+               break;
+       default:
+               return -EINVAL;
        }
 
+       if (id < 0)
+               return id;
+
        sprintf(hdev->name, "hci%d", id);
        hdev->id = id;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       list_add(&hdev->list, head);
-
+       write_lock(&hci_dev_list_lock);
+       list_add(&hdev->list, &hci_dev_list);
        write_unlock(&hci_dev_list_lock);
 
        hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
-                                                       WQ_MEM_RECLAIM, 1);
+                                         WQ_MEM_RECLAIM, 1);
        if (!hdev->workqueue) {
                error = -ENOMEM;
                goto err;
@@ -1752,7 +1737,8 @@ int hci_register_dev(struct hci_dev *hdev)
                goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
-                               RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
+                                   RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
+                                   hdev);
        if (hdev->rfkill) {
                if (rfkill_register(hdev->rfkill) < 0) {
                        rfkill_destroy(hdev->rfkill);
@@ -1772,6 +1758,7 @@ int hci_register_dev(struct hci_dev *hdev)
 err_wqueue:
        destroy_workqueue(hdev->workqueue);
 err:
+       ida_simple_remove(&hci_index_ida, hdev->id);
        write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
@@ -1783,12 +1770,14 @@ EXPORT_SYMBOL(hci_register_dev);
 /* Unregister HCI device */
 void hci_unregister_dev(struct hci_dev *hdev)
 {
-       int i;
+       int i, id;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
        set_bit(HCI_UNREGISTER, &hdev->dev_flags);
 
+       id = hdev->id;
+
        write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
@@ -1799,7 +1788,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
                kfree_skb(hdev->reassembly[i]);
 
        if (!test_bit(HCI_INIT, &hdev->flags) &&
-                               !test_bit(HCI_SETUP, &hdev->dev_flags)) {
+           !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                hci_dev_lock(hdev);
                mgmt_index_removed(hdev);
                hci_dev_unlock(hdev);
@@ -1829,6 +1818,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_unlock(hdev);
 
        hci_dev_put(hdev);
+
+       ida_simple_remove(&hci_index_ida, id);
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1853,7 +1844,7 @@ int hci_recv_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
        if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
-                               && !test_bit(HCI_INIT, &hdev->flags))) {
+                     && !test_bit(HCI_INIT, &hdev->flags))) {
                kfree_skb(skb);
                return -ENXIO;
        }
@@ -1872,7 +1863,7 @@ int hci_recv_frame(struct sk_buff *skb)
 EXPORT_SYMBOL(hci_recv_frame);
 
 static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
-                                                 int count, __u8 index)
+                         int count, __u8 index)
 {
        int len = 0;
        int hlen = 0;
@@ -1881,7 +1872,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
        struct bt_skb_cb *scb;
 
        if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
-                               index >= NUM_REASSEMBLY)
+           index >= NUM_REASSEMBLY)
                return -EILSEQ;
 
        skb = hdev->reassembly[index];
@@ -2023,7 +2014,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
                        type = bt_cb(skb)->pkt_type;
 
                rem = hci_reassembly(hdev, type, data, count,
-                                                       STREAM_REASSEMBLY);
+                                    STREAM_REASSEMBLY);
                if (rem < 0)
                        return rem;
 
@@ -2157,7 +2148,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 }
 
 static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
-                               struct sk_buff *skb, __u16 flags)
+                         struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
@@ -2216,7 +2207,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
@@ -2239,12 +2229,12 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
        skb_queue_tail(&conn->data_q, skb);
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_sco);
 
 /* ---- HCI TX task (outgoing data) ---- */
 
 /* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
+                                    int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_conn *conn = NULL, *c;
@@ -2303,7 +2293,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
        return conn;
 }
 
-static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
+static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_conn *c;
@@ -2316,16 +2306,16 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
-                               hdev->name, batostr(&c->dst));
-                       hci_acl_disconn(c, 0x13);
+                              hdev->name, batostr(&c->dst));
+                       hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
                }
        }
 
        rcu_read_unlock();
 }
 
-static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
-                                               int *quote)
+static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+                                     int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_chan *chan = NULL;
@@ -2442,7 +2432,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
                        skb->priority = HCI_PRIO_MAX - 1;
 
                        BT_DBG("chan %p skb %p promoted to %d", chan, skb,
-                                                               skb->priority);
+                              skb->priority);
                }
 
                if (hci_conn_num(hdev, type) == num)
@@ -2459,18 +2449,18 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
        return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
 }
 
-static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
+static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
 {
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
                if (!cnt && time_after(jiffies, hdev->acl_last_tx +
-                                       msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
+                                      msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
                        hci_link_tx_to(hdev, ACL_LINK);
        }
 }
 
-static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
+static void hci_sched_acl_pkt(struct hci_dev *hdev)
 {
        unsigned int cnt = hdev->acl_cnt;
        struct hci_chan *chan;
@@ -2480,11 +2470,11 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
        __check_timeout(hdev, cnt);
 
        while (hdev->acl_cnt &&
-                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote-- && (skb = skb_peek(&chan->data_q))) {
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                       skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2508,7 +2498,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
                hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl_blk(struct hci_dev *hdev)
+static void hci_sched_acl_blk(struct hci_dev *hdev)
 {
        unsigned int cnt = hdev->block_cnt;
        struct hci_chan *chan;
@@ -2518,13 +2508,13 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
        __check_timeout(hdev, cnt);
 
        while (hdev->block_cnt > 0 &&
-                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
                        int blocks;
 
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                               skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2537,7 +2527,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
                                return;
 
                        hci_conn_enter_active_mode(chan->conn,
-                                               bt_cb(skb)->force_active);
+                                                  bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
@@ -2554,7 +2544,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
                hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static void hci_sched_acl(struct hci_dev *hdev)
 {
        BT_DBG("%s", hdev->name);
 
@@ -2573,7 +2563,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 }
 
 /* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
+static void hci_sched_sco(struct hci_dev *hdev)
 {
        struct hci_conn *conn;
        struct sk_buff *skb;
@@ -2596,7 +2586,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
        }
 }
 
-static inline void hci_sched_esco(struct hci_dev *hdev)
+static void hci_sched_esco(struct hci_dev *hdev)
 {
        struct hci_conn *conn;
        struct sk_buff *skb;
@@ -2607,7 +2597,8 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
        if (!hci_conn_num(hdev, ESCO_LINK))
                return;
 
-       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
+                                                    &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
                        hci_send_frame(skb);
@@ -2619,7 +2610,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
        }
 }
 
-static inline void hci_sched_le(struct hci_dev *hdev)
+static void hci_sched_le(struct hci_dev *hdev)
 {
        struct hci_chan *chan;
        struct sk_buff *skb;
@@ -2634,7 +2625,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
                /* LE tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
                if (!hdev->le_cnt && hdev->le_pkts &&
-                               time_after(jiffies, hdev->le_last_tx + HZ * 45))
+                   time_after(jiffies, hdev->le_last_tx + HZ * 45))
                        hci_link_tx_to(hdev, LE_LINK);
        }
 
@@ -2644,7 +2635,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote-- && (skb = skb_peek(&chan->data_q))) {
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                       skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2676,7 +2667,7 @@ static void hci_tx_work(struct work_struct *work)
        struct sk_buff *skb;
 
        BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
-               hdev->sco_cnt, hdev->le_cnt);
+              hdev->sco_cnt, hdev->le_cnt);
 
        /* Schedule queues and send stuff to HCI driver */
 
@@ -2696,7 +2687,7 @@ static void hci_tx_work(struct work_struct *work)
 /* ----- HCI RX task (incoming data processing) ----- */
 
 /* ACL data packet */
-static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_acl_hdr *hdr = (void *) skb->data;
        struct hci_conn *conn;
@@ -2708,7 +2699,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        flags  = hci_flags(handle);
        handle = hci_handle(handle);
 
-       BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+       BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len,
+              handle, flags);
 
        hdev->stat.acl_rx++;
 
@@ -2732,14 +2724,14 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        } else {
                BT_ERR("%s ACL packet for unknown connection handle %d",
-                       hdev->name, handle);
+                      hdev->name, handle);
        }
 
        kfree_skb(skb);
 }
 
 /* SCO data packet */
-static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_sco_hdr *hdr = (void *) skb->data;
        struct hci_conn *conn;
@@ -2763,7 +2755,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        } else {
                BT_ERR("%s SCO packet for unknown connection handle %d",
-                       hdev->name, handle);
+                      hdev->name, handle);
        }
 
        kfree_skb(skb);
index 4eefb7f65cf62e6409fb5b67d0fed541eed5b541..1ba929c05d0da41c7c584a9166383a4f29f169da 100644 (file)
 
 /* 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>
@@ -95,7 +82,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        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);
 }
@@ -166,7 +154,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        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;
 
@@ -178,7 +167,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk
        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;
@@ -329,7 +319,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
                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);
@@ -358,7 +348,7 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
        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)
@@ -406,7 +396,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
                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;
@@ -473,7 +464,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
                return 1;
 
        if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
-                                               hdev->lmp_subver == 0x0757)
+           hdev->lmp_subver == 0x0757)
                return 1;
 
        if (hdev->manufacturer == 15) {
@@ -486,7 +477,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
        }
 
        if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
-                                               hdev->lmp_subver == 0x1805)
+           hdev->lmp_subver == 0x1805)
                return 1;
 
        return 0;
@@ -566,7 +557,7 @@ static void hci_setup(struct hci_dev *hdev)
        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,
@@ -618,8 +609,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
        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);
@@ -646,7 +636,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
        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;
 
@@ -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;
 
@@ -713,10 +705,10 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
                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)
@@ -736,7 +728,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;
 
@@ -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;
 
@@ -798,9 +790,8 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
        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)
@@ -816,7 +807,7 @@ 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;
 
@@ -832,7 +823,7 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
        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);
 }
@@ -847,7 +838,7 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 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;
 
@@ -871,7 +862,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 }
 
 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);
 
@@ -890,7 +881,7 @@ static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                     struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
 
@@ -900,7 +891,7 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
 }
 
 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;
 
@@ -959,7 +950,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        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);
 }
@@ -1000,7 +991,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 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;
 
@@ -1031,7 +1022,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 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;
 
@@ -1047,7 +1038,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 }
 
 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;
 
@@ -1076,7 +1067,7 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 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);
@@ -1156,8 +1147,8 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
        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);
@@ -1176,13 +1167,13 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        }
 
        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);
 
@@ -1203,7 +1194,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 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;
@@ -1333,7 +1324,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
 }
 
 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;
@@ -1343,15 +1334,14 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 
        /* 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;
@@ -1638,7 +1628,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
        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) {
@@ -1668,7 +1658,7 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
        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;
@@ -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);
@@ -1745,7 +1735,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
        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;
@@ -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;
@@ -1845,7 +1835,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                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) {
@@ -1878,9 +1869,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        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;
 
@@ -1897,7 +1888,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
        }
 }
 
-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;
@@ -1914,10 +1905,10 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
                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);
@@ -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;
@@ -1949,7 +1940,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
        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;
@@ -1969,7 +1960,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        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);
@@ -1989,7 +1980,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        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);
@@ -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;
@@ -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;
@@ -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;
@@ -2104,7 +2096,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
        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;
@@ -2128,7 +2121,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
                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;
        }
 
@@ -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;
@@ -2384,7 +2378,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
        }
 }
 
-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;
@@ -2465,7 +2459,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-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;
@@ -2491,7 +2485,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
        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;
@@ -2502,7 +2496,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        }
 
        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;
        }
@@ -2557,8 +2551,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        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;
@@ -2569,13 +2562,13 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
        }
 
        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];
@@ -2607,7 +2600,7 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
        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;
@@ -2621,7 +2614,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
                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
@@ -2635,7 +2629,7 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
        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;
@@ -2656,7 +2650,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 
        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;
 
@@ -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;
@@ -2689,15 +2683,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        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;
        }
@@ -2705,16 +2699,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        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;
                }
 
@@ -2723,7 +2716,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        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);
 
@@ -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;
@@ -2760,12 +2753,12 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 
        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;
@@ -2788,7 +2781,7 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        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;
@@ -2804,7 +2797,7 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff
        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;
@@ -2822,7 +2815,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
        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);
@@ -2881,7 +2875,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
        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;
@@ -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;
@@ -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);
@@ -3043,7 +3040,51 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        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) {
@@ -3062,7 +3103,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
        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;
@@ -3081,7 +3122,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                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);
@@ -3092,14 +3133,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                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;
 
@@ -3107,14 +3148,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                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;
@@ -3136,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;
@@ -3165,13 +3206,13 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        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
@@ -3183,7 +3224,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
                }
 
                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);
@@ -3192,7 +3233,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
                }
 
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
-                                               sizeof(ev->bdaddr), &ev->bdaddr);
+                            sizeof(ev->bdaddr), &ev->bdaddr);
                goto unlock;
        }
 
@@ -3204,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;
 
@@ -3219,7 +3260,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
        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;
@@ -3247,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;
@@ -3263,8 +3306,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
        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;
@@ -3285,20 +3328,20 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
                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;
@@ -3307,6 +3350,19 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        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);
@@ -3319,15 +3375,6 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
                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);
@@ -3345,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];
@@ -3367,8 +3413,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
        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;
@@ -3411,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;
 
@@ -3559,6 +3604,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                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 5914623f426aa835aadee48c6ec8eb8400ab7728..a7f04de03d7916add5a20cf44d8e88e5daad495d 100644 (file)
 
 /* Bluetooth HCI sockets. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.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/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/compat.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
+#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -113,11 +95,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                flt = &hci_pi(sk)->filter;
 
                if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
-                               0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+                             0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
+                             &flt->type_mask))
                        continue;
 
                if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
-                       register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
+                       int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 
                        if (!hci_test_bit(evt, &flt->event_mask))
                                continue;
@@ -240,7 +223,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
                        struct hci_mon_hdr *hdr;
 
                        /* Create a private copy with headroom */
-                       skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
+                       skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE,
+                                              GFP_ATOMIC);
                        if (!skb_copy)
                                continue;
 
@@ -495,7 +479,8 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 }
 
 /* Ioctls that require bound socket */
-static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
+                               unsigned long arg)
 {
        struct hci_dev *hdev = hci_pi(sk)->hdev;
 
@@ -540,7 +525,8 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
        }
 }
 
-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
 {
        struct sock *sk = sock->sk;
        void __user *argp = (void __user *) arg;
@@ -601,7 +587,8 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
        }
 }
 
-static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
+                        int addr_len)
 {
        struct sockaddr_hci haddr;
        struct sock *sk = sock->sk;
@@ -690,7 +677,8 @@ done:
        return err;
 }
 
-static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
+                           int *addr_len, int peer)
 {
        struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
        struct sock *sk = sock->sk;
@@ -711,13 +699,15 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add
        return 0;
 }
 
-static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
+                         struct sk_buff *skb)
 {
        __u32 mask = hci_pi(sk)->cmsg_mask;
 
        if (mask & HCI_CMSG_DIR) {
                int incoming = bt_cb(skb)->incoming;
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming),
+                        &incoming);
        }
 
        if (mask & HCI_CMSG_TSTAMP) {
@@ -747,7 +737,7 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 }
 
 static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-                               struct msghdr *msg, size_t len, int flags)
+                           struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -857,8 +847,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                u16 ocf = hci_opcode_ocf(opcode);
 
                if (((ogf > HCI_SFLT_MAX_OGF) ||
-                               !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-                                       !capable(CAP_NET_RAW)) {
+                    !hci_test_bit(ocf & HCI_FLT_OCF_BITS,
+                                  &hci_sec_filter.ocf_mask[ogf])) &&
+                   !capable(CAP_NET_RAW)) {
                        err = -EPERM;
                        goto drop;
                }
@@ -891,7 +882,8 @@ drop:
        goto done;
 }
 
-static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
+static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, unsigned int len)
 {
        struct hci_ufilter uf = { .opcode = 0 };
        struct sock *sk = sock->sk;
@@ -973,7 +965,8 @@ done:
        return err;
 }
 
-static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int __user *optlen)
 {
        struct hci_ufilter uf;
        struct sock *sk = sock->sk;
index 937f3187eafa51bbb540db6352535cfb4a30485e..a20e61c3653dbf84f3c567977757f61239fd2a82 100644 (file)
@@ -1,10 +1,6 @@
 /* Bluetooth HCI driver model support. */
 
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
 #include <linux/module.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -31,27 +27,30 @@ static inline char *link_typetostr(int type)
        }
 }
 
-static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_type(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", link_typetostr(conn->type));
 }
 
-static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_address(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", batostr(&conn->dst));
 }
 
-static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_features(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                               conn->features[0], conn->features[1],
-                               conn->features[2], conn->features[3],
-                               conn->features[4], conn->features[5],
-                               conn->features[6], conn->features[7]);
+                      conn->features[0], conn->features[1],
+                      conn->features[2], conn->features[3],
+                      conn->features[4], conn->features[5],
+                      conn->features[6], conn->features[7]);
 }
 
 #define LINK_ATTR(_name, _mode, _show, _store) \
@@ -185,19 +184,22 @@ static inline char *host_typetostr(int type)
        }
 }
 
-static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_bus(struct device *dev,
+                       struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 }
 
-static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_type(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 }
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        char name[HCI_MAX_NAME_LENGTH + 1];
@@ -210,55 +212,64 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
        return sprintf(buf, "%s\n", name);
 }
 
-static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_class(struct device *dev,
+                         struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
-       return sprintf(buf, "0x%.2x%.2x%.2x\n",
-                       hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+       return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
+                      hdev->dev_class[1], hdev->dev_class[0]);
 }
 
-static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_address(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 }
 
-static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_features(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                               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 ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_manufacturer(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->manufacturer);
 }
 
-static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_version(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_ver);
 }
 
-static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_revision(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_rev);
 }
 
-static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_idle_timeout(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->idle_timeout);
 }
 
-static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_idle_timeout(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        unsigned int val;
@@ -276,13 +287,16 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
        return count;
 }
 
-static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_max_interval(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 }
 
-static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_max_interval(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
@@ -300,13 +314,16 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
        return count;
 }
 
-static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_min_interval(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 }
 
-static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_min_interval(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
@@ -335,11 +352,11 @@ static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
 
 static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
-                               show_idle_timeout, store_idle_timeout);
+                  show_idle_timeout, store_idle_timeout);
 static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
-                               show_sniff_max_interval, store_sniff_max_interval);
+                  show_sniff_max_interval, store_sniff_max_interval);
 static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
-                               show_sniff_min_interval, store_sniff_min_interval);
+                  show_sniff_min_interval, store_sniff_min_interval);
 
 static struct attribute *bt_host_attrs[] = {
        &dev_attr_bus.attr,
@@ -455,8 +472,8 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
        memcpy(&data5, &uuid[14], 2);
 
        seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
-                               ntohl(data0), ntohs(data1), ntohs(data2),
-                               ntohs(data3), ntohl(data4), ntohs(data5));
+                  ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3),
+                  ntohl(data4), ntohs(data5));
 }
 
 static int uuids_show(struct seq_file *f, void *p)
@@ -513,7 +530,7 @@ static int auto_accept_delay_get(void *data, u64 *val)
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
-                                       auto_accept_delay_set, "%llu\n");
+                       auto_accept_delay_set, "%llu\n");
 
 void hci_init_sysfs(struct hci_dev *hdev)
 {
@@ -547,15 +564,15 @@ int hci_add_sysfs(struct hci_dev *hdev)
                return 0;
 
        debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
-                                               hdev, &inquiry_cache_fops);
+                           hdev, &inquiry_cache_fops);
 
        debugfs_create_file("blacklist", 0444, hdev->debugfs,
-                                               hdev, &blacklist_fops);
+                           hdev, &blacklist_fops);
 
        debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
 
        debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
-                                               &auto_accept_delay_fops);
+                           &auto_accept_delay_fops);
        return 0;
 }
 
index 2c20d765b394841bf878c331b4f7c69a897e6e28..ccd985da65180656d7df83a986655c4b82258220 100644 (file)
 */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/freezer.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/input.h>
-#include <linux/hid.h>
 #include <linux/hidraw.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -244,7 +225,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 }
 
 static int __hidp_send_ctrl_message(struct hidp_session *session,
-                       unsigned char hdr, unsigned char *data, int size)
+                                   unsigned char hdr, unsigned char *data,
+                                   int size)
 {
        struct sk_buff *skb;
 
@@ -268,7 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
        return 0;
 }
 
-static inline int hidp_send_ctrl_message(struct hidp_session *session,
+static int hidp_send_ctrl_message(struct hidp_session *session,
                        unsigned char hdr, unsigned char *data, int size)
 {
        int err;
@@ -471,7 +453,7 @@ static void hidp_set_timer(struct hidp_session *session)
                mod_timer(&session->timer, jiffies + HZ * session->idle_to);
 }
 
-static inline void hidp_del_timer(struct hidp_session *session)
+static void hidp_del_timer(struct hidp_session *session)
 {
        if (session->idle_to > 0)
                del_timer(&session->timer);
index 73a32d705c1fc14f423c5178c367ee4064cd9284..18b3f6892a36847de621954cbae7358ae719c0be 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <net/sock.h>
 
 #include "hidp.h"
 
index 24f144b72a96a87ee5f8fdc2016f613f00615344..4ca88247b7c25595b8a1c05141e74be4e714a641 100644 (file)
 
 #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;
 
@@ -73,6 +55,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                   struct l2cap_chan *chan, int err);
 
+static 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)
@@ -196,7 +181,7 @@ static void __l2cap_state_change(struct l2cap_chan *chan, int state)
                                                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)
@@ -224,6 +209,37 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
        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
@@ -366,7 +382,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        mutex_unlock(&conn->chan_lock);
 
        l2cap_chan_put(chan);
@@ -392,6 +408,9 @@ struct l2cap_chan *l2cap_chan_create(void)
 
        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;
@@ -430,7 +449,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        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 {
@@ -447,6 +466,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                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;
@@ -466,18 +492,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        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);
 
@@ -490,34 +514,22 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
                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);
@@ -526,30 +538,15 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
                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)
@@ -562,12 +559,8 @@ 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:
@@ -595,7 +588,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                        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);
                }
@@ -609,9 +602,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
-               lock_sock(sk);
-               sock_set_flag(sk, SOCK_ZAPPED);
-               release_sock(sk);
+               if (chan->ops->teardown)
+                       chan->ops->teardown(chan, 0);
                break;
        }
 }
@@ -627,7 +619,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                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;
 
@@ -773,9 +765,11 @@ static inline void __unpack_control(struct l2cap_chan *chan,
        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);
        }
 }
 
@@ -830,66 +824,102 @@ static inline void __pack_control(struct l2cap_chan *chan,
        }
 }
 
-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)
@@ -914,25 +944,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
 
 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)
@@ -953,7 +971,7 @@ 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);
@@ -995,6 +1013,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
                __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),
@@ -1053,20 +1076,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                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,
@@ -1150,13 +1173,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        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;
 
@@ -1171,10 +1188,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        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);
@@ -1198,6 +1212,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
                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);
@@ -1270,7 +1289,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
                l2cap_chan_unlock(chan);
 
-               chan->ops->close(chan->data);
+               chan->ops->close(chan);
                l2cap_chan_put(chan);
        }
 
@@ -1295,7 +1314,12 @@ static void security_timeout(struct work_struct *work)
        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)
@@ -1439,21 +1463,17 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                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:
@@ -1463,13 +1483,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
        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;
@@ -1571,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);
 }
@@ -1595,234 +1611,293 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 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;
-
-               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++;
+               BT_DBG("Resent txseq %d", control.txseq);
 
-               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,
@@ -1951,10 +2026,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        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;
@@ -1974,7 +2046,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        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));
@@ -1985,9 +2061,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                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;
 }
@@ -1999,7 +2073,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        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);
@@ -2015,7 +2088,10 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        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);
@@ -2055,7 +2131,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
                }
        }
 
-       return err;
+       return 0;
 }
 
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
@@ -2117,17 +2193,12 @@ 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.
@@ -2143,6 +2214,296 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
        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)
 {
@@ -2165,7 +2526,7 @@ 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);
        }
 
@@ -2195,9 +2556,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
        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;
@@ -2309,8 +2670,8 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
                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:
@@ -2333,20 +2694,24 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
 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;
 
@@ -2355,7 +2720,6 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
        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;
@@ -2376,12 +2740,15 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
 
        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)
@@ -2507,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;
@@ -2537,7 +2905,7 @@ done:
        }
 
        req->dcid  = cpu_to_le16(chan->dcid);
-       req->flags = cpu_to_le16(0);
+       req->flags = __constant_cpu_to_le16(0);
 
        return ptr - data;
 }
@@ -2757,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;
 }
@@ -2856,7 +3224,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        }
 
        req->dcid   = cpu_to_le16(chan->dcid);
-       req->flags  = cpu_to_le16(0x0000);
+       req->flags  = __constant_cpu_to_le16(0);
 
        return ptr - data;
 }
@@ -2883,8 +3251,8 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
 
        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);
 
@@ -2922,8 +3290,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
         * 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");
@@ -2986,7 +3354,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        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;
@@ -2995,25 +3363,16 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        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);
@@ -3067,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);
@@ -3189,7 +3548,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        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);
 
@@ -3211,11 +3570,11 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        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;
        }
 
@@ -3238,8 +3597,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        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);
@@ -3271,7 +3628,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
                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:
@@ -3362,7 +3719,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                goto done;
        }
 
-       if (flags & 0x01)
+       if (flags & L2CAP_CONF_FLAG_CONTINUATION)
                goto done;
 
        set_bit(CONF_INPUT_DONE, &chan->conf_state);
@@ -3370,7 +3727,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        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);
@@ -3424,7 +3780,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        l2cap_chan_put(chan);
 
        mutex_unlock(&conn->chan_lock);
@@ -3458,7 +3814,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        l2cap_chan_put(chan);
 
        mutex_unlock(&conn->chan_lock);
@@ -3479,8 +3835,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                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;
@@ -3500,15 +3856,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                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);
        }
@@ -3548,7 +3904,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
                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);
 
@@ -3783,9 +4139,9 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
        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);
@@ -3933,7 +4289,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                        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);
                }
 
@@ -3965,65 +4321,38 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
        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,
@@ -4045,16 +4374,17 @@ 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:
@@ -4104,7 +4434,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
                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 */
@@ -4126,448 +4456,609 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
        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);
 
-       return 0;
+       l2cap_pass_to_tx(chan, control);
+
+       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);
 
-                       list_for_each_entry(l, &chan->srej_l, list) {
-                               if (l->tx_seq == tx_seq) {
-                                       l2cap_resend_srejframe(chan, tx_seq);
-                                       return 0;
+                       chan->buffer_seq = chan->expected_tx_seq;
+                       skb_in_use = 1;
+
+                       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;
+                       /* 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));
 
-               set_bit(CONN_SREJ_SENT, &chan->conn_state);
-
-               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);
                }
+               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;
        }
-       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;
-       }
-
-       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);
+       /* Make sure reqseq is for a packet that has been sent but not acked */
+       u16 unacked;
 
-       chan->expected_ack_seq = tx_seq;
-       l2cap_drop_acked_frames(chan);
-
-       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;
+       chan->last_acked_seq = control->txseq;
+       chan->expected_tx_seq = __next_seq(chan, control->txseq);
 
-       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;
-       }
-
-       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)
@@ -4578,34 +5069,57 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
                goto drop;
        }
 
-       req_seq = __get_reqseq(chan, control);
-
-       req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
+       if (!control->sframe) {
+               int err;
 
-       next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
-                                               chan->expected_ack_seq);
+               BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d",
+                      control->sar, control->reqseq, control->final,
+                      control->txseq);
 
-       /* check for invalid req-seq */
-       if (req_seq_offset > next_tx_seq_offset) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-               goto drop;
-       }
-
-       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;
@@ -4615,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);
@@ -4645,49 +5167,13 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                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:
@@ -4700,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;
 
@@ -4720,17 +5205,15 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
        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;
 
@@ -4746,13 +5229,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
        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)
@@ -4780,7 +5261,7 @@ 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;
 
@@ -4974,6 +5455,17 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        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);
index 3bb1611b9d487c1c8406748d069af917d269b86c..a4bb27e8427e9aabaa48b90727cb23bcf5568f96 100644 (file)
@@ -27,7 +27,6 @@
 
 /* Bluetooth L2CAP sockets. */
 
-#include <linux/security.h>
 #include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (err < 0)
                goto done;
 
-       if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
-                               __le16_to_cpu(la.l2_psm) == 0x0003)
+       if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
+           __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
                chan->sec_level = BT_SECURITY_SDP;
 
        bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
@@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
+static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
+{
+       switch (chan->scid) {
+       case L2CAP_CID_LE_DATA:
+               if (mtu < L2CAP_LE_MIN_MTU)
+                       return false;
+               break;
+
+       default:
+               if (mtu < L2CAP_DEFAULT_MIN_MTU)
+                       return false;
+       }
+
+       return true;
+}
+
 static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
@@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
+               if (!l2cap_valid_mtu(chan, opts.imtu)) {
+                       err = -EINVAL;
+                       break;
+               }
+
                chan->mode = opts.mode;
                switch (chan->mode) {
                case L2CAP_MODE_BASIC:
@@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock)
        return err;
 }
 
-static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
+static void l2cap_sock_cleanup_listen(struct sock *parent)
 {
-       struct sock *sk, *parent = data;
+       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);
+
+               l2cap_sock_kill(sk);
+       }
+}
+
+static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk, *parent = chan->data;
+
+       /* Check for backlog size */
+       if (sk_acceptq_is_full(parent)) {
+               BT_DBG("backlog full %d", parent->sk_ack_backlog);
+               return NULL;
+       }
 
        sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
                                                                GFP_ATOMIC);
@@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
        return l2cap_pi(sk)->chan;
 }
 
-static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
+static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
        int err;
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
 
        lock_sock(sk);
@@ -925,16 +970,57 @@ done:
        return err;
 }
 
-static void l2cap_sock_close_cb(void *data)
+static void l2cap_sock_close_cb(struct l2cap_chan *chan)
 {
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
 
        l2cap_sock_kill(sk);
 }
 
-static void l2cap_sock_state_change_cb(void *data, int state)
+static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
 {
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
+
+       sock_set_flag(sk, SOCK_ZAPPED);
+
+       switch (chan->state) {
+       case BT_OPEN:
+       case BT_BOUND:
+       case BT_CLOSED:
+               break;
+       case BT_LISTEN:
+               l2cap_sock_cleanup_listen(sk);
+               sk->sk_state = BT_CLOSED;
+               chan->state = BT_CLOSED;
+
+               break;
+       default:
+               sk->sk_state = BT_CLOSED;
+               chan->state = BT_CLOSED;
+
+               sk->sk_err = err;
+
+               if (parent) {
+                       bt_accept_unlink(sk);
+                       parent->sk_data_ready(parent, 0);
+               } else {
+                       sk->sk_state_change(sk);
+               }
+
+               break;
+       }
+
+       release_sock(sk);
+}
+
+static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state)
+{
+       struct sock *sk = chan->data;
 
        sk->sk_state = state;
 }
@@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
        return skb;
 }
 
+static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk = chan->data;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
+
+       BT_DBG("sk %p, parent %p", sk, parent);
+
+       sk->sk_state = BT_CONNECTED;
+       sk->sk_state_change(sk);
+
+       if (parent)
+               parent->sk_data_ready(parent, 0);
+
+       release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
        .recv           = l2cap_sock_recv_cb,
        .close          = l2cap_sock_close_cb,
+       .teardown       = l2cap_sock_teardown_cb,
        .state_change   = l2cap_sock_state_change_cb,
+       .ready          = l2cap_sock_ready_cb,
        .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
index 506628876f3604dcdf9530852e6a27095dbf1f21..e1c97527e16ca352d4e55016b3a1f70b3e40d5b6 100644 (file)
 
 #define pr_fmt(fmt) "Bluetooth: " fmt
 
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <asm/errno.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 
index 25d22077607963d66a73cca2d644d4df468fa78f..c72307cc25fc7af2fc679203ef19f29142d17a2f 100644 (file)
@@ -24,8 +24,6 @@
 
 /* Bluetooth HCI Management interface */
 
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
 #include <linux/module.h>
 #include <asm/unaligned.h>
 
@@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 }
 
 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;
@@ -871,7 +870,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        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;
@@ -978,7 +977,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        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;
@@ -1001,7 +1000,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                scan = 0;
 
                if (test_bit(HCI_ISCAN, &hdev->flags) &&
-                                               hdev->discov_timeout > 0)
+                   hdev->discov_timeout > 0)
                        cancel_delayed_work(&hdev->discov_off);
        }
 
@@ -1056,7 +1055,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
                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;
                }
@@ -1317,7 +1316,7 @@ static bool enable_service_cache(struct hci_dev *hdev)
 }
 
 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;
@@ -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;
@@ -1454,13 +1453,13 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
                                        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);
 
@@ -1535,10 +1534,10 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        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;
        }
@@ -1594,7 +1593,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        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 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
        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);
 
@@ -1821,7 +1821,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
                            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 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
                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)
 {
@@ -1911,8 +1927,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        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;
        }
@@ -1934,6 +1957,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        /* 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;
@@ -1941,7 +1966,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        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;
@@ -2238,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;
@@ -2407,7 +2432,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
 
        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,
@@ -2629,7 +2654,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                                        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);
        }
@@ -2754,7 +2779,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        }
 
        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);
@@ -2762,7 +2787,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        }
 
        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;
@@ -2771,7 +2796,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        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;
@@ -2955,7 +2980,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
        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);
@@ -3090,7 +3115,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
        mgmt_pending_remove(cmd);
 
        mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
-                                                                       hdev);
+                            hdev);
        return err;
 }
 
@@ -3180,7 +3205,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 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;
 
@@ -3194,8 +3219,8 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 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;
@@ -3226,7 +3251,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                         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,
@@ -3240,7 +3266,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                         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,
index 8a602388f1e73c185aa24499e9ff636c9358fcee..c75107ef89204877315ea8d61248c2fa4e2bddd2 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/net.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -115,14 +101,14 @@ static void rfcomm_session_del(struct rfcomm_session *s);
 #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
 #define __get_rpn_parity(line)    (((line) >> 3) & 0x7)
 
-static inline void rfcomm_schedule(void)
+static void rfcomm_schedule(void)
 {
        if (!rfcomm_thread)
                return;
        wake_up_process(rfcomm_thread);
 }
 
-static inline void rfcomm_session_put(struct rfcomm_session *s)
+static void rfcomm_session_put(struct rfcomm_session *s)
 {
        if (atomic_dec_and_test(&s->refcnt))
                rfcomm_session_del(s);
@@ -227,7 +213,7 @@ static int rfcomm_l2sock_create(struct socket **sock)
        return err;
 }
 
-static inline int rfcomm_check_security(struct rfcomm_dlc *d)
+static int rfcomm_check_security(struct rfcomm_dlc *d)
 {
        struct sock *sk = d->session->sock->sk;
        struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
@@ -1750,7 +1736,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
 /* Send data queued for the DLC.
  * Return number of frames left in the queue.
  */
-static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
+static int rfcomm_process_tx(struct rfcomm_dlc *d)
 {
        struct sk_buff *skb;
        int err;
@@ -1798,7 +1784,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
        return skb_queue_len(&d->tx_queue);
 }
 
-static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+static void rfcomm_process_dlcs(struct rfcomm_session *s)
 {
        struct rfcomm_dlc *d;
        struct list_head *p, *n;
@@ -1858,7 +1844,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_process_rx(struct rfcomm_session *s)
+static void rfcomm_process_rx(struct rfcomm_session *s)
 {
        struct socket *sock = s->sock;
        struct sock *sk = sock->sk;
@@ -1883,7 +1869,7 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_accept_connection(struct rfcomm_session *s)
+static void rfcomm_accept_connection(struct rfcomm_session *s)
 {
        struct socket *sock = s->sock, *nsock;
        int err;
@@ -1917,7 +1903,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
                sock_release(nsock);
 }
 
-static inline void rfcomm_check_connection(struct rfcomm_session *s)
+static void rfcomm_check_connection(struct rfcomm_session *s)
 {
        struct sock *sk = s->sock->sk;
 
@@ -1941,7 +1927,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_process_sessions(void)
+static void rfcomm_process_sessions(void)
 {
        struct list_head *p, *n;
 
index e8707debb8642cff6cc08755a6400134bcf5b8c7..7e1e59645c056f71400ad9ed4dc0444548c41951 100644 (file)
  * RFCOMM sockets.
  */
 
-#include <linux/module.h>
-
-#include <linux/types.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/export.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
index d1820ff14aee46cfc55cd1c169495004c3130818..cb960773c002efafeb45b888ee8f3ba3e9208490 100644 (file)
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 
-#include <linux/capability.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/rfcomm.h>
@@ -132,7 +127,7 @@ static struct rfcomm_dev *__rfcomm_dev_get(int id)
        return NULL;
 }
 
-static inline struct rfcomm_dev *rfcomm_dev_get(int id)
+static struct rfcomm_dev *rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
 
@@ -345,7 +340,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
        tty_port_put(&dev->port);
 }
 
-static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
+static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
        tty_port_get(&dev->port);
        atomic_add(skb->truesize, &dev->wmem_alloc);
index cbdd313659a78f3bf9133d10ee01e487fd2d9053..40bbe25dcff7f97c9a279c6d087eaed078563364 100644 (file)
 /* Bluetooth SCO sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.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/device.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/list.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -123,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
        return conn;
 }
 
-static inline struct sock *sco_chan_get(struct sco_conn *conn)
+static struct sock *sco_chan_get(struct sco_conn *conn)
 {
        struct sock *sk = NULL;
        sco_conn_lock(conn);
@@ -157,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        return 0;
 }
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+                       struct sock *parent)
 {
        int err = 0;
 
@@ -228,7 +211,7 @@ done:
        return err;
 }
 
-static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 {
        struct sco_conn *conn = sco_pi(sk)->conn;
        struct sk_buff *skb;
@@ -254,7 +237,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
        return len;
 }
 
-static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 {
        struct sock *sk = sco_chan_get(conn);
 
@@ -523,7 +506,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
                goto done;
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
 done:
        release_sock(sk);
@@ -788,7 +771,7 @@ static int sco_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
        release_sock(sk);
        return err;
@@ -878,7 +861,7 @@ static void sco_conn_ready(struct sco_conn *conn)
                bh_lock_sock(parent);
 
                sk = sco_sock_alloc(sock_net(parent), NULL,
-                               BTPROTO_SCO, GFP_ATOMIC);
+                                   BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
                        goto done;
@@ -907,7 +890,7 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       register struct sock *sk;
+       struct sock *sk;
        struct hlist_node *node;
        int lm = 0;
 
@@ -920,7 +903,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
-                               !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                   !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm |= HCI_LM_ACCEPT;
                        break;
                }
@@ -981,7 +964,7 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
 
        sk_for_each(sk, node, &sco_sk_list.head) {
                seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-                               batostr(&bt_sk(sk)->dst), sk->sk_state);
+                          batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
        read_unlock(&sco_sk_list.lock);
@@ -1044,8 +1027,8 @@ int __init sco_init(void)
        }
 
        if (bt_debugfs) {
-               sco_debugfs = debugfs_create_file("sco", 0444,
-                                       bt_debugfs, NULL, &sco_debugfs_fops);
+               sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
+                                                 NULL, &sco_debugfs_fops);
                if (!sco_debugfs)
                        BT_ERR("Failed to create SCO debug file");
        }
index 6fc7c4708f3e1fa6336a434ef8c63d072e262d5a..16ef0dc85a0a87580c311563028cc567fa826bce 100644 (file)
    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)
 
@@ -648,7 +649,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
        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;
 
@@ -703,7 +704,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
        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;
@@ -712,6 +713,9 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
        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;
 
@@ -732,7 +736,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        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))
@@ -771,7 +775,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
                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))
index 498c94e344274cde556be0af87bb1df68a1cbfb1..85ac364f4636010128d997ad58fe93fea50e58a4 100644 (file)
@@ -2097,6 +2097,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
        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)
index d7134c17033600fcb06219619c1209d1dce12ebc..079038d26a1433848853a5d8aca17d3e5a741145 100644 (file)
@@ -1337,6 +1337,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(!ifmgd->associated))
                return;
 
+       ieee80211_stop_poll(sdata);
+
        memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
        ifmgd->associated = NULL;
@@ -2592,8 +2594,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
        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);
index 3bb24a121c95f7e82e35719a6aebf582038c449c..a470e1123a5576ed5e14b779ed4a9213cda407b7 100644 (file)
@@ -271,6 +271,9 @@ struct sta_ampdu_mlme {
  * @plink_timer: peer link watch timer
  * @plink_timer_was_running: used by suspend/resume to restore timers
  * @t_offset: timing offset relative to this host
+ * @t_offset_setpoint: reference timing offset of this sta to be used when
+ *     calculating clockdrift
+ * @ch_type: peer's channel type
  * @debugfs: debug filesystem info
  * @dead: set to true when sta is unlinked
  * @uploaded: set to true when sta is uploaded to the driver
@@ -278,6 +281,8 @@ struct sta_ampdu_mlme {
  * @sta: station information we share with the driver
  * @sta_state: duplicates information about station state (for debug)
  * @beacon_loss_count: number of times beacon loss has triggered
+ * @supports_40mhz: tracks whether the station advertised 40 MHz support
+ *     as we overwrite its HT parameters with the currently used value
  */
 struct sta_info {
        /* General information, mostly static */
index 15f347477a9953fb85acc494436cd2763cd266a9..baf5704740ee62080e8dc4a16de8cb71503b7669 100644 (file)
@@ -1389,7 +1389,7 @@ static void reg_set_request_processed(void)
        spin_unlock(&reg_requests_lock);
 
        if (last_request->initiator == NL80211_REGDOM_SET_BY_USER)
-               cancel_delayed_work_sync(&reg_timeout);
+               cancel_delayed_work(&reg_timeout);
 
        if (need_more_processing)
                schedule_work(&reg_work);
index 8f2d68fc3a444b3c90a699d29d50bf5e48cbb31f..316cfd00914fe8df7d6510b13aeaf4165a9d6d88 100644 (file)
@@ -804,7 +804,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
             ntype == NL80211_IFTYPE_P2P_CLIENT))
                return -EBUSY;
 
-       if (ntype != otype) {
+       if (ntype != otype && netif_running(dev)) {
                err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
                                                    ntype);
                if (err)
This page took 0.235863 seconds and 5 git commands to generate.