Skip to content

Commit

Permalink
Bluetooth: Implement support for Mesh
Browse files Browse the repository at this point in the history
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: Brian Gix <brian.gix@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
Brian Gix authored and Luiz Augusto von Dentz committed Sep 6, 2022
1 parent fd3f106 commit b338d91
Show file tree
Hide file tree
Showing 11 changed files with 760 additions and 46 deletions.
1 change: 1 addition & 0 deletions include/net/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ enum {
HCI_LE_SIMULTANEOUS_ROLES,
HCI_CMD_DRAIN_WORKQUEUE,

HCI_MESH,
HCI_MESH_SENDING,

__HCI_NUM_FLAGS,
};

Expand Down
16 changes: 14 additions & 2 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ struct adv_info {
bool enabled;
bool pending;
bool periodic;
__u8 mesh;
__u8 instance;
__u32 flags;
__u16 timeout;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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);
Expand Down
52 changes: 52 additions & 0 deletions include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
13 changes: 10 additions & 3 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit b338d91

Please sign in to comment.