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

Commit 9662cbc7 authored by John W. Linville's avatar John W. Linville
Browse files
parents 640f5950 4b0b2f08
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ enum {

#define LMP_EV4		0x01
#define LMP_EV5		0x02
#define LMP_NO_BREDR	0x20
#define LMP_LE		0x40

#define LMP_SNIFF_SUBR	0x02
@@ -745,6 +746,14 @@ struct hci_rp_read_bd_addr {
	bdaddr_t bdaddr;
} __packed;

#define HCI_OP_READ_DATA_BLOCK_SIZE	0x100a
struct hci_rp_read_data_block_size {
	__u8     status;
	__le16   max_acl_len;
	__le16   block_len;
	__le16   num_blocks;
} __packed;

#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY	0x0c1c
struct hci_cp_write_page_scan_activity {
	__le16   interval;
+57 −61
Original line number Diff line number Diff line
@@ -61,18 +61,11 @@ struct inquiry_cache {

struct hci_conn_hash {
	struct list_head list;
	spinlock_t       lock;
	unsigned int     acl_num;
	unsigned int     sco_num;
	unsigned int     le_num;
};

struct hci_chan_hash {
	struct list_head list;
	spinlock_t       lock;
	unsigned int     num;
};

struct bdaddr_list {
	struct list_head list;
	bdaddr_t bdaddr;
@@ -124,7 +117,7 @@ struct adv_entry {
#define NUM_REASSEMBLY 4
struct hci_dev {
	struct list_head list;
	spinlock_t	lock;
	struct mutex	lock;
	atomic_t	refcnt;

	char		name[8];
@@ -188,6 +181,11 @@ struct hci_dev {
	unsigned int	sco_pkts;
	unsigned int	le_pkts;

	__u16		block_len;
	__u16		block_mtu;
	__u16		num_blocks;
	__u16		block_cnt;

	unsigned long	acl_last_tx;
	unsigned long	sco_last_tx;
	unsigned long	le_last_tx;
@@ -200,10 +198,13 @@ struct hci_dev {
	__u16			discov_timeout;
	struct delayed_work	discov_off;

	struct delayed_work	service_cache;

	struct timer_list	cmd_timer;
	struct tasklet_struct	cmd_task;
	struct tasklet_struct	rx_task;
	struct tasklet_struct	tx_task;

	struct work_struct	rx_work;
	struct work_struct	cmd_work;
	struct work_struct	tx_work;

	struct sk_buff_head	rx_q;
	struct sk_buff_head	raw_q;
@@ -232,7 +233,7 @@ struct hci_dev {
	struct list_head	remote_oob_data;

	struct list_head	adv_entries;
	struct timer_list	adv_timer;
	struct delayed_work	adv_work;

	struct hci_dev_stats	stat;

@@ -301,15 +302,12 @@ struct hci_conn {
	unsigned int	sent;

	struct sk_buff_head data_q;
	struct hci_chan_hash chan_hash;
	struct list_head chan_list;

	struct timer_list disc_timer;
	struct delayed_work disc_work;
	struct timer_list idle_timer;
	struct timer_list auto_accept_timer;

	struct work_struct work_add;
	struct work_struct work_del;

	struct device	dev;
	atomic_t	devref;

@@ -390,15 +388,15 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	INIT_LIST_HEAD(&h->list);
	spin_lock_init(&h->lock);
	h->acl_num = 0;
	h->sco_num = 0;
	h->le_num = 0;
}

static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	list_add(&c->list, &h->list);
	list_add_rcu(&c->list, &h->list);
	switch (c->type) {
	case ACL_LINK:
		h->acl_num++;
@@ -416,7 +414,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	list_del(&c->list);

	list_del_rcu(&c->list);
	synchronize_rcu();

	switch (c->type) {
	case ACL_LINK:
		h->acl_num--;
@@ -451,14 +452,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
								__u16 handle)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct list_head *p;
	struct hci_conn  *c;

	list_for_each(p, &h->list) {
		c = list_entry(p, struct hci_conn, list);
		if (c->handle == handle)
	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->handle == handle) {
			rcu_read_unlock();
			return c;
		}
	}
	rcu_read_unlock();

	return NULL;
}

@@ -466,14 +471,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
							__u8 type, bdaddr_t *ba)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct list_head *p;
	struct hci_conn  *c;

	list_for_each(p, &h->list) {
		c = list_entry(p, struct hci_conn, list);
		if (c->type == type && !bacmp(&c->dst, ba))
	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type == type && !bacmp(&c->dst, ba)) {
			rcu_read_unlock();
			return c;
		}
	}

	rcu_read_unlock();

	return NULL;
}

@@ -481,37 +491,20 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
							__u8 type, __u16 state)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct list_head *p;
	struct hci_conn  *c;

	list_for_each(p, &h->list) {
		c = list_entry(p, struct hci_conn, list);
		if (c->type == type && c->state == state)
	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type == type && c->state == state) {
			rcu_read_unlock();
			return c;
		}
	return NULL;
	}

static inline void hci_chan_hash_init(struct hci_conn *c)
{
	struct hci_chan_hash *h = &c->chan_hash;
	INIT_LIST_HEAD(&h->list);
	spin_lock_init(&h->lock);
	h->num = 0;
}

static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
{
	struct hci_chan_hash *h = &c->chan_hash;
	list_add(&chan->list, &h->list);
	h->num++;
}
	rcu_read_unlock();

static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
{
	struct hci_chan_hash *h = &c->chan_hash;
	list_del(&chan->list);
	h->num--;
	return NULL;
}

void hci_acl_connect(struct hci_conn *conn);
@@ -527,7 +520,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);

struct hci_chan *hci_chan_create(struct hci_conn *conn);
int hci_chan_del(struct hci_chan *chan);
void hci_chan_hash_flush(struct hci_conn *conn);
void hci_chan_list_flush(struct hci_conn *conn);

struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
						__u8 sec_level, __u8 auth_type);
@@ -538,7 +531,6 @@ int hci_conn_change_link_key(struct hci_conn *conn);
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_conn_enter_sniff_mode(struct hci_conn *conn);

void hci_conn_hold_device(struct hci_conn *conn);
void hci_conn_put_device(struct hci_conn *conn);
@@ -546,7 +538,7 @@ void hci_conn_put_device(struct hci_conn *conn);
static inline void hci_conn_hold(struct hci_conn *conn)
{
	atomic_inc(&conn->refcnt);
	del_timer(&conn->disc_timer);
	cancel_delayed_work_sync(&conn->disc_work);
}

static inline void hci_conn_put(struct hci_conn *conn)
@@ -565,7 +557,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
		} else {
			timeo = msecs_to_jiffies(10);
		}
		mod_timer(&conn->disc_timer, jiffies + timeo);
		cancel_delayed_work_sync(&conn->disc_work);
		queue_delayed_work(conn->hdev->workqueue,
					&conn->disc_work, jiffies + timeo);
	}
}

