diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-01-02 16:43:54 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-01-02 16:43:54 -0500 |
commit | dc0d633e35643662f27a0b1c531da3cd6b204b9c (patch) | |
tree | cae724ecca3fb997bf3ad6b70bff4e3c739cd648 /include/net | |
parent | aef6c928a92481f75fbd548eb8c1e840912444b8 (diff) | |
parent | 4ae1652ef1bf38e07caa5d1d86ffd3b31103b55a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 22 | ||||
-rw-r--r-- | include/net/bluetooth/hci.h | 14 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 162 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 40 | ||||
-rw-r--r-- | include/net/bluetooth/smp.h | 6 |
5 files changed, 121 insertions, 123 deletions
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 980e59f37d4f..abaad6ed9b83 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void); extern struct dentry *bt_debugfs; -#ifdef CONFIG_BT_L2CAP int l2cap_init(void); void l2cap_exit(void); -#else -static inline int l2cap_init(void) -{ - return 0; -} - -static inline void l2cap_exit(void) -{ -} -#endif -#ifdef CONFIG_BT_SCO int sco_init(void); void sco_exit(void); -#else -static inline int sco_init(void) -{ - return 0; -} - -static inline void sco_exit(void) -{ -} -#endif #endif /* __BLUETOOTH_H */ diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2e48d326e365..5b2fed5eebf2 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -280,6 +280,10 @@ enum { #define HCI_ERROR_LOCAL_HOST_TERM 0x16 #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 +/* Flow control modes */ +#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 +#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01 + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 @@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param { __u8 filter_policy; } __packed; +#define LE_SCANNING_DISABLED 0x00 +#define LE_SCANNING_ENABLED 0x01 + #define HCI_OP_LE_SET_SCAN_ENABLE 0x200c struct hci_cp_le_set_scan_enable { __u8 enable; @@ -975,9 +982,14 @@ struct hci_ev_role_change { } __packed; #define HCI_EV_NUM_COMP_PKTS 0x13 +struct hci_comp_pkts_info { + __le16 handle; + __le16 count; +} __packed; + struct hci_ev_num_comp_pkts { __u8 num_hndl; - /* variable length part */ + struct hci_comp_pkts_info handles[0]; } __packed; #define HCI_EV_MODE_CHANGE 0x14 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 25c161ab6803..5e2e98458496 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -28,10 +28,6 @@ #include <linux/interrupt.h> #include <net/bluetooth/hci.h> -/* HCI upper protocols */ -#define HCI_PROTO_L2CAP 0 -#define HCI_PROTO_SCO 1 - /* HCI priority */ #define HCI_PRIO_MAX 7 @@ -54,7 +50,6 @@ struct inquiry_entry { }; struct inquiry_cache { - spinlock_t lock; __u32 timestamp; struct inquiry_entry *list; }; @@ -314,6 +309,7 @@ struct hci_conn { struct hci_dev *hdev; void *l2cap_data; void *sco_data; + void *smp_conn; struct hci_conn *link; @@ -330,25 +326,31 @@ struct hci_chan { unsigned int sent; }; -extern struct hci_proto *hci_proto[]; extern struct list_head hci_dev_list; extern struct list_head hci_cb_list; extern rwlock_t hci_dev_list_lock; extern rwlock_t hci_cb_list_lock; +/* ----- HCI interface to upper protocols ----- */ +extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); +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 sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); +extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status); +extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); +extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); + /* ----- Inquiry cache ----- */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ #define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ -#define inquiry_cache_lock(c) spin_lock(&c->lock) -#define inquiry_cache_unlock(c) spin_unlock(&c->lock) -#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) -#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) - static inline void inquiry_cache_init(struct hci_dev *hdev) { struct inquiry_cache *c = &hdev->inq_cache; - spin_lock_init(&c->lock); c->list = NULL; } @@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE) /* ----- HCI protocols ----- */ -struct hci_proto { - char *name; - unsigned int id; - unsigned long flags; - - void *priv; - - int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, - __u8 type); - int (*connect_cfm) (struct hci_conn *conn, __u8 status); - int (*disconn_ind) (struct hci_conn *conn); - int (*disconn_cfm) (struct hci_conn *conn, __u8 reason); - int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, - __u16 flags); - int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); - int (*security_cfm) (struct hci_conn *conn, __u8 status, - __u8 encrypt); -}; - static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) { - register struct hci_proto *hp; - int mask = 0; - - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->connect_ind) - mask |= hp->connect_ind(hdev, bdaddr, type); + switch (type) { + case ACL_LINK: + return l2cap_connect_ind(hdev, bdaddr); - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->connect_ind) - mask |= hp->connect_ind(hdev, bdaddr, type); + case SCO_LINK: + case ESCO_LINK: + return sco_connect_ind(hdev, bdaddr); - return mask; + default: + BT_ERR("unknown link type %d", type); + return -EINVAL; + } } static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) { - register struct hci_proto *hp; + switch (conn->type) { + case ACL_LINK: + case LE_LINK: + l2cap_connect_cfm(conn, status); + break; - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->connect_cfm) - hp->connect_cfm(conn, status); + case SCO_LINK: + case ESCO_LINK: + sco_connect_cfm(conn, status); + break; - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->connect_cfm) - hp->connect_cfm(conn, status); + default: + BT_ERR("unknown link type %d", conn->type); + break; + } if (conn->connect_cfm_cb) conn->connect_cfm_cb(conn, status); @@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) static inline int hci_proto_disconn_ind(struct hci_conn *conn) { - register struct hci_proto *hp; - int reason = HCI_ERROR_REMOTE_USER_TERM; + if (conn->type != ACL_LINK && conn->type != LE_LINK) + return HCI_ERROR_REMOTE_USER_TERM; - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->disconn_ind) - reason = hp->disconn_ind(conn); - - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->disconn_ind) - reason = hp->disconn_ind(conn); - - return reason; + return l2cap_disconn_ind(conn); } static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) { - register struct hci_proto *hp; + switch (conn->type) { + case ACL_LINK: + case LE_LINK: + l2cap_disconn_cfm(conn, reason); + break; - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->disconn_cfm) - hp->disconn_cfm(conn, reason); + case SCO_LINK: + case ESCO_LINK: + sco_disconn_cfm(conn, reason); + break; - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->disconn_cfm) - hp->disconn_cfm(conn, reason); + default: + BT_ERR("unknown link type %d", conn->type); + break; + } if (conn->disconn_cfm_cb) conn->disconn_cfm_cb(conn, reason); @@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) { - register struct hci_proto *hp; __u8 encrypt; + if (conn->type != ACL_LINK && conn->type != LE_LINK) + return; + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; - - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->security_cfm) - hp->security_cfm(conn, status, encrypt); - - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->security_cfm) - hp->security_cfm(conn, status, encrypt); + l2cap_security_cfm(conn, status, encrypt); if (conn->security_cfm_cb) conn->security_cfm_cb(conn, status); @@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) { - register struct hci_proto *hp; - - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->security_cfm) - hp->security_cfm(conn, status, encrypt); + if (conn->type != ACL_LINK && conn->type != LE_LINK) + return; - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->security_cfm) - hp->security_cfm(conn, status, encrypt); + l2cap_security_cfm(conn, status, encrypt); if (conn->security_cfm_cb) conn->security_cfm_cb(conn, status); } -int hci_register_proto(struct hci_proto *hproto); -int hci_unregister_proto(struct hci_proto *hproto); - /* ----- HCI callbacks ----- */ struct hci_cb { struct list_head list; @@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; - read_lock_bh(&hci_cb_list_lock); + read_lock(&hci_cb_list_lock); list_for_each(p, &hci_cb_list) { struct hci_cb *cb = list_entry(p, struct hci_cb, list); if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } - read_unlock_bh(&hci_cb_list_lock); + read_unlock(&hci_cb_list_lock); } static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, @@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, hci_proto_encrypt_cfm(conn, status, encrypt); - read_lock_bh(&hci_cb_list_lock); + read_lock(&hci_cb_list_lock); list_for_each(p, &hci_cb_list) { struct hci_cb *cb = list_entry(p, struct hci_cb, list); if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } - read_unlock_bh(&hci_cb_list_lock); + read_unlock(&hci_cb_list_lock); } static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) { struct list_head *p; - read_lock_bh(&hci_cb_list_lock); + read_lock(&hci_cb_list_lock); list_for_each(p, &hci_cb_list) { struct hci_cb *cb = list_entry(p, struct hci_cb, list); if (cb->key_change_cfm) cb->key_change_cfm(conn, status); } - read_unlock_bh(&hci_cb_list_lock); + read_unlock(&hci_cb_list_lock); } static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, @@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, { struct list_head *p; - read_lock_bh(&hci_cb_list_lock); + read_lock(&hci_cb_list_lock); list_for_each(p, &hci_cb_list) { struct hci_cb *cb = list_entry(p, struct hci_cb, list); if (cb->role_switch_cfm) cb->role_switch_cfm(conn, status, role); } - read_unlock_bh(&hci_cb_list_lock); + read_unlock(&hci_cb_list_lock); } int hci_register_cb(struct hci_cb *hcb); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c0d168adf9be..9572cbd12a7a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -522,7 +522,7 @@ struct l2cap_conn { __u8 info_state; __u8 info_ident; - struct delayed_work info_work; + struct delayed_work info_timer; spinlock_t lock; @@ -532,7 +532,7 @@ struct l2cap_conn { __u8 disc_reason; - struct timer_list security_timer; + struct delayed_work security_timer; struct smp_chan *smp_chan; struct list_head chan_l; @@ -595,17 +595,45 @@ enum { FLAG_EFS_ENABLE, }; +static inline void l2cap_chan_hold(struct l2cap_chan *c) +{ + atomic_inc(&c->refcnt); +} + +static inline void l2cap_chan_put(struct l2cap_chan *c) +{ + if (atomic_dec_and_test(&c->refcnt)) + kfree(c); +} + +static inline void l2cap_set_timer(struct l2cap_chan *chan, + struct delayed_work *work, long timeout) +{ + BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); + + if (!__cancel_delayed_work(work)) + l2cap_chan_hold(chan); + schedule_delayed_work(work, timeout); +} + +static inline void l2cap_clear_timer(struct l2cap_chan *chan, + struct delayed_work *work) +{ + if (__cancel_delayed_work(work)) + l2cap_chan_put(chan); +} + #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) -#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer) +#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ L2CAP_DEFAULT_RETRANS_TO); -#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer) +#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ L2CAP_DEFAULT_MONITOR_TO); -#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer) +#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ L2CAP_DEFAULT_ACK_TO); -#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer) +#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 15b97d549441..aeaf5fa2b9f1 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -115,6 +115,10 @@ struct smp_cmd_security_req { #define SMP_MIN_ENC_KEY_SIZE 7 #define SMP_MAX_ENC_KEY_SIZE 16 +#define SMP_FLAG_TK_VALID 1 +#define SMP_FLAG_CFM_PENDING 2 +#define SMP_FLAG_MITM_AUTH 3 + struct smp_chan { struct l2cap_conn *conn; u8 preq[7]; /* SMP Pairing Request */ @@ -124,6 +128,7 @@ struct smp_chan { u8 pcnf[16]; /* SMP Pairing Confirm */ u8 tk[16]; /* SMP Temporary Key */ u8 smp_key_size; + unsigned long smp_flags; struct crypto_blkcipher *tfm; struct work_struct confirm; struct work_struct random; @@ -134,6 +139,7 @@ struct smp_chan { int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); +int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); |