You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
@@ -126,6 +126,8 @@ enum {
|
||||
HCI_SSP_ENABLED,
|
||||
HCI_SC_ENABLED,
|
||||
HCI_SC_ONLY,
|
||||
HCI_PRIVACY,
|
||||
HCI_RPA_EXPIRED,
|
||||
HCI_RPA_RESOLVING,
|
||||
HCI_HS_ENABLED,
|
||||
HCI_LE_ENABLED,
|
||||
@@ -138,6 +140,7 @@ enum {
|
||||
HCI_FAST_CONNECTABLE,
|
||||
HCI_BREDR_ENABLED,
|
||||
HCI_6LOWPAN_ENABLED,
|
||||
HCI_LE_SCAN_INTERRUPTED,
|
||||
};
|
||||
|
||||
/* A mask for the flags that are supposed to remain when a reset happens
|
||||
@@ -180,6 +183,8 @@ enum {
|
||||
#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */
|
||||
#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */
|
||||
#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
|
||||
|
||||
/* HCI data types */
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
@@ -354,6 +359,7 @@ enum {
|
||||
|
||||
/* ---- HCI Error Codes ---- */
|
||||
#define HCI_ERROR_AUTH_FAILURE 0x05
|
||||
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
|
||||
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
|
||||
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
|
||||
#define HCI_ERROR_REMOTE_USER_TERM 0x13
|
||||
@@ -1178,6 +1184,9 @@ struct hci_cp_le_set_scan_enable {
|
||||
__u8 filter_dup;
|
||||
} __packed;
|
||||
|
||||
#define HCI_LE_USE_PEER_ADDR 0x00
|
||||
#define HCI_LE_USE_WHITELIST 0x01
|
||||
|
||||
#define HCI_OP_LE_CREATE_CONN 0x200d
|
||||
struct hci_cp_le_create_conn {
|
||||
__le16 scan_interval;
|
||||
@@ -1202,6 +1211,20 @@ struct hci_rp_le_read_white_list_size {
|
||||
__u8 size;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_CLEAR_WHITE_LIST 0x2010
|
||||
|
||||
#define HCI_OP_LE_ADD_TO_WHITE_LIST 0x2011
|
||||
struct hci_cp_le_add_to_white_list {
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_DEL_FROM_WHITE_LIST 0x2012
|
||||
struct hci_cp_le_del_from_white_list {
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_CONN_UPDATE 0x2013
|
||||
struct hci_cp_le_conn_update {
|
||||
__le16 handle;
|
||||
@@ -1216,7 +1239,7 @@ struct hci_cp_le_conn_update {
|
||||
#define HCI_OP_LE_START_ENC 0x2019
|
||||
struct hci_cp_le_start_enc {
|
||||
__le16 handle;
|
||||
__u8 rand[8];
|
||||
__le64 rand;
|
||||
__le16 ediv;
|
||||
__u8 ltk[16];
|
||||
} __packed;
|
||||
@@ -1628,7 +1651,7 @@ struct hci_ev_le_conn_complete {
|
||||
#define HCI_EV_LE_LTK_REQ 0x05
|
||||
struct hci_ev_le_ltk_req {
|
||||
__le16 handle;
|
||||
__u8 random[8];
|
||||
__le64 rand;
|
||||
__le16 ediv;
|
||||
} __packed;
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ struct smp_ltk {
|
||||
u8 type;
|
||||
u8 enc_size;
|
||||
__le16 ediv;
|
||||
u8 rand[8];
|
||||
__le64 rand;
|
||||
u8 val[16];
|
||||
};
|
||||
|
||||
@@ -130,6 +130,9 @@ struct oob_data {
|
||||
|
||||
#define HCI_MAX_SHORT_NAME_LENGTH 10
|
||||
|
||||
/* Default LE RPA expiry time, 15 minutes */
|
||||
#define HCI_DEFAULT_RPA_TIMEOUT (15 * 60)
|
||||
|
||||
struct amp_assoc {
|
||||
__u16 len;
|
||||
__u16 offset;
|
||||
@@ -153,7 +156,7 @@ struct hci_dev {
|
||||
bdaddr_t bdaddr;
|
||||
bdaddr_t random_addr;
|
||||
bdaddr_t static_addr;
|
||||
__u8 own_addr_type;
|
||||
__u8 adv_addr_type;
|
||||
__u8 dev_name[HCI_MAX_NAME_LENGTH];
|
||||
__u8 short_name[HCI_MAX_SHORT_NAME_LENGTH];
|
||||
__u8 eir[HCI_MAX_EIR_LENGTH];
|
||||
@@ -281,7 +284,9 @@ struct hci_dev {
|
||||
struct list_head long_term_keys;
|
||||
struct list_head identity_resolving_keys;
|
||||
struct list_head remote_oob_data;
|
||||
struct list_head le_white_list;
|
||||
struct list_head le_conn_params;
|
||||
struct list_head pend_le_conns;
|
||||
|
||||
struct hci_dev_stats stat;
|
||||
|
||||
@@ -303,6 +308,11 @@ struct hci_dev {
|
||||
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
|
||||
__u8 scan_rsp_data_len;
|
||||
|
||||
__u8 irk[16];
|
||||
__u32 rpa_timeout;
|
||||
struct delayed_work rpa_expired;
|
||||
bdaddr_t rpa;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
int (*flush)(struct hci_dev *hdev);
|
||||
@@ -322,6 +332,10 @@ struct hci_conn {
|
||||
__u8 dst_type;
|
||||
bdaddr_t src;
|
||||
__u8 src_type;
|
||||
bdaddr_t init_addr;
|
||||
__u8 init_addr_type;
|
||||
bdaddr_t resp_addr;
|
||||
__u8 resp_addr_type;
|
||||
__u16 handle;
|
||||
__u16 state;
|
||||
__u8 mode;
|
||||
@@ -361,6 +375,7 @@ struct hci_conn {
|
||||
struct delayed_work disc_work;
|
||||
struct delayed_work auto_accept_work;
|
||||
struct delayed_work idle_work;
|
||||
struct delayed_work le_conn_timeout;
|
||||
|
||||
struct device dev;
|
||||
|
||||
@@ -394,6 +409,12 @@ struct hci_conn_params {
|
||||
|
||||
u16 conn_min_interval;
|
||||
u16 conn_max_interval;
|
||||
|
||||
enum {
|
||||
HCI_AUTO_CONN_DISABLED,
|
||||
HCI_AUTO_CONN_ALWAYS,
|
||||
HCI_AUTO_CONN_LINK_LOSS,
|
||||
} auto_connect;
|
||||
};
|
||||
|
||||
extern struct list_head hci_dev_list;
|
||||
@@ -554,6 +575,13 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int hci_conn_count(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *c = &hdev->conn_hash;
|
||||
|
||||
return c->acl_num + c->amp_num + c->sco_num + c->le_num;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
|
||||
__u16 handle)
|
||||
{
|
||||
@@ -627,8 +655,10 @@ void hci_chan_del(struct hci_chan *chan);
|
||||
void hci_chan_list_flush(struct hci_conn *conn);
|
||||
struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
|
||||
|
||||
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
__u8 dst_type, __u8 sec_level, __u8 auth_type);
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type);
|
||||
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type);
|
||||
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
__u16 setting);
|
||||
int hci_conn_check_link_mode(struct hci_conn *conn);
|
||||
@@ -639,6 +669,8 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
|
||||
|
||||
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
|
||||
|
||||
void hci_le_conn_failed(struct hci_conn *conn, u8 status);
|
||||
|
||||
/*
|
||||
* hci_conn_get() and hci_conn_put() are used to control the life-time of an
|
||||
* "hci_conn" object. They do not guarantee that the hci_conn object is running,
|
||||
@@ -770,28 +802,42 @@ int hci_inquiry(void __user *arg);
|
||||
|
||||
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
void 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);
|
||||
|
||||
struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
void hci_white_list_clear(struct hci_dev *hdev);
|
||||
int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
|
||||
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type);
|
||||
void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
|
||||
u16 conn_min_interval, u16 conn_max_interval);
|
||||
int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
|
||||
u8 auto_connect, u16 conn_min_interval,
|
||||
u16 conn_max_interval);
|
||||
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_conn_params_clear(struct hci_dev *hdev);
|
||||
|
||||
struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conns_clear(struct hci_dev *hdev);
|
||||
|
||||
void hci_update_background_scan(struct hci_dev *hdev);
|
||||
|
||||
void hci_uuids_clear(struct hci_dev *hdev);
|
||||
|
||||
void hci_link_keys_clear(struct hci_dev *hdev);
|
||||
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
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);
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8],
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
|
||||
bool master);
|
||||
struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, u8 type, u8 authenticated,
|
||||
u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]);
|
||||
u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand);
|
||||
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type, bool master);
|
||||
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type);
|
||||
@@ -1115,6 +1161,9 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
|
||||
const void *param, u8 event);
|
||||
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
|
||||
|
||||
void hci_req_add_le_scan_disable(struct hci_request *req);
|
||||
void hci_req_add_le_passive_scan(struct hci_request *req);
|
||||
|
||||
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
const void *param, u32 timeout);
|
||||
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
@@ -1160,6 +1209,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered);
|
||||
void mgmt_discoverable_timeout(struct hci_dev *hdev);
|
||||
void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
|
||||
void mgmt_connectable(struct hci_dev *hdev, u8 connectable);
|
||||
void mgmt_advertising(struct hci_dev *hdev, u8 advertising);
|
||||
void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
bool persistent);
|
||||
@@ -1167,7 +1217,8 @@ void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u32 flags, u8 *name, u8 name_len,
|
||||
u8 *dev_class);
|
||||
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 reason);
|
||||
u8 link_type, u8 addr_type, u8 reason,
|
||||
bool mgmt_connected);
|
||||
void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
@@ -1247,9 +1298,14 @@ struct hci_sec_filter {
|
||||
|
||||
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
u16 latency, u16 to_multiplier);
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
|
||||
__u8 ltk[16]);
|
||||
|
||||
int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
||||
u8 *own_addr_type);
|
||||
void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 *bdaddr_type);
|
||||
|
||||
#define SCO_AIRMODE_MASK 0x0003
|
||||
#define SCO_AIRMODE_CVSD 0x0000
|
||||
#define SCO_AIRMODE_TRANSP 0x0003
|
||||
|
||||
@@ -96,6 +96,7 @@ struct mgmt_rp_read_index_list {
|
||||
#define MGMT_SETTING_ADVERTISING 0x00000400
|
||||
#define MGMT_SETTING_SECURE_CONN 0x00000800
|
||||
#define MGMT_SETTING_DEBUG_KEYS 0x00001000
|
||||
#define MGMT_SETTING_PRIVACY 0x00002000
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
#define MGMT_READ_INFO_SIZE 0
|
||||
@@ -186,7 +187,7 @@ struct mgmt_ltk_info {
|
||||
__u8 master;
|
||||
__u8 enc_size;
|
||||
__le16 ediv;
|
||||
__u8 rand[8];
|
||||
__le64 rand;
|
||||
__u8 val[16];
|
||||
} __packed;
|
||||
|
||||
@@ -389,6 +390,13 @@ struct mgmt_cp_set_scan_params {
|
||||
|
||||
#define MGMT_OP_SET_DEBUG_KEYS 0x002E
|
||||
|
||||
#define MGMT_OP_SET_PRIVACY 0x002F
|
||||
struct mgmt_cp_set_privacy {
|
||||
__u8 privacy;
|
||||
__u8 irk[16];
|
||||
} __packed;
|
||||
#define MGMT_SET_PRIVACY_SIZE 17
|
||||
|
||||
struct mgmt_irk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 val[16];
|
||||
|
||||
+66
-50
@@ -231,7 +231,7 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
|
||||
__u8 ltk[16])
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
@@ -242,9 +242,9 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
|
||||
cp.rand = rand;
|
||||
cp.ediv = ediv;
|
||||
memcpy(cp.rand, rand, sizeof(cp.rand));
|
||||
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
|
||||
}
|
||||
@@ -363,6 +363,16 @@ static void hci_conn_auto_accept(struct work_struct *work)
|
||||
&conn->dst);
|
||||
}
|
||||
|
||||
static void le_conn_timeout(struct work_struct *work)
|
||||
{
|
||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||
le_conn_timeout.work);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
hci_le_create_connection_cancel(conn);
|
||||
}
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
@@ -410,6 +420,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);
|
||||
INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept);
|
||||
INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle);
|
||||
INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);
|
||||
|
||||
atomic_set(&conn->refcnt, 0);
|
||||
|
||||
@@ -442,6 +453,8 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
/* Unacked frames */
|
||||
hdev->acl_cnt += conn->sent;
|
||||
} else if (conn->type == LE_LINK) {
|
||||
cancel_delayed_work_sync(&conn->le_conn_timeout);
|
||||
|
||||
if (hdev->le_pkts)
|
||||
hdev->le_cnt += conn->sent;
|
||||
else
|
||||
@@ -515,7 +528,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
|
||||
EXPORT_SYMBOL(hci_get_route);
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void le_conn_failed(struct hci_conn *conn, u8 status)
|
||||
void hci_le_conn_failed(struct hci_conn *conn, u8 status)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
@@ -527,6 +540,11 @@ static void le_conn_failed(struct hci_conn *conn, u8 status)
|
||||
hci_proto_connect_cfm(conn, status);
|
||||
|
||||
hci_conn_del(conn);
|
||||
|
||||
/* Since we may have temporarily stopped the background scanning in
|
||||
* favor of connection establishment, we should restart it.
|
||||
*/
|
||||
hci_update_background_scan(hdev);
|
||||
}
|
||||
|
||||
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
||||
@@ -545,50 +563,55 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
||||
if (!conn)
|
||||
goto done;
|
||||
|
||||
le_conn_failed(conn, status);
|
||||
hci_le_conn_failed(conn, status);
|
||||
|
||||
done:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_create_le_conn(struct hci_conn *conn)
|
||||
static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||
struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_le_create_conn cp;
|
||||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
u8 own_addr_type;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
/* Update random address, but set require_privacy to false so
|
||||
* that we never connect with an unresolvable address.
|
||||
*/
|
||||
if (hci_update_random_address(req, false, &own_addr_type))
|
||||
return;
|
||||
|
||||
/* Save the address type used for this connnection attempt so we able
|
||||
* to retrieve this information if we need it.
|
||||
*/
|
||||
conn->src_type = own_addr_type;
|
||||
|
||||
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
|
||||
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
|
||||
bacpy(&cp.peer_addr, &conn->dst);
|
||||
cp.peer_addr_type = conn->dst_type;
|
||||
cp.own_address_type = conn->src_type;
|
||||
cp.own_address_type = own_addr_type;
|
||||
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
|
||||
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
|
||||
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_req_add(&req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
|
||||
hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
|
||||
|
||||
err = hci_req_run(&req, create_le_conn_complete);
|
||||
if (err) {
|
||||
hci_conn_del(conn);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
conn->state = BT_CONNECT;
|
||||
}
|
||||
|
||||
static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
{
|
||||
struct hci_conn_params *params;
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->flags))
|
||||
@@ -617,12 +640,6 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
if (conn)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
/* Convert from L2CAP channel address type to HCI address type */
|
||||
if (dst_type == BDADDR_LE_PUBLIC)
|
||||
dst_type = ADDR_LE_DEV_PUBLIC;
|
||||
else
|
||||
dst_type = ADDR_LE_DEV_RANDOM;
|
||||
|
||||
/* When given an identity address with existing identity
|
||||
* resolving key, the connection needs to be established
|
||||
* to a resolvable random address.
|
||||
@@ -647,9 +664,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
conn->dst_type = dst_type;
|
||||
conn->src_type = hdev->own_addr_type;
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
@@ -665,17 +680,34 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
conn->le_conn_max_interval = hdev->le_conn_max_interval;
|
||||
}
|
||||
|
||||
err = hci_create_le_conn(conn);
|
||||
if (err)
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
/* If controller is scanning, we stop it since some controllers are
|
||||
* not able to scan and connect at the same time. Also set the
|
||||
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
|
||||
* handler for scan disabling knows to set the correct discovery
|
||||
* state.
|
||||
*/
|
||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
|
||||
hci_req_add_le_scan_disable(&req);
|
||||
set_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags);
|
||||
}
|
||||
|
||||
hci_req_add_le_create_conn(&req, conn);
|
||||
|
||||
err = hci_req_run(&req, create_le_conn_complete);
|
||||
if (err) {
|
||||
hci_conn_del(conn);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
done:
|
||||
hci_conn_hold(conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type)
|
||||
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type)
|
||||
{
|
||||
struct hci_conn *acl;
|
||||
|
||||
@@ -744,22 +776,6 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
return sco;
|
||||
}
|
||||
|
||||
/* Create SCO, ACL or LE connection. */
|
||||
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
__u8 dst_type, __u8 sec_level, __u8 auth_type)
|
||||
{
|
||||
BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
|
||||
|
||||
switch (type) {
|
||||
case LE_LINK:
|
||||
return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
|
||||
case ACL_LINK:
|
||||
return hci_connect_acl(hdev, dst, sec_level, auth_type);
|
||||
}
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* Check link security requirement */
|
||||
int hci_conn_check_link_mode(struct hci_conn *conn)
|
||||
{
|
||||
|
||||
+638
-43
File diff suppressed because it is too large
Load Diff
+259
-15
@@ -991,12 +991,8 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status) {
|
||||
if (*sent)
|
||||
set_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
else
|
||||
clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
}
|
||||
if (!status)
|
||||
mgmt_advertising(hdev, *sent);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
@@ -1022,7 +1018,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
break;
|
||||
|
||||
case LE_SCAN_DISABLE:
|
||||
/* Cancel this timer so that we don't try to disable scanning
|
||||
* when it's already disabled.
|
||||
*/
|
||||
cancel_delayed_work(&hdev->le_scan_disable);
|
||||
|
||||
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
/* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
|
||||
* interrupted scanning due to a connect request. Mark
|
||||
* therefore discovery as stopped.
|
||||
*/
|
||||
if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
|
||||
&hdev->dev_flags))
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1042,6 +1050,49 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
|
||||
hdev->le_white_list_size = rp->size;
|
||||
}
|
||||
|
||||
static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (!status)
|
||||
hci_white_list_clear(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_add_to_white_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status)
|
||||
hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type);
|
||||
}
|
||||
|
||||
static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_del_from_white_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status)
|
||||
hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type);
|
||||
}
|
||||
|
||||
static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -1082,6 +1133,25 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_set_adv_param *cp;
|
||||
u8 status = *((u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hdev->adv_addr_type = cp->own_address_type;
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -1583,6 +1653,57 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
|
||||
amp_write_remote_assoc(hdev, cp->phy_handle);
|
||||
}
|
||||
|
||||
static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_cp_le_create_conn *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
/* All connection failure handling is taken care of by the
|
||||
* hci_le_conn_failed function which is triggered by the HCI
|
||||
* request completion callbacks used for connecting.
|
||||
*/
|
||||
if (status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
/* Store the initiator and responder address information which
|
||||
* is needed for SMP. These values will not change during the
|
||||
* lifetime of the connection.
|
||||
*/
|
||||
conn->init_addr_type = cp->own_address_type;
|
||||
if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->init_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->init_addr, &hdev->bdaddr);
|
||||
|
||||
conn->resp_addr_type = cp->peer_addr_type;
|
||||
bacpy(&conn->resp_addr, &cp->peer_addr);
|
||||
|
||||
/* We don't want the connection attempt to stick around
|
||||
* indefinitely since LE doesn't have a page timeout concept
|
||||
* like BR/EDR. Set a timer for any connection that doesn't use
|
||||
* the white list for connecting.
|
||||
*/
|
||||
if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
|
||||
queue_delayed_work(conn->hdev->workqueue,
|
||||
&conn->le_conn_timeout,
|
||||
HCI_LE_CONN_TIMEOUT);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
@@ -1845,7 +1966,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_disconn_complete *ev = (void *) skb->data;
|
||||
u8 reason = hci_to_mgmt_reason(ev->reason);
|
||||
struct hci_conn_params *params;
|
||||
struct hci_conn *conn;
|
||||
bool mgmt_connected;
|
||||
u8 type;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
|
||||
@@ -1864,13 +1987,30 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, reason);
|
||||
mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
reason, mgmt_connected);
|
||||
|
||||
if (conn->type == ACL_LINK && conn->flush_key)
|
||||
hci_remove_link_key(hdev, &conn->dst);
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
switch (params->auto_connect) {
|
||||
case HCI_AUTO_CONN_LINK_LOSS:
|
||||
if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
|
||||
break;
|
||||
/* Fall through */
|
||||
|
||||
case HCI_AUTO_CONN_ALWAYS:
|
||||
hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type = conn->type;
|
||||
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
@@ -2344,6 +2484,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_le_read_white_list_size(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CLEAR_WHITE_LIST:
|
||||
hci_cc_le_clear_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_ADD_TO_WHITE_LIST:
|
||||
hci_cc_le_add_to_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_DEL_FROM_WHITE_LIST:
|
||||
hci_cc_le_del_from_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_READ_SUPPORTED_STATES:
|
||||
hci_cc_le_read_supported_states(hdev, skb);
|
||||
break;
|
||||
@@ -2352,6 +2504,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_write_le_host_supported(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_ADV_PARAM:
|
||||
hci_cc_set_adv_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
|
||||
hci_cc_write_remote_amp_assoc(hdev, skb);
|
||||
break;
|
||||
@@ -2439,6 +2595,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cs_accept_phylink(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CREATE_CONN:
|
||||
hci_cs_le_create_conn(hdev, ev->status);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
|
||||
break;
|
||||
@@ -3623,8 +3783,48 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
}
|
||||
|
||||
/* If we didn't have a hci_conn object previously
|
||||
* but we're in master role this must be something
|
||||
* initiated using a white list. Since white list based
|
||||
* connections are not "first class citizens" we don't
|
||||
* have full tracking of them. Therefore, we go ahead
|
||||
* with a "best effort" approach of determining the
|
||||
* initiator address based on the HCI_PRIVACY flag.
|
||||
*/
|
||||
if (conn->out) {
|
||||
conn->resp_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->resp_addr, &ev->bdaddr);
|
||||
if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
|
||||
conn->init_addr_type = ADDR_LE_DEV_RANDOM;
|
||||
bacpy(&conn->init_addr, &hdev->rpa);
|
||||
} else {
|
||||
hci_copy_identity_address(hdev,
|
||||
&conn->init_addr,
|
||||
&conn->init_addr_type);
|
||||
}
|
||||
} else {
|
||||
/* Set the responder (our side) address type based on
|
||||
* the advertising address type.
|
||||
*/
|
||||
conn->resp_addr_type = hdev->adv_addr_type;
|
||||
if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->resp_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->resp_addr, &hdev->bdaddr);
|
||||
|
||||
conn->init_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->init_addr, &ev->bdaddr);
|
||||
}
|
||||
} else {
|
||||
cancel_delayed_work(&conn->le_conn_timeout);
|
||||
}
|
||||
|
||||
/* Ensure that the hci_conn contains the identity address type
|
||||
* regardless of which address the connection was made with.
|
||||
*/
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
|
||||
/* Lookup the identity address from the stored connection
|
||||
* address and address type.
|
||||
*
|
||||
@@ -3641,11 +3841,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
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);
|
||||
hci_le_conn_failed(conn, ev->status);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@@ -3664,25 +3860,73 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
|
||||
hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
|
||||
u8 addr_type)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
|
||||
/* If this is a resolvable address, we should resolve it and then
|
||||
* update address and address type variables.
|
||||
*/
|
||||
irk = hci_get_irk(hdev, addr, addr_type);
|
||||
if (irk) {
|
||||
addr = &irk->bdaddr;
|
||||
addr_type = irk->addr_type;
|
||||
}
|
||||
|
||||
if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
|
||||
return;
|
||||
|
||||
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
|
||||
HCI_AT_NO_BONDING);
|
||||
if (!IS_ERR(conn))
|
||||
return;
|
||||
|
||||
switch (PTR_ERR(conn)) {
|
||||
case -EBUSY:
|
||||
/* If hci_connect() returns -EBUSY it means there is already
|
||||
* an LE connection attempt going on. Since controllers don't
|
||||
* support more than one connection attempt at the time, we
|
||||
* don't consider this an error case.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
s8 rssi;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
while (num_reports--) {
|
||||
struct hci_ev_le_advertising_info *ev = ptr;
|
||||
|
||||
if (ev->evt_type == LE_ADV_IND ||
|
||||
ev->evt_type == LE_ADV_DIRECT_IND)
|
||||
check_pending_le_conn(hdev, &ev->bdaddr,
|
||||
ev->bdaddr_type);
|
||||
|
||||
rssi = ev->data[ev->length];
|
||||
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
|
||||
NULL, rssi, 0, 1, ev->data, ev->length);
|
||||
|
||||
ptr += sizeof(*ev) + ev->length + 1;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
@@ -3701,7 +3945,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (conn == NULL)
|
||||
goto not_found;
|
||||
|
||||
ltk = hci_find_ltk(hdev, ev->ediv, ev->random, conn->out);
|
||||
ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out);
|
||||
if (ltk == NULL)
|
||||
goto not_found;
|
||||
|
||||
|
||||
@@ -2434,6 +2434,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
/* Channel lock is released before requesting new skb and then
|
||||
* reacquired thus we need to recheck channel state.
|
||||
*/
|
||||
if (chan->state != BT_CONNECTED) {
|
||||
kfree_skb(skb);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
l2cap_do_send(chan, skb);
|
||||
return len;
|
||||
}
|
||||
@@ -2483,6 +2491,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
/* Channel lock is released before requesting new skb and then
|
||||
* reacquired thus we need to recheck channel state.
|
||||
*/
|
||||
if (chan->state != BT_CONNECTED) {
|
||||
kfree_skb(skb);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
l2cap_do_send(chan, skb);
|
||||
err = len;
|
||||
break;
|
||||
@@ -7092,12 +7108,19 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
|
||||
auth_type = l2cap_get_auth_type(chan);
|
||||
|
||||
if (bdaddr_type_is_le(dst_type))
|
||||
hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
|
||||
chan->sec_level, auth_type);
|
||||
else
|
||||
hcon = hci_connect(hdev, ACL_LINK, dst, dst_type,
|
||||
chan->sec_level, auth_type);
|
||||
if (bdaddr_type_is_le(dst_type)) {
|
||||
/* Convert from L2CAP channel address type to HCI address type
|
||||
*/
|
||||
if (dst_type == BDADDR_LE_PUBLIC)
|
||||
dst_type = ADDR_LE_DEV_PUBLIC;
|
||||
else
|
||||
dst_type = ADDR_LE_DEV_RANDOM;
|
||||
|
||||
hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level,
|
||||
auth_type);
|
||||
} else {
|
||||
hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
|
||||
}
|
||||
|
||||
if (IS_ERR(hcon)) {
|
||||
err = PTR_ERR(hcon);
|
||||
@@ -7251,7 +7274,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||
|
||||
if (hcon->type == LE_LINK) {
|
||||
if (!status && encrypt)
|
||||
smp_distribute_keys(conn, 0);
|
||||
smp_distribute_keys(conn);
|
||||
cancel_delayed_work(&conn->security_timer);
|
||||
}
|
||||
|
||||
|
||||
+347
-76
File diff suppressed because it is too large
Load Diff
+136
-44
@@ -124,6 +124,24 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
return !memcmp(bdaddr->b, hash, 3);
|
||||
}
|
||||
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
|
||||
{
|
||||
int err;
|
||||
|
||||
get_random_bytes(&rpa->b[3], 3);
|
||||
|
||||
rpa->b[5] &= 0x3f; /* Clear two most significant bits */
|
||||
rpa->b[5] |= 0x40; /* Set second most significant bit */
|
||||
|
||||
err = smp_ah(tfm, irk, &rpa->b[3], rpa->b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
BT_DBG("RPA %pMR", rpa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
|
||||
u8 _rat, bdaddr_t *ra, u8 res[16])
|
||||
@@ -265,6 +283,9 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
||||
if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
|
||||
remote_dist |= SMP_DIST_ID_KEY;
|
||||
|
||||
if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
|
||||
local_dist |= SMP_DIST_ID_KEY;
|
||||
|
||||
if (rsp == NULL) {
|
||||
req->io_capability = conn->hcon->io_capability;
|
||||
req->oob_flag = SMP_OOB_NOT_PRESENT;
|
||||
@@ -424,14 +445,9 @@ static void confirm_work(struct work_struct *work)
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (conn->hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->src_type, &conn->hcon->src,
|
||||
conn->hcon->dst_type, &conn->hcon->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->dst_type, &conn->hcon->dst,
|
||||
conn->hcon->src_type, &conn->hcon->src, res);
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->init_addr_type, &conn->hcon->init_addr,
|
||||
conn->hcon->resp_addr_type, &conn->hcon->resp_addr, res);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@@ -471,14 +487,9 @@ static void random_work(struct work_struct *work)
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->src_type, &hcon->src,
|
||||
hcon->dst_type, &hcon->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->dst_type, &hcon->dst,
|
||||
hcon->src_type, &hcon->src, res);
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->init_addr_type, &hcon->init_addr,
|
||||
hcon->resp_addr_type, &hcon->resp_addr, res);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@@ -496,11 +507,9 @@ static void random_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (hcon->out) {
|
||||
u8 stk[16], rand[8];
|
||||
__le16 ediv;
|
||||
|
||||
memset(rand, 0, sizeof(rand));
|
||||
ediv = 0;
|
||||
u8 stk[16];
|
||||
__le64 rand = 0;
|
||||
__le16 ediv = 0;
|
||||
|
||||
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
|
||||
swap128(key, stk);
|
||||
@@ -516,11 +525,9 @@ static void random_work(struct work_struct *work)
|
||||
hci_le_start_enc(hcon, ediv, rand, stk);
|
||||
hcon->enc_key_size = smp->enc_key_size;
|
||||
} else {
|
||||
u8 stk[16], r[16], rand[8];
|
||||
__le16 ediv;
|
||||
|
||||
memset(rand, 0, sizeof(rand));
|
||||
ediv = 0;
|
||||
u8 stk[16], r[16];
|
||||
__le64 rand = 0;
|
||||
__le16 ediv = 0;
|
||||
|
||||
swap128(smp->prnd, r);
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
|
||||
@@ -542,6 +549,20 @@ error:
|
||||
smp_failure(conn, reason);
|
||||
}
|
||||
|
||||
static void smp_reencrypt(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan,
|
||||
reencrypt.work);
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_ltk *ltk = smp->ltk;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val);
|
||||
hcon->enc_key_size = ltk->enc_size;
|
||||
}
|
||||
|
||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_chan *smp;
|
||||
@@ -552,6 +573,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
|
||||
INIT_WORK(&smp->confirm, confirm_work);
|
||||
INIT_WORK(&smp->random, random_work);
|
||||
INIT_DELAYED_WORK(&smp->reencrypt, smp_reencrypt);
|
||||
|
||||
smp->conn = conn;
|
||||
conn->smp_chan = smp;
|
||||
@@ -569,9 +591,29 @@ void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
|
||||
BUG_ON(!smp);
|
||||
|
||||
cancel_delayed_work_sync(&smp->reencrypt);
|
||||
|
||||
complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
|
||||
mgmt_smp_complete(conn->hcon, complete);
|
||||
|
||||
/* If pairing failed clean up any keys we might have */
|
||||
if (!complete) {
|
||||
if (smp->ltk) {
|
||||
list_del(&smp->ltk->list);
|
||||
kfree(smp->ltk);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
list_del(&smp->slave_ltk->list);
|
||||
kfree(smp->slave_ltk);
|
||||
}
|
||||
|
||||
if (smp->remote_irk) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
conn->hcon->smp_conn = NULL;
|
||||
@@ -927,6 +969,9 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
|
||||
return 0;
|
||||
|
||||
/* Mark the information as received */
|
||||
smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
@@ -936,7 +981,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
rp->ediv, rp->rand);
|
||||
smp->ltk = ltk;
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
smp_distribute_keys(conn, 1);
|
||||
smp_distribute_keys(conn);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
@@ -980,8 +1025,24 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
return 0;
|
||||
|
||||
/* Mark the information as received */
|
||||
smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
|
||||
|
||||
skb_pull(skb, sizeof(*info));
|
||||
|
||||
/* Strictly speaking the Core Specification (4.1) allows sending
|
||||
* an empty address which would force us to rely on just the IRK
|
||||
* as "identity information". However, since such
|
||||
* implementations are not known of and in order to not over
|
||||
* complicate our implementation, simply pretend that we never
|
||||
* received an IRK for such a device.
|
||||
*/
|
||||
if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
|
||||
BT_ERR("Ignoring IRK with no identity address");
|
||||
smp_distribute_keys(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bacpy(&smp->id_addr, &info->bdaddr);
|
||||
smp->id_addr_type = info->addr_type;
|
||||
|
||||
@@ -999,7 +1060,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
|
||||
l2cap_conn_update_id_addr(hcon);
|
||||
|
||||
smp_distribute_keys(conn, 1);
|
||||
smp_distribute_keys(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1128,26 +1189,29 @@ static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
}
|
||||
}
|
||||
|
||||
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
int smp_distribute_keys(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_cmd_pairing *req, *rsp;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
bool ltk_encrypt;
|
||||
__u8 *keydist;
|
||||
|
||||
BT_DBG("conn %p force %d", conn, force);
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
|
||||
/* The responder sends its keys first */
|
||||
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
|
||||
if (hcon->out && (smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
|
||||
req = (void *) &smp->preq[1];
|
||||
|
||||
if (conn->hcon->out) {
|
||||
if (hcon->out) {
|
||||
keydist = &rsp->init_key_dist;
|
||||
*keydist &= req->init_key_dist;
|
||||
} else {
|
||||
@@ -1160,24 +1224,25 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
struct smp_cmd_master_ident ident;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
__le16 ediv;
|
||||
__le64 rand;
|
||||
|
||||
get_random_bytes(enc.ltk, sizeof(enc.ltk));
|
||||
get_random_bytes(&ediv, sizeof(ediv));
|
||||
get_random_bytes(ident.rand, sizeof(ident.rand));
|
||||
get_random_bytes(&rand, sizeof(rand));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
|
||||
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
smp->enc_key_size, ediv, ident.rand);
|
||||
smp->enc_key_size, ediv, rand);
|
||||
smp->slave_ltk = ltk;
|
||||
|
||||
ident.ediv = ediv;
|
||||
ident.rand = rand;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
|
||||
|
||||
@@ -1188,14 +1253,18 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
struct smp_cmd_ident_addr_info addrinfo;
|
||||
struct smp_cmd_ident_info idinfo;
|
||||
|
||||
/* Send a dummy key */
|
||||
get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
|
||||
memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
|
||||
|
||||
/* Just public address */
|
||||
memset(&addrinfo, 0, sizeof(addrinfo));
|
||||
bacpy(&addrinfo.bdaddr, &conn->hcon->src);
|
||||
/* The hci_conn contains the local identity address
|
||||
* after the connection has been established.
|
||||
*
|
||||
* This is true even when the connection has been
|
||||
* established using a resolvable random address.
|
||||
*/
|
||||
bacpy(&addrinfo.bdaddr, &hcon->src);
|
||||
addrinfo.addr_type = hcon->src_type;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
|
||||
&addrinfo);
|
||||
@@ -1214,8 +1283,31 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
*keydist &= ~SMP_DIST_SIGN;
|
||||
}
|
||||
|
||||
if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) {
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
|
||||
/* If there are still keys to be received wait for them */
|
||||
if ((smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
|
||||
/* Check if we should try to re-encrypt the link with the LTK.
|
||||
* SMP_FLAG_LTK_ENCRYPT flag is used to track whether we've
|
||||
* already tried this (in which case we shouldn't try again).
|
||||
*
|
||||
* The request will trigger an encryption key refresh event
|
||||
* which will cause a call to auth_cfm and eventually lead to
|
||||
* l2cap_core.c calling this smp_distribute_keys function again
|
||||
* and thereby completing the process.
|
||||
*/
|
||||
if (smp->ltk)
|
||||
ltk_encrypt = !test_and_set_bit(SMP_FLAG_LTK_ENCRYPT,
|
||||
&smp->smp_flags);
|
||||
else
|
||||
ltk_encrypt = false;
|
||||
|
||||
/* Re-encrypt the link with LTK if possible */
|
||||
if (ltk_encrypt && hcon->out) {
|
||||
queue_delayed_work(hdev->req_workqueue, &smp->reencrypt,
|
||||
SMP_REENCRYPT_TIMEOUT);
|
||||
} else {
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
|
||||
smp_notify_keys(conn);
|
||||
|
||||
+8
-3
@@ -78,7 +78,7 @@ struct smp_cmd_encrypt_info {
|
||||
#define SMP_CMD_MASTER_IDENT 0x07
|
||||
struct smp_cmd_master_ident {
|
||||
__le16 ediv;
|
||||
__u8 rand[8];
|
||||
__le64 rand;
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_IDENT_INFO 0x08
|
||||
@@ -118,7 +118,10 @@ struct smp_cmd_security_req {
|
||||
#define SMP_FLAG_TK_VALID 1
|
||||
#define SMP_FLAG_CFM_PENDING 2
|
||||
#define SMP_FLAG_MITM_AUTH 3
|
||||
#define SMP_FLAG_COMPLETE 4
|
||||
#define SMP_FLAG_LTK_ENCRYPT 4
|
||||
#define SMP_FLAG_COMPLETE 5
|
||||
|
||||
#define SMP_REENCRYPT_TIMEOUT msecs_to_jiffies(250)
|
||||
|
||||
struct smp_chan {
|
||||
struct l2cap_conn *conn;
|
||||
@@ -139,18 +142,20 @@ struct smp_chan {
|
||||
unsigned long smp_flags;
|
||||
struct work_struct confirm;
|
||||
struct work_struct random;
|
||||
struct delayed_work reencrypt;
|
||||
};
|
||||
|
||||
/* SMP Commands */
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
|
||||
int smp_conn_security(struct hci_conn *hcon, __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_distribute_keys(struct l2cap_conn *conn);
|
||||
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
|
||||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn);
|
||||
|
||||
bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
|
||||
|
||||
#endif /* __SMP_H */
|
||||
|
||||
Reference in New Issue
Block a user