@@ -597,10 +591,8 @@ static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
	try_module_get(d->owner) ? __hci_dev_hold(d) : NULL;	\
})

#define hci_dev_lock(d)		spin_lock(&d->lock)
#define hci_dev_unlock(d)	spin_unlock(&d->lock)
#define hci_dev_lock_bh(d)	spin_lock_bh(&d->lock)
#define hci_dev_unlock_bh(d)	spin_unlock_bh(&d->lock)
#define hci_dev_lock(d)		mutex_lock(&d->lock)
#define hci_dev_unlock(d)	mutex_unlock(&d->lock)

struct hci_dev *hci_dev_get(int index);
struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
@@ -960,12 +952,16 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)

/* HCI socket flags */
#define HCI_PI_MGMT_INIT	0

struct hci_pinfo {
	struct bt_sock    bt;
	struct hci_dev    *hdev;
	struct hci_filter filter;
	__u32             cmsg_mask;
	unsigned short   channel;
	unsigned long     flags;
};

/* HCI security filter */
+13 −11
Original line number Diff line number Diff line
@@ -482,10 +482,11 @@ struct l2cap_chan {
	__u32		remote_acc_lat;
	__u32		remote_flush_to;

	struct timer_list	chan_timer;
	struct timer_list	retrans_timer;
	struct timer_list	monitor_timer;
	struct timer_list	ack_timer;
	struct delayed_work	chan_timer;
	struct delayed_work	retrans_timer;
	struct delayed_work	monitor_timer;
	struct delayed_work	ack_timer;

	struct sk_buff		*tx_send_head;
	struct sk_buff_head	tx_q;
	struct sk_buff_head	srej_q;
@@ -521,7 +522,7 @@ struct l2cap_conn {
	__u8		info_state;
	__u8		info_ident;

	struct timer_list info_timer;
	struct delayed_work info_work;

	spinlock_t	lock;

@@ -535,7 +536,7 @@ struct l2cap_conn {
	struct smp_chan *smp_chan;

	struct list_head chan_l;
	rwlock_t	chan_lock;
	struct mutex	chan_lock;
};

#define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
@@ -595,16 +596,16 @@ enum {
};

#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __clear_chan_timer(c) l2cap_clear_timer(&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, &c->retrans_timer)
#define __clear_retrans_timer(c) l2cap_clear_timer(&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, &c->monitor_timer)
#define __clear_monitor_timer(c) l2cap_clear_timer(&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, &c->ack_timer)
#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer)

static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{
@@ -805,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);
inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
								bdaddr_t *dst);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
								u32 priority);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
