Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ffd2e9a authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-upstream' of...

parents 3e3831c4 81ad6fd9
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -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;

+67 −11
Original line number Diff line number Diff line
@@ -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
+9 −1
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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);

	err = hci_req_run(&req, create_le_conn_complete);
	if (err) {
		hci_conn_del(conn);
		return err;
	}
	hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);

	return 0;
	conn->state = BT_CONNECT;
}

static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
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,16 +680,33 @@ 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,
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)
{
+637 −42

File changed.

Preview size limit exceeded, changes collapsed.

Loading