Commit b338d917 authored by Brian Gix's avatar Brian Gix Committed by Luiz Augusto von Dentz
Browse files

Bluetooth: Implement support for Mesh



The patch adds state bits, storage and HCI command chains for sending
and receiving Bluetooth Mesh advertising packets, and delivery to
requesting user space processes. It specifically creates 4 new MGMT
commands and 2 new MGMT events:

MGMT_OP_SET_MESH_RECEIVER - Sets passive scan parameters and a list of
AD Types which will trigger Mesh Packet Received events

MGMT_OP_MESH_READ_FEATURES - Returns information on how many outbound
Mesh packets can be simultaneously queued, and what the currently queued
handles are.

MGMT_OP_MESH_SEND - Command to queue a specific outbound Mesh packet,
with the number of times it should be sent, and the BD Addr to use.
Discrete advertisments are added to the ADV Instance list.

MGMT_OP_MESH_SEND_CANCEL - Command to cancel a prior outbound message
request.

MGMT_EV_MESH_DEVICE_FOUND - Event to deliver entire received Mesh
Advertisement packet, along with timing information.

MGMT_EV_MESH_PACKET_CMPLT - Event to indicate that an outbound packet is
no longer queued for delivery.

Signed-off-by: default avatarBrian Gix <brian.gix@intel.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent fd3f1066
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -627,6 +627,7 @@ static inline bool iso_enabled(void)

int mgmt_init(void);
void mgmt_exit(void);
void mgmt_cleanup(struct sock *sk);

void bt_sock_reclassify_lock(struct sock *sk, int proto);

+3 −0
Original line number Diff line number Diff line
@@ -354,6 +354,9 @@ enum {
	HCI_LE_SIMULTANEOUS_ROLES,
	HCI_CMD_DRAIN_WORKQUEUE,

	HCI_MESH,
	HCI_MESH_SENDING,

	__HCI_NUM_FLAGS,
};

+14 −2
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ struct adv_info {
	bool	enabled;
	bool	pending;
	bool	periodic;
	__u8	mesh;
	__u8	instance;
	__u32	flags;
	__u16	timeout;
@@ -372,6 +373,8 @@ struct hci_dev {
	__u8		le_resolv_list_size;
	__u8		le_num_of_adv_sets;
	__u8		le_states[8];
	__u8		mesh_ad_types[16];
	__u8		mesh_send_ref;
	__u8		commands[64];
	__u8		hci_ver;
	__u16		hci_rev;
@@ -511,6 +514,7 @@ struct hci_dev {
	struct list_head	cmd_sync_work_list;
	struct mutex		cmd_sync_work_lock;
	struct work_struct	cmd_sync_cancel_work;
	struct work_struct	reenable_adv_work;

	__u16			discov_timeout;
	struct delayed_work	discov_off;
@@ -561,6 +565,7 @@ struct hci_dev {

	struct hci_conn_hash	conn_hash;

	struct list_head	mesh_pending;
	struct list_head	mgmt_pending;
	struct list_head	reject_list;
	struct list_head	accept_list;
@@ -614,6 +619,8 @@ struct hci_dev {
	struct delayed_work	rpa_expired;
	bdaddr_t		rpa;

	struct delayed_work	mesh_send_done;

	enum {
		INTERLEAVE_SCAN_NONE,
		INTERLEAVE_SCAN_NO_FILTER,
@@ -1576,7 +1583,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
				      u32 flags, u16 adv_data_len, u8 *adv_data,
				      u16 scan_rsp_len, u8 *scan_rsp_data,
				      u16 timeout, u16 duration, s8 tx_power,
				      u32 min_interval, u32 max_interval);
				      u32 min_interval, u32 max_interval,
				      u8 mesh_handle);
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
				      u32 flags, u8 data_len, u8 *data,
				      u32 min_interval, u32 max_interval);
@@ -1997,6 +2005,9 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
#define DISCOV_LE_FAST_ADV_INT_MAX	0x00F0	/* 150 msec */
#define DISCOV_LE_PER_ADV_INT_MIN	0x00A0	/* 200 msec */
#define DISCOV_LE_PER_ADV_INT_MAX	0x00A0	/* 200 msec */
#define DISCOV_LE_ADV_MESH_MIN		0x00A0  /* 100 msec */
#define DISCOV_LE_ADV_MESH_MAX		0x00A0  /* 100 msec */
#define INTERVAL_TO_MS(x)		(((x) * 10) / 0x10)

#define NAME_RESOLVE_DURATION		msecs_to_jiffies(10240)	/* 10.24 sec */

@@ -2048,7 +2059,8 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status);
void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status);
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
		       u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
		       u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len);
		       u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len,
		       u64 instant);
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
		      u8 addr_type, s8 rssi, u8 *name, u8 name_len);
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+52 −0
Original line number Diff line number Diff line
@@ -837,6 +837,42 @@ struct mgmt_cp_add_adv_patterns_monitor_rssi {
	struct mgmt_adv_pattern patterns[];
} __packed;
#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE	8
#define MGMT_OP_SET_MESH_RECEIVER		0x0057
struct mgmt_cp_set_mesh {
	__u8   enable;
	__le16 window;
	__le16 period;
	__u8   num_ad_types;
	__u8   ad_types[];
} __packed;
#define MGMT_SET_MESH_RECEIVER_SIZE	6