+108 −83
Original line number Diff line number Diff line
@@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list {
/* Reserve one extra byte for names in management messages so that they
 * are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH		(HCI_MAX_NAME_LENGTH + 1)
#define MGMT_MAX_SHORT_NAME_LENGTH	(10 + 1)

#define MGMT_SETTING_POWERED		0x00000001
#define MGMT_SETTING_CONNECTABLE	0x00000002
#define MGMT_SETTING_FAST_CONNECTABLE	0x00000004
#define MGMT_SETTING_DISCOVERABLE	0x00000008
#define MGMT_SETTING_PAIRABLE		0x00000010
#define MGMT_SETTING_LINK_SECURITY	0x00000020
#define MGMT_SETTING_SSP		0x00000040
#define MGMT_SETTING_BREDR		0x00000080
#define MGMT_SETTING_HS			0x00000100
#define MGMT_SETTING_LE			0x00000200

#define MGMT_OP_READ_INFO		0x0004
struct mgmt_rp_read_info {
	__u8 type;
	__u8 powered;
	__u8 connectable;
	__u8 discoverable;
	__u8 pairable;
	__u8 sec_mode;
	bdaddr_t bdaddr;
	__u8 version;
	__le16 manufacturer;
	__le32 supported_settings;
	__le32 current_settings;
	__u8 dev_class[3];
	__u8 features[8];
	__u16 manufacturer;
	__u8 hci_ver;
	__u16 hci_rev;
	__u8 name[MGMT_MAX_NAME_LENGTH];
	__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;

struct mgmt_mode {
@@ -93,28 +100,38 @@ struct mgmt_cp_set_discoverable {

#define MGMT_OP_SET_CONNECTABLE		0x0007

#define MGMT_OP_SET_PAIRABLE		0x0008
#define MGMT_OP_SET_FAST_CONNECTABLE	0x0008

#define MGMT_OP_ADD_UUID		0x0009
struct mgmt_cp_add_uuid {
	__u8 uuid[16];
	__u8 svc_hint;
} __packed;
#define MGMT_OP_SET_PAIRABLE		0x0009

#define MGMT_OP_REMOVE_UUID		0x000A
struct mgmt_cp_remove_uuid {
	__u8 uuid[16];
} __packed;
#define MGMT_OP_SET_LINK_SECURITY	0x000A

#define MGMT_OP_SET_DEV_CLASS		0x000B
#define MGMT_OP_SET_SSP			0x000B

#define MGMT_OP_SET_HS			0x000C

#define MGMT_OP_SET_LE			0x000D

#define MGMT_OP_SET_DEV_CLASS		0x000E
struct mgmt_cp_set_dev_class {
	__u8 major;
	__u8 minor;
} __packed;

#define MGMT_OP_SET_SERVICE_CACHE	0x000C
struct mgmt_cp_set_service_cache {
	__u8 enable;
#define MGMT_OP_SET_LOCAL_NAME		0x000F
struct mgmt_cp_set_local_name {
	__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;

#define MGMT_OP_ADD_UUID		0x0010
struct mgmt_cp_add_uuid {
	__u8 uuid[16];
	__u8 svc_hint;
} __packed;

#define MGMT_OP_REMOVE_UUID		0x0011
struct mgmt_cp_remove_uuid {
	__u8 uuid[16];
} __packed;

struct mgmt_link_key_info {
@@ -124,14 +141,14 @@ struct mgmt_link_key_info {
	u8 pin_len;
} __packed;

#define MGMT_OP_LOAD_LINK_KEYS		0x000D
#define MGMT_OP_LOAD_LINK_KEYS		0x0012
struct mgmt_cp_load_link_keys {
	__u8 debug_keys;
	__le16 key_count;
	struct mgmt_link_key_info keys[0];
} __packed;

#define MGMT_OP_REMOVE_KEYS		0x000E
#define MGMT_OP_REMOVE_KEYS		0x0013
struct mgmt_cp_remove_keys {
	bdaddr_t bdaddr;
	__u8 disconnect;
@@ -141,7 +158,7 @@ struct mgmt_rp_remove_keys {
	__u8 status;
};

#define MGMT_OP_DISCONNECT		0x000F
#define MGMT_OP_DISCONNECT		0x0014
struct mgmt_cp_disconnect {
	bdaddr_t bdaddr;
} __packed;
@@ -160,13 +177,13 @@ struct mgmt_addr_info {
	__u8 type;
} __packed;

#define MGMT_OP_GET_CONNECTIONS		0x0010
#define MGMT_OP_GET_CONNECTIONS		0x0015
struct mgmt_rp_get_connections {
	__le16 conn_count;
	struct mgmt_addr_info addr[0];
} __packed;

#define MGMT_OP_PIN_CODE_REPLY		0x0011
#define MGMT_OP_PIN_CODE_REPLY		0x0016
struct mgmt_cp_pin_code_reply {
	bdaddr_t bdaddr;
	__u8 pin_len;
@@ -177,17 +194,17 @@ struct mgmt_rp_pin_code_reply {
	uint8_t status;
} __packed;

#define MGMT_OP_PIN_CODE_NEG_REPLY	0x0012
#define MGMT_OP_PIN_CODE_NEG_REPLY	0x0017
struct mgmt_cp_pin_code_neg_reply {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_OP_SET_IO_CAPABILITY	0x0013
#define MGMT_OP_SET_IO_CAPABILITY	0x0018
struct mgmt_cp_set_io_capability {
	__u8 io_capability;
} __packed;

#define MGMT_OP_PAIR_DEVICE		0x0014
#define MGMT_OP_PAIR_DEVICE		0x0019
struct mgmt_cp_pair_device {
	struct mgmt_addr_info addr;
	__u8 io_cap;
@@ -197,7 +214,7 @@ struct mgmt_rp_pair_device {
	__u8 status;
} __packed;

#define MGMT_OP_USER_CONFIRM_REPLY	0x0015
#define MGMT_OP_USER_CONFIRM_REPLY	0x001A
struct mgmt_cp_user_confirm_reply {
	bdaddr_t bdaddr;
} __packed;
@@ -206,61 +223,68 @@ struct mgmt_rp_user_confirm_reply {
	__u8 status;
} __packed;

#define MGMT_OP_USER_CONFIRM_NEG_REPLY	0x0016
#define MGMT_OP_USER_CONFIRM_NEG_REPLY	0x001B
struct mgmt_cp_user_confirm_neg_reply {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_OP_SET_LOCAL_NAME		0x0017
struct mgmt_cp_set_local_name {
	__u8 name[MGMT_MAX_NAME_LENGTH];
#define MGMT_OP_USER_PASSKEY_REPLY	0x001C
struct mgmt_cp_user_passkey_reply {
	bdaddr_t bdaddr;
	__le32 passkey;
} __packed;
struct mgmt_rp_user_passkey_reply {
	bdaddr_t bdaddr;
	__u8 status;
} __packed;

#define MGMT_OP_READ_LOCAL_OOB_DATA	0x0018
#define MGMT_OP_USER_PASSKEY_NEG_REPLY	0x001D
struct mgmt_cp_user_passkey_neg_reply {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_OP_READ_LOCAL_OOB_DATA	0x001E
struct mgmt_rp_read_local_oob_data {
	__u8 hash[16];
	__u8 randomizer[16];
} __packed;

#define MGMT_OP_ADD_REMOTE_OOB_DATA	0x0019
#define MGMT_OP_ADD_REMOTE_OOB_DATA	0x001F
struct mgmt_cp_add_remote_oob_data {
	bdaddr_t bdaddr;
	__u8 hash[16];
	__u8 randomizer[16];
} __packed;

#define MGMT_OP_REMOVE_REMOTE_OOB_DATA	0x001A
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA	0x0020
struct mgmt_cp_remove_remote_oob_data {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_OP_START_DISCOVERY		0x001B
#define MGMT_OP_START_DISCOVERY		0x0021
struct mgmt_cp_start_discovery {
	__u8 type;
} __packed;

#define MGMT_OP_STOP_DISCOVERY		0x001C
#define MGMT_OP_STOP_DISCOVERY		0x0022

#define MGMT_OP_BLOCK_DEVICE		0x001D
struct mgmt_cp_block_device {
#define MGMT_OP_CONFIRM_NAME		0x0023
struct mgmt_cp_confirm_name {
	bdaddr_t bdaddr;
	__u8 name_known;
} __packed;

#define MGMT_OP_UNBLOCK_DEVICE		0x001E
struct mgmt_cp_unblock_device {
struct mgmt_rp_confirm_name {
	bdaddr_t bdaddr;
	__u8 status;
} __packed;

#define MGMT_OP_SET_FAST_CONNECTABLE	0x001F
struct mgmt_cp_set_fast_connectable {
	__u8 enable;
} __packed;

#define MGMT_OP_USER_PASSKEY_REPLY	0x0020
struct mgmt_cp_user_passkey_reply {
#define MGMT_OP_BLOCK_DEVICE		0x0024
struct mgmt_cp_block_device {
	bdaddr_t bdaddr;
	__le32 passkey;
} __packed;

#define MGMT_OP_USER_PASSKEY_NEG_REPLY	0x0021
struct mgmt_cp_user_passkey_neg_reply {
#define MGMT_OP_UNBLOCK_DEVICE		0x0025
struct mgmt_cp_unblock_device {
	bdaddr_t bdaddr;
} __packed;

@@ -285,81 +309,82 @@ struct mgmt_ev_controller_error {

#define MGMT_EV_INDEX_REMOVED		0x0005

#define MGMT_EV_POWERED			0x0006
#define MGMT_EV_NEW_SETTINGS		0x0006

#define MGMT_EV_DISCOVERABLE		0x0007

#define MGMT_EV_CONNECTABLE		0x0008
#define MGMT_EV_CLASS_OF_DEV_CHANGED	0x0007
struct mgmt_ev_class_of_dev_changed {
	__u8 dev_class[3];
};

#define MGMT_EV_PAIRABLE		0x0009
#define MGMT_EV_LOCAL_NAME_CHANGED	0x0008
struct mgmt_ev_local_name_changed {
	__u8 name[MGMT_MAX_NAME_LENGTH];
	__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;

#define MGMT_EV_NEW_LINK_KEY		0x000A
#define MGMT_EV_NEW_LINK_KEY		0x0009
struct mgmt_ev_new_link_key {
	__u8 store_hint;
	struct mgmt_link_key_info key;
} __packed;

#define MGMT_EV_CONNECTED		0x000B
#define MGMT_EV_CONNECTED		0x000A

#define MGMT_EV_DISCONNECTED		0x000C
#define MGMT_EV_DISCONNECTED		0x000B

#define MGMT_EV_CONNECT_FAILED		0x000D
#define MGMT_EV_CONNECT_FAILED		0x000C
struct mgmt_ev_connect_failed {
	struct mgmt_addr_info addr;
	__u8 status;
} __packed;

#define MGMT_EV_PIN_CODE_REQUEST	0x000E
#define MGMT_EV_PIN_CODE_REQUEST	0x000D
struct mgmt_ev_pin_code_request {
	bdaddr_t bdaddr;
	__u8 secure;
} __packed;

#define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
#define MGMT_EV_USER_CONFIRM_REQUEST	0x000E
struct mgmt_ev_user_confirm_request {
	bdaddr_t bdaddr;
	__u8 confirm_hint;
	__le32 value;
} __packed;

#define MGMT_EV_USER_PASSKEY_REQUEST	0x000F
struct mgmt_ev_user_passkey_request {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_EV_AUTH_FAILED		0x0010
struct mgmt_ev_auth_failed {
	bdaddr_t bdaddr;
	__u8 status;
} __packed;

#define MGMT_EV_LOCAL_NAME_CHANGED	0x0011
struct mgmt_ev_local_name_changed {
	__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;

#define MGMT_EV_DEVICE_FOUND		0x0012
#define MGMT_EV_DEVICE_FOUND		0x0011
struct mgmt_ev_device_found {
	struct mgmt_addr_info addr;
	__u8 dev_class[3];
	__s8 rssi;
	__u8 confirm_name;
	__u8 eir[HCI_MAX_EIR_LENGTH];
} __packed;

#define MGMT_EV_REMOTE_NAME		0x0013
#define MGMT_EV_REMOTE_NAME		0x0012
struct mgmt_ev_remote_name {
	bdaddr_t bdaddr;
	__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;

#define MGMT_EV_DISCOVERING		0x0014
#define MGMT_EV_DISCOVERING		0x0013

#define MGMT_EV_DEVICE_BLOCKED		0x0015
#define MGMT_EV_DEVICE_BLOCKED		0x0014
struct mgmt_ev_device_blocked {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_EV_DEVICE_UNBLOCKED	0x0016
#define MGMT_EV_DEVICE_UNBLOCKED	0x0015
struct mgmt_ev_device_unblocked {
	bdaddr_t bdaddr;
} __packed;

#define MGMT_EV_USER_PASSKEY_REQUEST	0x0017
struct mgmt_ev_user_passkey_request {
	bdaddr_t bdaddr;
} __packed;
+59 −78
Original line number Diff line number Diff line
@@ -275,9 +275,10 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
	}
}

static void hci_conn_timeout(unsigned long arg)
static void hci_conn_timeout(struct work_struct *work)
{
	struct hci_conn *conn = (void *) arg;
	struct hci_conn *conn = container_of(work, struct hci_conn,
							disc_work.work);
	struct hci_dev *hdev = conn->hdev;
	__u8 reason;

@@ -311,6 +312,42 @@ static void hci_conn_timeout(unsigned long arg)
	hci_dev_unlock(hdev);
}

/* Enter sniff mode */
static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("conn %p mode %d", conn, conn->mode);

	if (test_bit(HCI_RAW, &hdev->flags))
		return;

	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
		return;

	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
		return;

	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
		struct hci_cp_sniff_subrate cp;
		cp.handle             = cpu_to_le16(conn->handle);
		cp.max_latency        = cpu_to_le16(0);
		cp.min_remote_timeout = cpu_to_le16(0);
		cp.min_local_timeout  = cpu_to_le16(0);
		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
	}

	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
		struct hci_cp_sniff_mode cp;
		cp.handle       = cpu_to_le16(conn->handle);
		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
		cp.attempt      = cpu_to_le16(4);
		cp.timeout      = cpu_to_le16(1);
		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
	}
}

