Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 3b39198..b095e99 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -60,6 +60,8 @@
static DEFINE_RWLOCK(hci_task_lock);
+static int enable_smp;
+
/* HCI device list */
LIST_HEAD(hci_dev_list);
DEFINE_RWLOCK(hci_dev_list_lock);
@@ -68,6 +70,10 @@
LIST_HEAD(hci_cb_list);
DEFINE_RWLOCK(hci_cb_list_lock);
+/* AMP Manager event callbacks */
+LIST_HEAD(amp_mgr_cb_list);
+DEFINE_RWLOCK(amp_mgr_cb_list_lock);
+
/* HCI protocols */
#define HCI_MAX_PROTO 2
struct hci_proto *hci_proto[HCI_MAX_PROTO];
@@ -146,7 +152,7 @@
switch (hdev->req_status) {
case HCI_REQ_DONE:
- err = -bt_to_errno(hdev->req_result);
+ err = -bt_err(hdev->req_result);
break;
case HCI_REQ_CANCELED:
@@ -219,15 +225,25 @@
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
}
- /* Read Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
/* Read Local Version */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+
+ /* Set default HCI Flow Control Mode */
+ if (hdev->dev_type == HCI_BREDR)
+ hdev->flow_ctl_mode = HCI_PACKET_BASED_FLOW_CTL_MODE;
+ else
+ hdev->flow_ctl_mode = HCI_BLOCK_BASED_FLOW_CTL_MODE;
+
+ /* Read HCI Flow Control Mode */
+ hci_send_cmd(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, 0, NULL);
+
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+ /* Read Data Block Size (ACL mtu, max pkt, etc.) */
+ hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
+
#if 0
/* Host buffer size */
{
@@ -240,31 +256,46 @@
}
#endif
- /* Read BD Address */
- hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+ if (hdev->dev_type == HCI_BREDR) {
+ /* BR-EDR initialization */
- /* Read Class of Device */
- hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+ /* Read Local Supported Features */
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
- /* Read Local Name */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+ /* Read BD Address */
+ hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
- /* Read Voice Setting */
- hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+ /* Read Class of Device */
+ hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
- /* Optional initialization */
+ /* Read Local Name */
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
- /* Clear Event Filters */
- flt_type = HCI_FLT_CLEAR_ALL;
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+ /* Read Voice Setting */
+ hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
- /* Connection accept timeout ~20 secs */
- param = cpu_to_le16(0x7d00);
- hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
+ /* Optional initialization */
+ /* Clear Event Filters */
+ flt_type = HCI_FLT_CLEAR_ALL;
+ hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+ /* Connection accept timeout ~20 secs */
+ param = cpu_to_le16(0x7d00);
+ hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
+
+ bacpy(&cp.bdaddr, BDADDR_ANY);
+ cp.delete_all = 1;
+ hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY,
+ sizeof(cp), &cp);
+ } else {
+ /* AMP initialization */
+ /* Connection accept timeout ~5 secs */
+ param = cpu_to_le16(0x1f40);
+ hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
+
+ /* Read AMP Info */
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+ }
}
static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -338,6 +369,7 @@
read_unlock(&hci_dev_list_lock);
return hdev;
}
+EXPORT_SYMBOL(hci_dev_get);
/* ---- Inquiry support ---- */
static void inquiry_cache_flush(struct hci_dev *hdev)
@@ -523,10 +555,6 @@
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
set_bit(HCI_RAW, &hdev->flags);
- /* Treat all non BR/EDR controllers as raw devices for now */
- if (hdev->dev_type != HCI_BREDR)
- set_bit(HCI_RAW, &hdev->flags);
-
if (hdev->open(hdev)) {
ret = -EIO;
goto done;
@@ -540,7 +568,7 @@
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
- if (lmp_host_le_capable(hdev))
+ if (lmp_le_capable(hdev))
ret = __hci_request(hdev, hci_le_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
@@ -1021,50 +1049,17 @@
return NULL;
}
-static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
- u8 key_type, u8 old_key_type)
-{
- /* Legacy key */
- if (key_type < 0x03)
- return 1;
-
- /* Debug keys are insecure so don't store them persistently */
- if (key_type == HCI_LK_DEBUG_COMBINATION)
- return 0;
-
- /* Changed combination key and there's no previous one */
- if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
- return 0;
-
- /* Security mode 3 case */
- if (!conn)
- return 1;
-
- /* Neither local nor remote side had no-bonding as requirement */
- if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
- return 1;
-
- /* Local side had dedicated bonding as requirement */
- if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
- return 1;
-
- /* Remote side had dedicated bonding as requirement */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
- return 1;
-
- /* If none of the above criteria match, then don't store the key
- * persistently */
- return 0;
-}
-
struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
{
- struct link_key *k;
+ struct list_head *p;
- list_for_each_entry(k, &hdev->link_keys, list) {
+ list_for_each(p, &hdev->link_keys) {
+ struct link_key *k;
struct key_master_id *id;
- if (k->type != HCI_LK_SMP_LTK)
+ k = list_entry(p, struct link_key, list);
+
+ if (k->type != KEY_TYPE_LTK)
continue;
if (k->dlen != sizeof(*id))
@@ -1083,28 +1078,33 @@
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type)
{
- struct link_key *k;
+ struct list_head *p;
- list_for_each_entry(k, &hdev->link_keys, list)
- if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+ list_for_each(p, &hdev->link_keys) {
+ struct link_key *k;
+
+ k = list_entry(p, struct link_key, list);
+
+ if ((k->type == type) && (bacmp(bdaddr, &k->bdaddr) == 0))
return k;
+ }
return NULL;
}
EXPORT_SYMBOL(hci_find_link_key_type);
-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)
+int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+ u8 *val, u8 type, u8 pin_len)
{
struct link_key *key, *old_key;
- u8 old_key_type, persistent;
+ u8 old_key_type;
old_key = hci_find_link_key(hdev, bdaddr);
if (old_key) {
old_key_type = old_key->type;
key = old_key;
} else {
- old_key_type = conn ? conn->key_type : 0xff;
+ old_key_type = 0xff;
key = kzalloc(sizeof(*key), GFP_ATOMIC);
if (!key)
return -ENOMEM;
@@ -1113,37 +1113,16 @@
BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
- /* Some buggy controller combinations generate a changed
- * 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) {
- type = HCI_LK_COMBINATION;
- if (conn)
- conn->key_type = type;
- }
-
bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, val, 16);
+ key->type = type;
key->pin_len = pin_len;
- if (type == HCI_LK_CHANGED_COMBINATION)
+ if (new_key)
+ mgmt_new_key(hdev->id, key, old_key_type);
+
+ if (type == 0x06)
key->type = old_key_type;
- else
- key->type = type;
-
- if (!new_key)
- return 0;
-
- persistent = hci_persistent_key(hdev, conn, type, old_key_type);
-
- mgmt_new_key(hdev->id, key, persistent);
-
- if (!persistent) {
- list_del(&key->list);
- kfree(key);
- }
return 0;
}
@@ -1157,7 +1136,7 @@
BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
- old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
+ old_key = hci_find_link_key_type(hdev, bdaddr, KEY_TYPE_LTK);
if (old_key) {
key = old_key;
old_key_type = old_key->type;
@@ -1173,7 +1152,7 @@
bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, ltk, sizeof(key->val));
- key->type = HCI_LK_SMP_LTK;
+ key->type = KEY_TYPE_LTK;
key->pin_len = key_size;
id = (void *) &key->data;
@@ -1209,6 +1188,7 @@
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
+ clear_bit(HCI_RESET, &hdev->flags);
tasklet_schedule(&hdev->cmd_task);
}
@@ -1252,6 +1232,63 @@
return 0;
}
+static void hci_adv_clear(unsigned long arg)
+{
+ struct hci_dev *hdev = (void *) arg;
+
+ hci_adv_entries_clear(hdev);
+}
+
+int hci_adv_entries_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+
+ write_lock_bh(&hdev->adv_entries_lock);
+
+ list_for_each_safe(p, n, &hdev->adv_entries) {
+ struct adv_entry *entry;
+
+ entry = list_entry(p, struct adv_entry, list);
+
+ list_del(p);
+ kfree(entry);
+ }
+
+ write_unlock_bh(&hdev->adv_entries_lock);
+
+ return 0;
+}
+
+struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+ struct adv_entry *res = NULL;
+
+ read_lock_bh(&hdev->adv_entries_lock);
+
+ list_for_each(p, &hdev->adv_entries) {
+ struct adv_entry *entry;
+
+ entry = list_entry(p, struct adv_entry, list);
+
+ if (bacmp(bdaddr, &entry->bdaddr) == 0) {
+ res = entry;
+ goto out;
+ }
+ }
+out:
+ read_unlock_bh(&hdev->adv_entries_lock);
+ return res;
+}
+
+static inline int is_connectable_adv(u8 evt_type)
+{
+ if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
+ return 1;
+
+ return 0;
+}
+
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer)
{
@@ -1276,141 +1313,6 @@
return 0;
}
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
- bdaddr_t *bdaddr)
-{
- struct list_head *p;
-
- list_for_each(p, &hdev->blacklist) {
- struct bdaddr_list *b;
-
- b = list_entry(p, struct bdaddr_list, list);
-
- if (bacmp(bdaddr, &b->bdaddr) == 0)
- return b;
- }
-
- return NULL;
-}
-
-int hci_blacklist_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->blacklist) {
- struct bdaddr_list *b;
-
- b = list_entry(p, struct bdaddr_list, list);
-
- list_del(p);
- kfree(b);
- }
-
- return 0;
-}
-
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct bdaddr_list *entry;
- int err;
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0)
- return -EBADF;
-
- hci_dev_lock_bh(hdev);
-
- if (hci_blacklist_lookup(hdev, bdaddr)) {
- err = -EEXIST;
- goto err;
- }
-
- entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
- if (!entry) {
- return -ENOMEM;
- goto err;
- }
-
- bacpy(&entry->bdaddr, bdaddr);
-
- list_add(&entry->list, &hdev->blacklist);
-
- err = 0;
-
-err:
- hci_dev_unlock_bh(hdev);
- return err;
-}
-
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct bdaddr_list *entry;
- int err = 0;
-
- hci_dev_lock_bh(hdev);
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0) {
- hci_blacklist_clear(hdev);
- goto done;
- }
-
- entry = hci_blacklist_lookup(hdev, bdaddr);
- if (!entry) {
- err = -ENOENT;
- goto done;
- }
-
- list_del(&entry->list);
- kfree(entry);
-
-done:
- hci_dev_unlock_bh(hdev);
- return err;
-}
-
-static void hci_clear_adv_cache(unsigned long arg)
-{
- struct hci_dev *hdev = (void *) arg;
-
- hci_dev_lock(hdev);
-
- hci_adv_entries_clear(hdev);
-
- hci_dev_unlock(hdev);
-}
-
-int hci_adv_entries_clear(struct hci_dev *hdev)
-{
- struct adv_entry *entry, *tmp;
-
- list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
- list_del(&entry->list);
- kfree(entry);
- }
-
- BT_DBG("%s adv cache cleared", hdev->name);
-
- return 0;
-}
-
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct adv_entry *entry;
-
- list_for_each_entry(entry, &hdev->adv_entries, list)
- if (bacmp(bdaddr, &entry->bdaddr) == 0)
- return entry;
-
- return NULL;
-}
-
-static inline int is_connectable_adv(u8 evt_type)
-{
- if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
- return 1;
-
- return 0;
-}
-
int hci_add_adv_entry(struct hci_dev *hdev,
struct hci_ev_le_advertising_info *ev)
{
@@ -1419,9 +1321,10 @@
if (!is_connectable_adv(ev->evt_type))
return -EINVAL;
+ entry = hci_find_adv_entry(hdev, &ev->bdaddr);
/* Only new entries should be added to adv_entries. So, if
* bdaddr was found, don't add it. */
- if (hci_find_adv_entry(hdev, &ev->bdaddr))
+ if (entry)
return 0;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
@@ -1431,14 +1334,21 @@
bacpy(&entry->bdaddr, &ev->bdaddr);
entry->bdaddr_type = ev->bdaddr_type;
+ write_lock(&hdev->adv_entries_lock);
list_add(&entry->list, &hdev->adv_entries);
-
- BT_DBG("%s adv entry added: address %s type %u", hdev->name,
- batostr(&entry->bdaddr), entry->bdaddr_type);
+ write_unlock(&hdev->adv_entries_lock);
return 0;
}
+static struct crypto_blkcipher *alloc_cypher(void)
+{
+ if (enable_smp)
+ return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+
+ return ERR_PTR(-ENOTSUPP);
+}
+
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1496,6 +1406,7 @@
inquiry_cache_init(hdev);
hci_conn_hash_init(hdev);
+ hci_chan_list_init(hdev);
INIT_LIST_HEAD(&hdev->blacklist);
@@ -1506,8 +1417,8 @@
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_LIST_HEAD(&hdev->adv_entries);
- setup_timer(&hdev->adv_timer, hci_clear_adv_cache,
- (unsigned long) hdev);
+ rwlock_init(&hdev->adv_entries_lock);
+ setup_timer(&hdev->adv_timer, hci_adv_clear, (unsigned long) hdev);
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
@@ -1523,7 +1434,7 @@
if (!hdev->workqueue)
goto nomem;
- hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+ hdev->tfm = alloc_cypher();
if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm));
@@ -1883,6 +1794,74 @@
}
EXPORT_SYMBOL(hci_unregister_cb);
+int hci_register_amp(struct amp_mgr_cb *cb)
+{
+ BT_DBG("%p", cb);
+
+ write_lock_bh(&_mgr_cb_list_lock);
+ list_add(&cb->list, &_mgr_cb_list);
+ write_unlock_bh(&_mgr_cb_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(hci_register_amp);
+
+int hci_unregister_amp(struct amp_mgr_cb *cb)
+{
+ BT_DBG("%p", cb);
+
+ write_lock_bh(&_mgr_cb_list_lock);
+ list_del(&cb->list);
+ write_unlock_bh(&_mgr_cb_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(hci_unregister_amp);
+
+void hci_amp_cmd_complete(struct hci_dev *hdev, __u16 opcode,
+ struct sk_buff *skb)
+{
+ struct amp_mgr_cb *cb;
+
+ BT_DBG("opcode 0x%x", opcode);
+
+ read_lock_bh(&_mgr_cb_list_lock);
+ list_for_each_entry(cb, &_mgr_cb_list, list) {
+ if (cb->amp_cmd_complete_event)
+ cb->amp_cmd_complete_event(hdev, opcode, skb);
+ }
+ read_unlock_bh(&_mgr_cb_list_lock);
+}
+
+void hci_amp_cmd_status(struct hci_dev *hdev, __u16 opcode, __u8 status)
+{
+ struct amp_mgr_cb *cb;
+
+ BT_DBG("opcode 0x%x, status %d", opcode, status);
+
+ read_lock_bh(&_mgr_cb_list_lock);
+ list_for_each_entry(cb, &_mgr_cb_list, list) {
+ if (cb->amp_cmd_status_event)
+ cb->amp_cmd_status_event(hdev, opcode, status);
+ }
+ read_unlock_bh(&_mgr_cb_list_lock);
+}
+
+void hci_amp_event_packet(struct hci_dev *hdev, __u8 ev_code,
+ struct sk_buff *skb)
+{
+ struct amp_mgr_cb *cb;
+
+ BT_DBG("ev_code 0x%x", ev_code);
+
+ read_lock_bh(&_mgr_cb_list_lock);
+ list_for_each_entry(cb, &_mgr_cb_list, list) {
+ if (cb->amp_event)
+ cb->amp_event(hdev, ev_code, skb);
+ }
+ read_unlock_bh(&_mgr_cb_list_lock);
+}
+
static int hci_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
@@ -1904,6 +1883,7 @@
/* Get rid of skb owner, prior to sending to the driver. */
skb_orphan(skb);
+ hci_notify(hdev, HCI_DEV_WRITE);
return hdev->send(skb);
}
@@ -1942,6 +1922,7 @@
return 0;
}
+EXPORT_SYMBOL(hci_send_cmd);
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
@@ -1974,16 +1955,20 @@
hdr->dlen = cpu_to_le16(len);
}
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+void hci_send_acl(struct hci_conn *conn, struct hci_chan *chan,
+ struct sk_buff *skb, __u16 flags)
{
struct hci_dev *hdev = conn->hdev;
struct sk_buff *list;
- BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
+ BT_DBG("%s conn %p chan %p flags 0x%x", hdev->name, conn, chan, flags);
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
+ if (hdev->dev_type == HCI_BREDR)
+ hci_add_acl_hdr(skb, conn->handle, flags);
+ else
+ hci_add_acl_hdr(skb, chan->ll_handle, flags);
list = skb_shinfo(skb)->frag_list;
if (!list) {
@@ -2001,8 +1986,7 @@
spin_lock_bh(&conn->data_q.lock);
__skb_queue_tail(&conn->data_q, skb);
-
- flags &= ~ACL_START;
+ flags &= ~ACL_PB_MASK;
flags |= ACL_CONT;
do {
skb = list; list = list->next;
@@ -2134,21 +2118,38 @@
if (!test_bit(HCI_RAW, &hdev->flags)) {
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
- if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
+ if (hdev->acl_cnt <= 0 &&
+ time_after(jiffies, hdev->acl_last_tx + HZ * 45))
hci_link_tx_to(hdev, ACL_LINK);
}
- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+ while (hdev->acl_cnt > 0 &&
+ (conn = hci_low_sent(hdev, ACL_LINK, "e))) {
+ while (quote > 0 && (skb = skb_dequeue(&conn->data_q))) {
+ int count = 1;
+
BT_DBG("skb %p len %d", skb, skb->len);
+ if (hdev->flow_ctl_mode ==
+ HCI_BLOCK_BASED_FLOW_CTL_MODE)
+ /* Calculate count of blocks used by
+ * this packet
+ */
+ count = ((skb->len - HCI_ACL_HDR_SIZE - 1) /
+ hdev->data_block_len) + 1;
+
+ if (count > hdev->acl_cnt)
+ return;
+
hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
- hdev->acl_cnt--;
- conn->sent++;
+ hdev->acl_cnt -= count;
+ quote -= count;
+
+ conn->sent += count;
}
}
}
@@ -2255,7 +2256,7 @@
read_unlock(&hci_task_lock);
}
-/* ----- HCI RX task (incoming data processing) ----- */
+/* ----- HCI RX task (incoming data proccessing) ----- */
/* ACL data packet */
static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
@@ -2407,10 +2408,7 @@
if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(skb);
- if (test_bit(HCI_RESET, &hdev->flags))
- del_timer(&hdev->cmd_timer);
- else
- mod_timer(&hdev->cmd_timer,
+ mod_timer(&hdev->cmd_timer,
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
} else {
skb_queue_head(&hdev->cmd_q, skb);
@@ -2418,3 +2416,6 @@
}
}
}
+
+module_param(enable_smp, bool, 0644);
+MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");