#define MGMT_OP_MESH_READ_FEATURES	0x0058
#define MGMT_MESH_READ_FEATURES_SIZE	0
#define MESH_HANDLES_MAX	3
struct mgmt_rp_mesh_read_features {
	__le16	index;
	__u8   max_handles;
	__u8   used_handles;
	__u8   handles[MESH_HANDLES_MAX];
} __packed;

#define MGMT_OP_MESH_SEND		0x0059
struct mgmt_cp_mesh_send {
	struct mgmt_addr_info addr;
	__le64  instant;
	__le16  delay;
	__u8   cnt;
	__u8   adv_data_len;
	__u8   adv_data[];
} __packed;
#define MGMT_MESH_SEND_SIZE		19

#define MGMT_OP_MESH_SEND_CANCEL	0x005A
struct mgmt_cp_mesh_send_cancel {
	__u8  handle;
} __packed;
#define MGMT_MESH_SEND_CANCEL_SIZE	1

#define MGMT_EV_CMD_COMPLETE		0x0001
struct mgmt_ev_cmd_complete {
@@ -1120,3 +1156,19 @@ struct mgmt_ev_adv_monitor_device_lost {
	__le16 monitor_handle;
	struct mgmt_addr_info addr;
} __packed;

#define MGMT_EV_MESH_DEVICE_FOUND	0x0031
struct mgmt_ev_mesh_device_found {
	struct mgmt_addr_info addr;
	__s8	rssi;
	__le64	instant;
	__le32	flags;
	__le16	eir_len;
	__u8	eir[];
} __packed;


#define MGMT_EV_MESH_PACKET_CMPLT		0x0032
struct mgmt_ev_mesh_pkt_cmplt {
	__u8	handle;
} __packed;
+10 −3
Original line number Diff line number Diff line
@@ -1706,7 +1706,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
				      u32 flags, u16 adv_data_len, u8 *adv_data,
				      u16 scan_rsp_len, u8 *scan_rsp_data,
				      u16 timeout, u16 duration, s8 tx_power,
				      u32 min_interval, u32 max_interval)
				      u32 min_interval, u32 max_interval,
				      u8 mesh_handle)
{
	struct adv_info *adv;

@@ -1717,7 +1718,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
		memset(adv->per_adv_data, 0, sizeof(adv->per_adv_data));
	} else {
		if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets ||
		    instance < 1 || instance > hdev->le_num_of_adv_sets)
		    instance < 1 || instance > hdev->le_num_of_adv_sets + 1)
			return ERR_PTR(-EOVERFLOW);

		adv = kzalloc(sizeof(*adv), GFP_KERNEL);
@@ -1734,6 +1735,11 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
	adv->min_interval = min_interval;
	adv->max_interval = max_interval;
	adv->tx_power = tx_power;
	/* Defining a mesh_handle changes the timing units to ms,
	 * rather than seconds, and ties the instance to the requested
	 * mesh_tx queue.
	 */
	adv->mesh = mesh_handle;

	hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data,
				  scan_rsp_len, scan_rsp_data);
@@ -1762,7 +1768,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,

	adv = hci_add_adv_instance(hdev, instance, flags, 0, NULL, 0, NULL,
				   0, 0, HCI_ADV_TX_POWER_NO_PREFERENCE,
				   min_interval, max_interval);
				   min_interval, max_interval, 0);
	if (IS_ERR(adv))
		return adv;

@@ -2486,6 +2492,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
	mutex_init(&hdev->lock);
	mutex_init(&hdev->req_lock);

	INIT_LIST_HEAD(&hdev->mesh_pending);
	INIT_LIST_HEAD(&hdev->mgmt_pending);
	INIT_LIST_HEAD(&hdev->reject_list);
	INIT_LIST_HEAD(&hdev->accept_list);
Loading