static void hci_conn_idle(unsigned long arg)
{
	struct hci_conn *conn = (void *) arg;
@@ -325,12 +362,8 @@ static void hci_conn_auto_accept(unsigned long arg)
	struct hci_conn *conn = (void *) arg;
	struct hci_dev *hdev = conn->hdev;

	hci_dev_lock(hdev);

	hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
								&conn->dst);

	hci_dev_unlock(hdev);
}

struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
@@ -374,9 +407,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)

	skb_queue_head_init(&conn->data_q);

	hci_chan_hash_init(conn);
	INIT_LIST_HEAD(&conn->chan_list);;

	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
	setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
							(unsigned long) conn);
@@ -385,8 +418,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)

	hci_dev_hold(hdev);

	tasklet_disable(&hdev->tx_task);

	hci_conn_hash_add(hdev, conn);
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
@@ -395,8 +426,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)

	hci_conn_init_sysfs(conn);

	tasklet_enable(&hdev->tx_task);

	return conn;
}

@@ -408,7 +437,7 @@ int hci_conn_del(struct hci_conn *conn)

	del_timer(&conn->idle_timer);

	del_timer(&conn->disc_timer);
	cancel_delayed_work_sync(&conn->disc_work);

	del_timer(&conn->auto_accept_timer);

@@ -432,16 +461,13 @@ int hci_conn_del(struct hci_conn *conn)
		}
	}

	tasklet_disable(&hdev->tx_task);

	hci_chan_hash_flush(conn);
	hci_chan_list_flush(conn);

	hci_conn_hash_del(hdev, conn);
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);

	tasklet_enable(&hdev->tx_task);

	skb_queue_purge(&conn->data_q);

	hci_conn_put_device(conn);
@@ -674,7 +700,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
		goto encrypt;

auth:
	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
		return 0;

	if (!hci_conn_auth(conn, sec_level, auth_type))
@@ -767,57 +793,15 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
			jiffies + msecs_to_jiffies(hdev->idle_timeout));
}

/* Enter sniff mode */
void hci_conn_enter_sniff_mode(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("conn %p mode %d", conn, conn->mode);

	if (test_bit(HCI_RAW, &hdev->flags))
		return;

	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
		return;

	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
		return;

	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
		struct hci_cp_sniff_subrate cp;
		cp.handle             = cpu_to_le16(conn->handle);
		cp.max_latency        = cpu_to_le16(0);
		cp.min_remote_timeout = cpu_to_le16(0);
		cp.min_local_timeout  = cpu_to_le16(0);
		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
	}

	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
		struct hci_cp_sniff_mode cp;
		cp.handle       = cpu_to_le16(conn->handle);
		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
		cp.attempt      = cpu_to_le16(4);
		cp.timeout      = cpu_to_le16(1);
		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
	}
}

/* Drop all connection on the device */
void hci_conn_hash_flush(struct hci_dev *hdev)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct list_head *p;

	BT_DBG("hdev %s", hdev->name);

	p = h->list.next;
	while (p != &h->list) {
	struct hci_conn *c;

		c = list_entry(p, struct hci_conn, list);
		p = p->next;
	BT_DBG("hdev %s", hdev->name);

	list_for_each_entry_rcu(c, &h->list, list) {
		c->state = BT_CLOSED;

		hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
@@ -882,7 +866,7 @@ int hci_get_conn_list(void __user *arg)

	ci = cl->conn_info;

	hci_dev_lock_bh(hdev);
	hci_dev_lock(hdev);
	list_for_each_entry(c, &hdev->conn_hash.list, list) {
		bacpy(&(ci + n)->bdaddr, &c->dst);
		(ci + n)->handle = c->handle;
@@ -893,7 +877,7 @@ int hci_get_conn_list(void __user *arg)
		if (++n >= req.conn_num)
			break;
	}
	hci_dev_unlock_bh(hdev);
	hci_dev_unlock(hdev);

	cl->dev_id = hdev->id;
	cl->conn_num = n;
@@ -917,7 +901,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
	if (copy_from_user(&req, arg, sizeof(req)))
		return -EFAULT;

	hci_dev_lock_bh(hdev);
	hci_dev_lock(hdev);
	conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
	if (conn) {
		bacpy(&ci.bdaddr, &conn->dst);
@@ -927,7 +911,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
		ci.state = conn->state;
		ci.link_mode = conn->link_mode;
	}
	hci_dev_unlock_bh(hdev);
	hci_dev_unlock(hdev);

	if (!conn)
		return -ENOENT;
@@ -943,11 +927,11 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
	if (copy_from_user(&req, arg, sizeof(req)))
		return -EFAULT;

	hci_dev_lock_bh(hdev);
	hci_dev_lock(hdev);
	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
	if (conn)
		req.type = conn->auth_type;
	hci_dev_unlock_bh(hdev);
	hci_dev_unlock(hdev);

	if (!conn)
		return -ENOENT;
@@ -969,9 +953,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
	chan->conn = conn;
	skb_queue_head_init(&chan->data_q);

	tasklet_disable(&hdev->tx_task);
	hci_chan_hash_add(conn, chan);
	tasklet_enable(&hdev->tx_task);
	list_add_rcu(&chan->list, &conn->chan_list);

	return chan;
}
@@ -983,9 +965,9 @@ int hci_chan_del(struct hci_chan *chan)

	BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);

	tasklet_disable(&hdev->tx_task);
	hci_chan_hash_del(conn, chan);
	tasklet_enable(&hdev->tx_task);
	list_del_rcu(&chan->list);

	synchronize_rcu();

	skb_queue_purge(&chan->data_q);
	kfree(chan);
@@ -993,13 +975,12 @@ int hci_chan_del(struct hci_chan *chan)
	return 0;
}

void hci_chan_hash_flush(struct hci_conn *conn)
void hci_chan_list_flush(struct hci_conn *conn)
{
	struct hci_chan_hash *h = &conn->chan_hash;
	struct hci_chan *chan, *tmp;
	struct hci_chan *chan;

	BT_DBG("conn %p", conn);

	list_for_each_entry_safe(chan, tmp, &h->list, list)
	list_for_each_entry_rcu(chan, &conn->chan_list, list)
		hci_chan_del(chan);
}
Loading