Commit e21e5022 authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Enhance HCI callback interface

This patch adds callback functions for changing the link key and
switching the role to the Bluetooth core interface.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 9ee73ad7
......@@ -217,7 +217,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND,
HCI_CONN_ENCRYPT_PEND
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND
};
static inline void hci_conn_hash_init(struct hci_dev *hdev)
......@@ -290,6 +291,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
int hci_conn_auth(struct hci_conn *conn);
int hci_conn_encrypt(struct hci_conn *conn);
int hci_conn_change_link_key(struct hci_conn *conn);
int hci_conn_switch_role(struct hci_conn *conn, uint8_t role);
static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout)
{
......@@ -515,6 +517,8 @@ struct hci_cb {
void (*auth_cfm) (struct hci_conn *conn, __u8 status);
void (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
};
static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
......@@ -547,6 +551,32 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
read_unlock_bh(&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);
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);
}
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, __u8 role)
{
struct list_head *p;
read_lock_bh(&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);
}
int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb);
......
......@@ -348,6 +348,24 @@ int hci_conn_change_link_key(struct hci_conn *conn)
}
EXPORT_SYMBOL(hci_conn_change_link_key);
/* Switch role */
int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
{
BT_DBG("conn %p", conn);
if (!role && conn->link_mode & HCI_LM_MASTER)
return 1;
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
struct hci_cp_switch_role cp;
bacpy(&cp.bdaddr, &conn->dst);
cp.role = role;
hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
}
return 0;
}
EXPORT_SYMBOL(hci_conn_switch_role);
/* Drop all connection on the device */
void hci_conn_hash_flush(struct hci_dev *hdev)
{
......
......@@ -718,17 +718,20 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
BT_DBG("%s status %d", hdev->name, ev->status);
if (ev->status)
return;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) {
if (ev->role)
conn->link_mode &= ~HCI_LM_MASTER;
else
conn->link_mode |= HCI_LM_MASTER;
if (!ev->status) {
if (ev->role)
conn->link_mode &= ~HCI_LM_MASTER;
else
conn->link_mode |= HCI_LM_MASTER;
}
clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
hci_role_switch_cfm(conn, ev->status, ev->role);
}
hci_dev_unlock(hdev);
......@@ -749,6 +752,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (conn) {
if (!ev->status)
conn->link_mode |= HCI_LM_AUTH;
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
hci_auth_cfm(conn, ev->status);
......@@ -790,6 +794,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
else
conn->link_mode &= ~HCI_LM_ENCRYPT;
}
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
......@@ -801,6 +806,25 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
/* Change Connection Link Key Complete */
static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data;
struct hci_conn *conn = NULL;
__u16 handle = __le16_to_cpu(ev->handle);
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (conn) {
if (!ev->status)
conn->link_mode |= HCI_LM_SECURE;
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
hci_key_change_cfm(conn, ev->status);
}
hci_dev_unlock(hdev);
}
/* Pin Code Request*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment