diff options
author | David S. Miller <davem@davemloft.net> | 2012-03-07 22:53:48 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-03-07 22:53:48 -0800 |
commit | 0111ad823e5e261ffc54ef728f1d852760ee4920 (patch) | |
tree | 3fa6912f040765a447e7b4e25a4918b2d006d7a5 /net | |
parent | e427babeefe10023d348e2a3db272612d6e79dc3 (diff) | |
parent | fdde0a26a218d95e2ea38c0838ab6f24040af14c (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/Kconfig | 1 | ||||
-rw-r--r-- | net/bluetooth/bnep/sock.c | 6 | ||||
-rw-r--r-- | net/bluetooth/cmtp/sock.c | 6 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 73 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 645 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 631 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 469 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 53 | ||||
-rw-r--r-- | net/bluetooth/hidp/sock.c | 6 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 641 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 54 | ||||
-rw-r--r-- | net/bluetooth/lib.c | 27 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 2647 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 6 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 108 |
15 files changed, 3585 insertions, 1788 deletions
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 9ec85eb8853..3537d385035 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -29,7 +29,6 @@ menuconfig BT BNEP Module (Bluetooth Network Encapsulation Protocol) CMTP Module (CAPI Message Transport Protocol) HIDP Module (Human Interface Device Protocol) - SMP Module (Security Manager Protocol) Say Y here to compile Bluetooth support into the kernel or say M to compile it as module (bluetooth). diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 17800b1d28e..9f9c8dcd8af 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == BNEPGETCONNLIST) { struct bnep_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = bnep_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 3f2dd5c25ae..1230faaac29 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == CMTPGETCONNLIST) { struct cmtp_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = cmtp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 07bc69ed949..947172bf162 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,7 +35,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/interrupt.h> -#include <linux/notifier.h> #include <net/sock.h> #include <asm/system.h> @@ -51,7 +50,7 @@ static void hci_le_connect(struct hci_conn *conn) struct hci_cp_le_create_conn cp; conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode |= HCI_LM_MASTER; conn->sec_level = BT_SECURITY_LOW; @@ -80,10 +79,10 @@ void hci_acl_connect(struct hci_conn *conn) struct inquiry_entry *ie; struct hci_cp_create_conn cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode = HCI_LM_MASTER; @@ -105,7 +104,8 @@ void hci_acl_connect(struct hci_conn *conn) } memcpy(conn->dev_class, ie->data.dev_class, 3); - conn->ssp_mode = ie->data.ssp_mode; + if (ie->data.ssp_mode > 0) + set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; @@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; @@ -279,16 +279,13 @@ static void hci_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, disc_work.work); - struct hci_dev *hdev = conn->hdev; __u8 reason; - BT_DBG("conn %p state %d", conn, conn->state); + BT_DBG("conn %p state %s", conn, state_to_string(conn->state)); if (atomic_read(&conn->refcnt)) return; - hci_dev_lock(hdev); - switch (conn->state) { case BT_CONNECT: case BT_CONNECT2: @@ -308,8 +305,6 @@ static void hci_conn_timeout(struct work_struct *work) conn->state = BT_CLOSED; break; } - - hci_dev_unlock(hdev); } /* Enter sniff mode */ @@ -337,7 +332,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); @@ -372,7 +367,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) BT_DBG("%s dst %s", hdev->name, batostr(dst)); - conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); + conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); if (!conn) return NULL; @@ -386,7 +381,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->remote_auth = 0xff; conn->key_type = 0xff; - conn->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; switch (type) { @@ -407,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) skb_queue_head_init(&conn->data_q); - INIT_LIST_HEAD(&conn->chan_list);; + INIT_LIST_HEAD(&conn->chan_list); INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); @@ -555,7 +550,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (!acl) { acl = hci_conn_add(hdev, ACL_LINK, dst); if (!acl) - return NULL; + return ERR_PTR(-ENOMEM); } hci_conn_hold(acl); @@ -575,7 +570,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sco = hci_conn_add(hdev, type, dst); if (!sco) { hci_conn_put(acl); - return NULL; + return ERR_PTR(-ENOMEM); } } @@ -586,12 +581,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { - acl->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); - if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { + if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { /* defer SCO setup until mode change completed */ - set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend); + set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags); return sco; } @@ -607,8 +602,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 && - !(conn->link_mode & HCI_LM_ENCRYPT)) + if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; return 1; @@ -633,17 +627,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) conn->auth_type = auth_type; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; /* encrypt must be pending if auth is also pending */ - set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); if (conn->key_type != 0xff) - set_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); } return 0; @@ -654,7 +648,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; @@ -674,8 +668,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* For non 2.1 devices and low security level we don't need the link key. */ - if (sec_level == BT_SECURITY_LOW && - (!conn->ssp_mode || !conn->hdev->ssp_mode)) + if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn)) return 1; /* For other security levels we need the link key. */ @@ -704,7 +697,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) goto encrypt; auth: - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return 0; if (!hci_conn_auth(conn, sec_level, auth_type)) @@ -739,7 +732,7 @@ int hci_conn_change_link_key(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { 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, @@ -758,7 +751,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) if (!role && conn->link_mode & HCI_LM_MASTER) return 1; - if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { struct hci_cp_switch_role cp; bacpy(&cp.bdaddr, &conn->dst); cp.role = role; @@ -782,10 +775,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (conn->mode != HCI_CM_SNIFF) goto timer; - if (!conn->power_save && !force_active) + if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active) goto timer; - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); @@ -801,11 +794,11 @@ timer: void hci_conn_hash_flush(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; - struct hci_conn *c; + struct hci_conn *c, *n; BT_DBG("hdev %s", hdev->name); - list_for_each_entry_rcu(c, &h->list, list) { + list_for_each_entry_safe(c, n, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); @@ -950,7 +943,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s conn %p", hdev->name, conn); - chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC); + chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); if (!chan) return NULL; @@ -981,10 +974,10 @@ int hci_chan_del(struct hci_chan *chan) void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan *chan; + struct hci_chan *chan, *n; BT_DBG("conn %p", conn); - list_for_each_entry_rcu(chan, &conn->chan_list, list) + list_for_each_entry_safe(chan, n, &conn->chan_list, list) hci_chan_del(chan); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5aeb6249119..59ec99eb739 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -40,7 +40,6 @@ #include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/interrupt.h> -#include <linux/notifier.h> #include <linux/rfkill.h> #include <linux/timer.h> #include <linux/crypto.h> @@ -55,8 +54,6 @@ #define AUTO_OFF_TIMEOUT 2000 -bool enable_hs; - static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -69,24 +66,11 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); -/* HCI notifiers list */ -static ATOMIC_NOTIFIER_HEAD(hci_notifier); - /* ---- HCI notifications ---- */ -int hci_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&hci_notifier, nb); -} - -int hci_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&hci_notifier, nb); -} - static void hci_notify(struct hci_dev *hdev, int event) { - atomic_notifier_call_chain(&hci_notifier, event, hdev); + hci_sock_dev_event(hdev, event); } /* ---- HCI requests ---- */ @@ -98,8 +82,28 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) /* If this is the init phase check if the completed command matches * the last init command, and if not just return. */ - if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) + if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) { + struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + struct sk_buff *skb; + + /* Some CSR based controllers generate a spontaneous + * reset complete event during init and any pending + * command will never be completed. In such a case we + * need to resend whatever was the last sent + * command. + */ + + if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET) + return; + + skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC); + if (skb) { + skb_queue_head(&hdev->cmd_q, skb); + queue_work(hdev->workqueue, &hdev->cmd_work); + } + return; + } if (hdev->req_status == HCI_REQ_PEND) { hdev->req_result = result; @@ -355,72 +359,209 @@ struct hci_dev *hci_dev_get(int index) } /* ---- Inquiry support ---- */ -static void inquiry_cache_flush(struct hci_dev *hdev) + +bool hci_discovery_active(struct hci_dev *hdev) { - struct inquiry_cache *cache = &hdev->inq_cache; - struct inquiry_entry *next = cache->list, *e; + struct discovery_state *discov = &hdev->discovery; + + switch (discov->state) { + case DISCOVERY_FINDING: + case DISCOVERY_RESOLVING: + return true; + + default: + return false; + } +} + +void hci_discovery_set_state(struct hci_dev *hdev, int state) +{ + BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); + + if (hdev->discovery.state == state) + return; + + switch (state) { + case DISCOVERY_STOPPED: + if (hdev->discovery.state != DISCOVERY_STARTING) + mgmt_discovering(hdev, 0); + hdev->discovery.type = 0; + break; + case DISCOVERY_STARTING: + break; + case DISCOVERY_FINDING: + mgmt_discovering(hdev, 1); + break; + case DISCOVERY_RESOLVING: + break; + case DISCOVERY_STOPPING: + break; + } + + hdev->discovery.state = state; +} - BT_DBG("cache %p", cache); +static void inquiry_cache_flush(struct hci_dev *hdev) +{ + struct discovery_state *cache = &hdev->discovery; + struct inquiry_entry *p, *n; - cache->list = NULL; - while ((e = next)) { - next = e->next; - kfree(e); + list_for_each_entry_safe(p, n, &cache->all, all) { + list_del(&p->all); + kfree(p); } + + INIT_LIST_HEAD(&cache->unknown); + INIT_LIST_HEAD(&cache->resolve); } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; BT_DBG("cache %p, %s", cache, batostr(bdaddr)); - for (e = cache->list; e; e = e->next) + list_for_each_entry(e, &cache->all, all) { + if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + +struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, + bdaddr_t *bdaddr) +{ + struct discovery_state *cache = &hdev->discovery; + struct inquiry_entry *e; + + BT_DBG("cache %p, %s", cache, batostr(bdaddr)); + + list_for_each_entry(e, &cache->unknown, list) { + if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + +struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, + bdaddr_t *bdaddr, + int state) +{ + struct discovery_state *cache = &hdev->discovery; + struct inquiry_entry *e; + + BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state); + + list_for_each_entry(e, &cache->resolve, list) { + if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state) + return e; if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + +void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, + struct inquiry_entry *ie) +{ + struct discovery_state *cache = &hdev->discovery; + struct list_head *pos = &cache->resolve; + struct inquiry_entry *p; + + list_del(&ie->list); + + list_for_each_entry(p, &cache->resolve, list) { + if (p->name_state != NAME_PENDING && + abs(p->data.rssi) >= abs(ie->data.rssi)) break; - return e; + pos = &p->list; + } + + list_add(&ie->list, pos); } -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) +bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, + bool name_known, bool *ssp) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); + if (ssp) + *ssp = data->ssp_mode; + ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); - if (!ie) { - /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); - if (!ie) - return; + if (ie) { + if (ie->data.ssp_mode && ssp) + *ssp = true; + + if (ie->name_state == NAME_NEEDED && + data->rssi != ie->data.rssi) { + ie->data.rssi = data->rssi; + hci_inquiry_cache_update_resolve(hdev, ie); + } - ie->next = cache->list; - cache->list = ie; + goto update; + } + + /* Entry not in the cache. Add new one. */ + ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); + if (!ie) + return false; + + list_add(&ie->all, &cache->all); + + if (name_known) { + ie->name_state = NAME_KNOWN; + } else { + ie->name_state = NAME_NOT_KNOWN; + list_add(&ie->list, &cache->unknown); + } + +update: + if (name_known && ie->name_state != NAME_KNOWN && + ie->name_state != NAME_PENDING) { + ie->name_state = NAME_KNOWN; + list_del(&ie->list); } memcpy(&ie->data, data, sizeof(*data)); ie->timestamp = jiffies; cache->timestamp = jiffies; + + if (ie->name_state == NAME_NOT_KNOWN) + return false; + + return true; } static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_info *info = (struct inquiry_info *) buf; struct inquiry_entry *e; int copied = 0; - for (e = cache->list; e && copied < num; e = e->next, copied++) { + list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; + + if (copied >= num) + break; + bacpy(&info->bdaddr, &data->bdaddr); info->pscan_rep_mode = data->pscan_rep_mode; info->pscan_period_mode = data->pscan_period_mode; info->pscan_mode = data->pscan_mode; memcpy(info->dev_class, data->dev_class, 3); info->clock_offset = data->clock_offset; + info++; + copied++; } BT_DBG("cache %p, copied %d", cache, copied); @@ -567,7 +708,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); - if (!test_bit(HCI_SETUP, &hdev->flags)) { + if (!test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_powered(hdev, 1); hci_dev_unlock(hdev); @@ -603,6 +744,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); + cancel_work_sync(&hdev->le_scan); + hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); @@ -619,14 +762,14 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (hdev->discov_timeout > 0) { cancel_delayed_work(&hdev->discov_off); hdev->discov_timeout = 0; + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) - cancel_delayed_work(&hdev->power_off); - - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); + cancel_delayed_work_sync(&hdev->le_scan_disable); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); @@ -667,13 +810,18 @@ static int hci_dev_do_close(struct hci_dev *hdev) * and no tasks are scheduled. */ hdev->close(hdev); - hci_dev_lock(hdev); - mgmt_powered(hdev, 0); - hci_dev_unlock(hdev); + if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { + hci_dev_lock(hdev); + mgmt_powered(hdev, 0); + hci_dev_unlock(hdev); + } /* Clear flags */ hdev->flags = 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); + hci_req_unlock(hdev); hci_dev_put(hdev); @@ -688,7 +836,12 @@ int hci_dev_close(__u16 dev) hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; + + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + cancel_delayed_work(&hdev->power_off); + err = hci_dev_do_close(hdev); + hci_dev_put(hdev); return err; } @@ -847,11 +1000,11 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); (dr + n)->dev_id = hdev->id; (dr + n)->dev_opt = hdev->flags; @@ -883,11 +1036,11 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work_sync(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; @@ -967,11 +1120,11 @@ static void hci_power_on(struct work_struct *work) if (hci_dev_open(hdev->id) < 0) return; - if (test_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) schedule_delayed_work(&hdev->power_off, msecs_to_jiffies(AUTO_OFF_TIMEOUT)); - if (test_and_clear_bit(HCI_SETUP, &hdev->flags)) + if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); } @@ -982,9 +1135,7 @@ static void hci_power_off(struct work_struct *work) BT_DBG("%s", hdev->name); - clear_bit(HCI_AUTO_OFF, &hdev->flags); - - hci_dev_close(hdev->id); + hci_dev_do_close(hdev); } static void hci_discov_off(struct work_struct *work) @@ -1037,6 +1188,18 @@ int hci_link_keys_clear(struct hci_dev *hdev) return 0; } +int hci_smp_ltks_clear(struct hci_dev *hdev) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_del(&k->list); + kfree(k); + } + + return 0; +} + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *k; @@ -1084,44 +1247,38 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return 0; } -struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) { - struct link_key *k; + struct smp_ltk *k; - list_for_each_entry(k, &hdev->link_keys, list) { - struct key_master_id *id; - - if (k->type != HCI_LK_SMP_LTK) + list_for_each_entry(k, &hdev->long_term_keys, list) { + if (k->ediv != ediv || + memcmp(rand, k->rand, sizeof(k->rand))) continue; - if (k->dlen != sizeof(*id)) - continue; - - id = (void *) &k->data; - if (id->ediv == ediv && - (memcmp(rand, id->rand, sizeof(id->rand)) == 0)) - return k; + return k; } return NULL; } EXPORT_SYMBOL(hci_find_ltk); -struct link_key *hci_find_link_key_type(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type) +struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type) { - struct link_key *k; + struct smp_ltk *k; - list_for_each_entry(k, &hdev->link_keys, list) - if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0) + list_for_each_entry(k, &hdev->long_term_keys, list) + if (addr_type == k->bdaddr_type && + bacmp(bdaddr, &k->bdaddr) == 0) return k; return NULL; } -EXPORT_SYMBOL(hci_find_link_key_type); +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) + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type, persistent; @@ -1175,40 +1332,39 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } -int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]) +int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + ediv, u8 rand[8]) { - struct link_key *key, *old_key; - struct key_master_id *id; - u8 old_key_type; + struct smp_ltk *key, *old_key; - BT_DBG("%s addr %s", hdev->name, batostr(bdaddr)); + if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK)) + return 0; - old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK); - if (old_key) { + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); + if (old_key) key = old_key; - old_key_type = old_key->type; - } else { - key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC); + else { + key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; - list_add(&key->list, &hdev->link_keys); - old_key_type = 0xff; + list_add(&key->list, &hdev->long_term_keys); } - key->dlen = sizeof(*id); - bacpy(&key->bdaddr, bdaddr); - memcpy(key->val, ltk, sizeof(key->val)); - key->type = HCI_LK_SMP_LTK; - key->pin_len = key_size; + key->bdaddr_type = addr_type; + memcpy(key->val, tk, sizeof(key->val)); + key->authenticated = authenticated; + key->ediv = ediv; + key->enc_size = enc_size; + key->type = type; + memcpy(key->rand, rand, sizeof(key->rand)); - id = (void *) &key->data; - id->ediv = ediv; - memcpy(id->rand, rand, sizeof(id->rand)); + if (!new_key) + return 0; - if (new_key) - mgmt_new_link_key(hdev, key, old_key_type); + if (type & HCI_SMP_LTK) + mgmt_new_ltk(hdev, key, 1); return 0; } @@ -1229,6 +1385,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr)) + continue; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&k->list); + kfree(k); + } + + return 0; +} + /* HCI command timer function */ static void hci_cmd_timer(unsigned long arg) { @@ -1240,7 +1413,7 @@ static void hci_cmd_timer(unsigned long arg) } struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, - bdaddr_t *bdaddr) + bdaddr_t *bdaddr) { struct oob_data *data; @@ -1280,7 +1453,7 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer) + u8 *randomizer) { struct oob_data *data; @@ -1303,8 +1476,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, return 0; } -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) { struct bdaddr_list *b; @@ -1331,7 +1503,7 @@ int hci_blacklist_clear(struct hci_dev *hdev) return 0; } -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -1349,10 +1521,10 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) list_add(&entry->list, &hdev->blacklist); - return mgmt_device_blocked(hdev, bdaddr); + return mgmt_device_blocked(hdev, bdaddr, type); } -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) |