diff mbox series

[2/2] Bluetooth: Implement support for Mesh

Message ID 20211202222619.626678-3-brian.gix@intel.com (mailing list archive)
State Changes Requested
Headers show
Series Kernel based Mesh support | expand

Checks

Context Check Description
tedd_an/checkpatch fail [2/2] Bluetooth: Implement support for Mesh\WARNING:TYPO_SPELLING: 'recieving' may be misspelled - perhaps 'receiving'? #49: and recieving Bluetooth Mesh advertising packets, and delivery to ^^^^^^^^^ CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #585: FILE: net/bluetooth/hci_request.c:2183: + if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) || + hci_dev_test_flag(hdev, HCI_MESH)) WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line #645: FILE: net/bluetooth/hci_request.c:2397: + * with no filtering */ CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #664: FILE: net/bluetooth/hci_request.c:2461: + hci_req_sync(hdev, mesh_scan, DISCOV_LE_SCAN_INT, + HCI_CMD_TIMEOUT, status); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #668: FILE: net/bluetooth/hci_request.c:2465: + hci_req_sync(hdev, active_scan, + hdev->le_scan_int_discovery, CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #740: FILE: net/bluetooth/hci_sync.c:1116: + __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE, + sizeof(enable), &enable, HCI_CMD_TIMEOUT); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #753: FILE: net/bluetooth/hci_sync.c:1129: + __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_PARAM, + sizeof(cp_param), &cp_param, CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #757: FILE: net/bluetooth/hci_sync.c:1133: + err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA, + sizeof(cp_data), &cp_data, HCI_CMD_TIMEOUT); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1018: FILE: net/bluetooth/mgmt.c:2073: + mgmt_pending_foreach(MGMT_OP_SET_MESH, hdev, cmd_status_rsp, + &status); CHECK:BRACES: braces {} should be used on all arms of this statement #1034: FILE: net/bluetooth/mgmt.c:2089: + if (cp->enable) { [...] + } else [...] CHECK:BRACES: Unbalanced braces around else statement #1040: FILE: net/bluetooth/mgmt.c:2095: + } else CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1048: FILE: net/bluetooth/mgmt.c:2103: + memcpy(hdev->mesh_ad_types, cp->ad_types, + sizeof(hdev->mesh_ad_types)); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1067: FILE: net/bluetooth/mgmt.c:2122: + if ((cp->enable != 0x00 && cp->enable != 0x01) || + (cp->active != 0x00 && cp->active != 0x01)) CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1078: FILE: net/bluetooth/mgmt.c:2133: + err = hci_cmd_sync_queue(hdev, set_mesh_sync, cmd, + set_mesh_complete); CHECK:LINE_SPACING: Please don't use multiple blank lines #1080: FILE: net/bluetooth/mgmt.c:2135: + + CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1126: FILE: net/bluetooth/mgmt.c:2181: + if (!hci_dev_test_flag(hdev, HCI_MESH) || len <= MGMT_MESH_SEND_SIZE || + len > (MGMT_MESH_SEND_SIZE + 29)) CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1132: FILE: net/bluetooth/mgmt.c:2187: + if (hci_dev_test_flag(hdev, HCI_MESH_SENDING) || + hci_dev_test_flag(hdev, HCI_LE_ADV)) { CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1134: FILE: net/bluetooth/mgmt.c:2189: + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND, + MGMT_STATUS_BUSY); CHECK:LINE_SPACING: Please don't use multiple blank lines #1138: FILE: net/bluetooth/mgmt.c:2193: + + CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1142: FILE: net/bluetooth/mgmt.c:2197: + cmd = mgmt_pending_add(sk, MGMT_OP_MESH_SEND, hdev, send->data, + len - sizeof(struct mgmt_cp_mesh_send)); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1148: FILE: net/bluetooth/mgmt.c:2203: + err = hci_cmd_sync_queue(hdev, mesh_send_sync, cmd, + mesh_send_complete); CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis #1152: FILE: net/bluetooth/mgmt.c:2207: + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND, + MGMT_STATUS_FAILED); CHECK:UNNECESSARY_PARENTHESES: Unnecessary parentheses around 'hdev->adv_tx_power != HCI_TX_POWER_INVALID' #1189: FILE: net/bluetooth/mgmt.c:7922: + if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) || use_ext_adv(hdev)) total: 0 errors, 2 warnings, 21 checks, 1041 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. /github/workspace/src/12653673.patch has style problems, please review. NOTE: Ignored message types: UNKNOWN_COMMIT_ID NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/gitlint success Gitlint PASS

Commit Message

Brian Gix Dec. 2, 2021, 10:26 p.m. UTC
The patch adds state bits, storage and HCI command chains for sending
and recieving Bluetooth Mesh advertising packets, and delivery to
requesting user space processes.

Signed-off-by: Brian Gix <brian.gix@intel.com>
---
 include/net/bluetooth/hci.h      |   5 +
 include/net/bluetooth/hci_core.h |  16 ++-
 include/net/bluetooth/hci_sync.h |   2 +
 net/bluetooth/hci_conn.c         |   4 +-
 net/bluetooth/hci_event.c        |  61 +++++----
 net/bluetooth/hci_request.c      | 119 ++++++++++++++----
 net/bluetooth/hci_sync.c         |  94 +++++++++++---
 net/bluetooth/mgmt.c             | 208 +++++++++++++++++++++++++++++--
 8 files changed, 430 insertions(+), 79 deletions(-)

Comments

Luiz Augusto von Dentz Dec. 2, 2021, 10:55 p.m. UTC | #1
Hi Brian,

On Thu, Dec 2, 2021 at 2:26 PM Brian Gix <brian.gix@intel.com> wrote:
>
> The patch adds state bits, storage and HCI command chains for sending
> and recieving Bluetooth Mesh advertising packets, and delivery to
> requesting user space processes.
>
> Signed-off-by: Brian Gix <brian.gix@intel.com>
> ---
>  include/net/bluetooth/hci.h      |   5 +
>  include/net/bluetooth/hci_core.h |  16 ++-
>  include/net/bluetooth/hci_sync.h |   2 +
>  net/bluetooth/hci_conn.c         |   4 +-
>  net/bluetooth/hci_event.c        |  61 +++++----
>  net/bluetooth/hci_request.c      | 119 ++++++++++++++----
>  net/bluetooth/hci_sync.c         |  94 +++++++++++---
>  net/bluetooth/mgmt.c             | 208 +++++++++++++++++++++++++++++--
>  8 files changed, 430 insertions(+), 79 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 0d2a9216869b..74bc9d24be1e 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -333,6 +333,11 @@ enum {
>         HCI_QUALITY_REPORT,
>         HCI_OFFLOAD_CODECS_ENABLED,
>
> +       HCI_MESH,
> +       HCI_MESH_SENDING,
> +       HCI_MESH_ACTIVE,
> +       HCI_MESH_JIFFIES,
> +
>         __HCI_NUM_FLAGS,
>  };
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 7bae8376fd6f..f3c0608eecda 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -345,6 +345,7 @@ struct hci_dev {
>         __u8            le_resolv_list_size;
>         __u8            le_num_of_adv_sets;
>         __u8            le_states[8];
> +       __u8            mesh_ad_types[16];
>         __u8            commands[64];
>         __u8            hci_ver;
>         __u16           hci_rev;
> @@ -581,6 +582,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,
> @@ -1471,13 +1474,19 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
>
>  /* Use ext scanning if set ext scan param and ext scan enable is supported */
>  #define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
> -                          ((dev)->commands[37] & 0x40))
> +                          ((dev)->commands[37] & 0x40) && \
> +                          !hci_dev_test_flag(dev, HCI_MESH))
> +
>  /* Use ext create connection if command is supported */
>  #define use_ext_conn(dev) ((dev)->commands[37] & 0x80)
>
>  /* Extended advertising support */
>  #define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))
>
> +/* Use ext advertising if supported and not running Mesh */
> +#define use_ext_adv(dev) (ext_adv_capable(dev) && \
> +                         !hci_dev_test_flag(dev, HCI_MESH))

Is this a requirement that Mesh cannot use extended
scanning/advertising? This would probably not play very well with
bluetoothd, afaik the use of extended scanning/advertising allows for
better timings so this is going in the opposite direction that I'd
expect.

>  /* ----- HCI protocols ----- */
>  #define HCI_PROTO_DEFER             0x01
>
> @@ -1759,6 +1768,8 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
>  #define DISCOV_LE_RESTART_DELAY                msecs_to_jiffies(200)   /* msec */
>  #define DISCOV_LE_FAST_ADV_INT_MIN     0x00A0  /* 100 msec */
>  #define DISCOV_LE_FAST_ADV_INT_MAX     0x00F0  /* 150 msec */
> +#define DISCOV_LE_ADV_MESH_MIN         0x00A0  /* 100 msec */
> +#define DISCOV_LE_ADV_MESH_MAX         0x00A0  /* 100 msec */
>
>  #define NAME_RESOLVE_DURATION          msecs_to_jiffies(10240) /* 10.24 sec */
>
> @@ -1810,7 +1821,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,
> +                      u32 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);
> diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
> index 0336c1bc5d25..0339e6881750 100644
> --- a/include/net/bluetooth/hci_sync.h
> +++ b/include/net/bluetooth/hci_sync.h
> @@ -83,6 +83,8 @@ int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
>  struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev, bool ext,
>                                              struct sock *sk);
>
> +int hci_mesh_send_sync(struct hci_dev *hdev, u8 *data, u8 len);
> +
>  int hci_reset_sync(struct hci_dev *hdev);
>  int hci_dev_open_sync(struct hci_dev *hdev);
>  int hci_dev_close_sync(struct hci_dev *hdev);
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index cd6e1cf7e396..e3d2b59c5ae5 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -638,7 +638,7 @@ static void hci_conn_auto_accept(struct work_struct *work)
>
>  static void le_disable_advertising(struct hci_dev *hdev)
>  {
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 struct hci_cp_le_set_ext_adv_enable cp;
>
>                 cp.enable = 0x00;
> @@ -1063,7 +1063,7 @@ static void hci_req_directed_advertising(struct hci_request *req,
>         u8 own_addr_type;
>         u8 enable;
>
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 struct hci_cp_le_set_ext_adv_params cp;
>                 bdaddr_t random_addr;
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 9d8d2d9e5d1f..1316cd8561bb 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1486,6 +1486,8 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
>                 hci_dev_set_flag(hdev, HCI_LE_SCAN);
>                 if (hdev->le_scan_type == LE_SCAN_ACTIVE)
>                         clear_pending_adv_report(hdev);
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       hci_discovery_set_state(hdev, DISCOVERY_FINDING);
>                 break;
>
>         case LE_SCAN_DISABLE:
> @@ -1500,7 +1502,7 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
>                                           d->last_adv_addr_type, NULL,
>                                           d->last_adv_rssi, d->last_adv_flags,
>                                           d->last_adv_data,
> -                                         d->last_adv_data_len, NULL, 0);
> +                                         d->last_adv_data_len, NULL, 0, 0);
>                 }
>
>                 /* Cancel this timer so that we don't try to disable scanning
> @@ -1516,6 +1518,9 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
>                  */
>                 if (hci_dev_test_and_clear_flag(hdev, HCI_LE_SCAN_INTERRUPTED))
>                         hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> +               else if (!hci_dev_test_flag(hdev, HCI_LE_ADV) &&
> +                        hdev->discovery.state == DISCOVERY_FINDING)
> +                       hci_req_reenable_advertising(hdev);
>
>                 break;
>
> @@ -2772,7 +2777,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
>                 mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
>                                   info->dev_class, HCI_RSSI_INVALID,
> -                                 flags, NULL, 0, NULL, 0);
> +                                 flags, NULL, 0, NULL, 0, 0);
>         }
>
>         hci_dev_unlock(hdev);
> @@ -4433,7 +4438,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
>
>                         mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
>                                           info->dev_class, info->rssi,
> -                                         flags, NULL, 0, NULL, 0);
> +                                         flags, NULL, 0, NULL, 0, 0);
>                 }
>         } else {
>                 struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
> @@ -4457,7 +4462,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
>
>                         mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
>                                           info->dev_class, info->rssi,
> -                                         flags, NULL, 0, NULL, 0);
> +                                         flags, NULL, 0, NULL, 0, 0);
>                 }
>         }
>
> @@ -4688,7 +4693,7 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
>
>                 mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
>                                   info->dev_class, info->rssi,
> -                                 flags, info->data, eir_len, NULL, 0);
> +                                 flags, info->data, eir_len, NULL, 0, 0);
>         }
>
>         hci_dev_unlock(hdev);
> @@ -5709,7 +5714,7 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
>  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                                u8 bdaddr_type, bdaddr_t *direct_addr,
>                                u8 direct_addr_type, s8 rssi, u8 *data, u8 len,
> -                              bool ext_adv)
> +                              bool ext_adv, bool ctl_time, u32 instant)
>  {
>         struct discovery_state *d = &hdev->discovery;
>         struct smp_irk *irk;
> @@ -5757,7 +5762,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>          * important to see if the address is matching the local
>          * controller address.
>          */
> -       if (direct_addr) {
> +       if (!hci_dev_test_flag(hdev, HCI_MESH) && direct_addr) {
>                 direct_addr_type = ev_bdaddr_type(hdev, direct_addr_type,
>                                                   &bdaddr_resolved);
>
> @@ -5805,6 +5810,18 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                 conn->le_adv_data_len = len;
>         }
>
> +       if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND)
> +               flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
> +       else
> +               flags = 0;
> +
> +       /* All scan results should be sent up for Mesh systems */
> +       if (hci_dev_test_flag(hdev, HCI_MESH)) {
> +               mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
> +                                 rssi, flags, data, len, NULL, 0, instant);
> +               return;
> +       }
> +
>         /* Passive scanning shouldn't trigger any device found events,
>          * except for devices marked as CONN_REPORT for which we do send
>          * device found events, or advertisement monitoring requested.
> @@ -5818,12 +5835,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                     idr_is_empty(&hdev->adv_monitors_idr))
>                         return;
>
> -               if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND)
> -                       flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
> -               else
> -                       flags = 0;
>                 mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
> -                                 rssi, flags, data, len, NULL, 0);
> +                                 rssi, flags, data, len, NULL, 0, 0);
>                 return;
>         }
>
> @@ -5842,11 +5855,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>          * and just sends a scan response event, then it is marked as
>          * not connectable as well.
>          */
> -       if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND ||
> -           type == LE_ADV_SCAN_RSP)
> +       if (type == LE_ADV_SCAN_RSP)
>                 flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
> -       else
> -               flags = 0;
>
>         /* If there's nothing pending either store the data from this
>          * event or send an immediate device found event if the data
> @@ -5863,7 +5873,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                 }
>
>                 mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
> -                                 rssi, flags, data, len, NULL, 0);
> +                                 rssi, flags, data, len, NULL, 0, 0);
>                 return;
>         }
>
> @@ -5882,7 +5892,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                                           d->last_adv_addr_type, NULL,
>                                           d->last_adv_rssi, d->last_adv_flags,
>                                           d->last_adv_data,
> -                                         d->last_adv_data_len, NULL, 0);
> +                                         d->last_adv_data_len, NULL, 0, 0);
>
>                 /* If the new report will trigger a SCAN_REQ store it for
>                  * later merging.
> @@ -5899,7 +5909,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>                  */
>                 clear_pending_adv_report(hdev);
>                 mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
> -                                 rssi, flags, data, len, NULL, 0);
> +                                 rssi, flags, data, len, NULL, 0, 0);
>                 return;
>         }
>
> @@ -5909,7 +5919,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
>          */
>         mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
>                           d->last_adv_addr_type, NULL, rssi, d->last_adv_flags,
> -                         d->last_adv_data, d->last_adv_data_len, data, len);
> +                         d->last_adv_data, d->last_adv_data_len, data, len, 0);
>         clear_pending_adv_report(hdev);
>  }
>
> @@ -5917,6 +5927,7 @@ 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];
> +       u32 instant = jiffies;
>
>         hci_dev_lock(hdev);
>
> @@ -5934,7 +5945,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
>                         rssi = ev->data[ev->length];
>                         process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
>                                            ev->bdaddr_type, NULL, 0, rssi,
> -                                          ev->data, ev->length, false);
> +                                          ev->data, ev->length, false,
> +                                          false, instant);
>                 } else {
>                         bt_dev_err(hdev, "Dropping invalid advertising data");
>                 }
> @@ -5993,6 +6005,7 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
>  {
>         u8 num_reports = skb->data[0];
>         void *ptr = &skb->data[1];
> +       u32 instant = jiffies;
>
>         hci_dev_lock(hdev);
>
> @@ -6007,7 +6020,8 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
>                         process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
>                                            ev->bdaddr_type, NULL, 0, ev->rssi,
>                                            ev->data, ev->length,
> -                                          !(evt_type & LE_EXT_ADV_LEGACY_PDU));
> +                                          !(evt_type & LE_EXT_ADV_LEGACY_PDU),
> +                                          false, instant);
>                 }
>
>                 ptr += sizeof(*ev) + ev->length;
> @@ -6197,6 +6211,7 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
>  {
>         u8 num_reports = skb->data[0];
>         struct hci_ev_le_direct_adv_info *ev = (void *)&skb->data[1];
> +       u32 instant = jiffies;
>
>         if (!num_reports || skb->len < num_reports * sizeof(*ev) + 1)
>                 return;
> @@ -6207,7 +6222,7 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
>                 process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
>                                    ev->bdaddr_type, &ev->direct_addr,
>                                    ev->direct_addr_type, ev->rssi, NULL, 0,
> -                                  false);
> +                                  false, false, instant);
>
>         hci_dev_unlock(hdev);
>  }
> diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
> index 8b3205e4b23e..4cba7c3e2ba2 100644
> --- a/net/bluetooth/hci_request.c
> +++ b/net/bluetooth/hci_request.c
> @@ -686,7 +686,12 @@ static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
>
>                 memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
>                 ext_enable_cp.enable = LE_SCAN_ENABLE;
> -               ext_enable_cp.filter_dup = filter_dup;
> +
> +               /* Mesh protocols requires duplicate filtering to be disabled */
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +               else
> +                       ext_enable_cp.filter_dup = filter_dup;
>
>                 hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
>                             sizeof(ext_enable_cp), &ext_enable_cp);
> @@ -694,18 +699,31 @@ static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
>                 struct hci_cp_le_set_scan_param param_cp;
>                 struct hci_cp_le_set_scan_enable enable_cp;
>
> +               memset(&enable_cp, 0, sizeof(enable_cp));
> +               hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
> +                           &enable_cp);
> +
>                 memset(&param_cp, 0, sizeof(param_cp));
>                 param_cp.type = type;
>                 param_cp.interval = cpu_to_le16(interval);
>                 param_cp.window = cpu_to_le16(window);
>                 param_cp.own_address_type = own_addr_type;
> -               param_cp.filter_policy = filter_policy;
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       param_cp.filter_policy = 0;
> +               else
> +                       param_cp.filter_policy = filter_policy;
>                 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
>                             &param_cp);
>
>                 memset(&enable_cp, 0, sizeof(enable_cp));
>                 enable_cp.enable = LE_SCAN_ENABLE;
> -               enable_cp.filter_dup = filter_dup;
> +
> +               /* Mesh protocols requires duplicate filtering to be disabled */
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +               else
> +                       enable_cp.filter_dup = filter_dup;
> +
>                 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
>                             &enable_cp);
>         }
> @@ -840,7 +858,7 @@ void __hci_req_pause_adv_instances(struct hci_request *req)
>         __hci_req_disable_advertising(req);
>
>         /* If we are using software rotation, pause the loop */
> -       if (!ext_adv_capable(req->hdev))
> +       if (!use_ext_adv(req->hdev))
>                 cancel_adv_timeout(req->hdev);
>  }
>
> @@ -851,7 +869,7 @@ static void __hci_req_resume_adv_instances(struct hci_request *req)
>
>         bt_dev_dbg(req->hdev, "Resuming advertising instances");
>
> -       if (ext_adv_capable(req->hdev)) {
> +       if (use_ext_adv(req->hdev)) {
>                 /* Call for each tracked instance to be re-enabled */
>                 list_for_each_entry(adv, &req->hdev->adv_instances, list) {
>                         __hci_req_enable_ext_advertising(req,
> @@ -886,7 +904,7 @@ static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
>
>  void __hci_req_disable_advertising(struct hci_request *req)
>  {
> -       if (ext_adv_capable(req->hdev)) {
> +       if (use_ext_adv(req->hdev)) {
>                 __hci_req_disable_ext_adv_instance(req, 0x00);
>
>         } else {
> @@ -972,8 +990,13 @@ void __hci_req_enable_advertising(struct hci_request *req)
>
>         /* If the "connectable" instance flag was not set, then choose between
>          * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
> +        * If the controller has been enabled for mesh, all advertisements should
> +        * non-connectable, and non-resolvable private. TODO: bgix
>          */
> -       connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
> +       if (hci_dev_test_flag(hdev, HCI_MESH))
> +               connectable = false;
> +       else
> +               connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
>                       mgmt_get_connectable(hdev);
>
>         if (!is_advertising_allowed(hdev, connectable))
> @@ -1016,8 +1039,12 @@ void __hci_req_enable_advertising(struct hci_request *req)
>                 else
>                         cp.type = LE_ADV_NONCONN_IND;
>
> -               if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
> -                   hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
> +               if (hci_dev_test_flag(hdev, HCI_MESH)) {
> +                       adv_min_interval = DISCOV_LE_ADV_MESH_MIN;
> +                       adv_max_interval = DISCOV_LE_ADV_MESH_MAX;
> +                       cp.filter_policy = 3;
> +               } else if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
> +                       hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
>                         adv_min_interval = DISCOV_LE_FAST_ADV_INT_MIN;
>                         adv_max_interval = DISCOV_LE_FAST_ADV_INT_MAX;
>                 }
> @@ -1028,7 +1055,8 @@ void __hci_req_enable_advertising(struct hci_request *req)
>         cp.own_address_type = own_addr_type;
>         cp.channel_map = hdev->le_adv_channel_map;
>
> -       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
> +       if (hdev->manufacturer != 0x000f || hdev->hci_rev != 0x16e4)
> +               hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
>
>         hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
>  }
> @@ -1041,7 +1069,7 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
>         if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
>                 return;
>
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 struct {
>                         struct hci_cp_le_set_ext_scan_rsp_data cp;
>                         u8 data[HCI_MAX_EXT_AD_LENGTH];
> @@ -1093,7 +1121,7 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
>         if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
>                 return;
>
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 struct {
>                         struct hci_cp_le_set_ext_adv_data cp;
>                         u8 data[HCI_MAX_EXT_AD_LENGTH];
> @@ -1189,7 +1217,7 @@ void hci_req_reenable_advertising(struct hci_dev *hdev)
>                 __hci_req_schedule_adv_instance(&req, hdev->cur_adv_instance,
>                                                 true);
>         } else {
> -               if (ext_adv_capable(hdev)) {
> +               if (use_ext_adv(hdev)) {
>                         __hci_req_start_ext_adv(&req, 0x00);
>                 } else {
>                         __hci_req_update_adv_data(&req, 0x00);
> @@ -1664,7 +1692,7 @@ int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
>                                 adv_instance->remaining_time - timeout;
>
>         /* Only use work for scheduling instances with legacy advertising */
> -       if (!ext_adv_capable(hdev)) {
> +       if (!use_ext_adv(hdev)) {
>                 hdev->adv_instance_timeout = timeout;
>                 queue_delayed_work(hdev->req_workqueue,
>                            &hdev->adv_instance_expire,
> @@ -1680,7 +1708,7 @@ int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
>                 return 0;
>
>         hdev->cur_adv_instance = instance;
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 __hci_req_start_ext_adv(req, instance);
>         } else {
>                 __hci_req_update_adv_data(req, instance);
> @@ -1752,7 +1780,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
>             hci_dev_test_flag(hdev, HCI_ADVERTISING))
>                 return;
>
> -       if (next_instance && !ext_adv_capable(hdev))
> +       if (next_instance && !use_ext_adv(hdev))
>                 __hci_req_schedule_adv_instance(req, next_instance->instance,
>                                                 false);
>  }
> @@ -2002,7 +2030,7 @@ static int discoverable_update(struct hci_request *req, unsigned long opt)
>                  * address in limited privacy mode.
>                  */
>                 if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
> -                       if (ext_adv_capable(hdev))
> +                       if (use_ext_adv(hdev))
>                                 __hci_req_start_ext_adv(req, 0x00);
>                         else
>                                 __hci_req_enable_advertising(req);
> @@ -2151,7 +2179,8 @@ static void le_scan_disable_work(struct work_struct *work)
>
>         bt_dev_dbg(hdev, "");
>
> -       if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
> +       if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
> +                               hci_dev_test_flag(hdev, HCI_MESH))
>                 return;
>
>         cancel_delayed_work(&hdev->le_scan_restart);
> @@ -2197,9 +2226,11 @@ static void le_scan_disable_work(struct work_struct *work)
>         return;
>
>  discov_stopped:
> -       hci_dev_lock(hdev);
> -       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> -       hci_dev_unlock(hdev);
> +       if (!hci_dev_test_flag(hdev, HCI_MESH)) {
> +               hci_dev_lock(hdev);
> +               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> +               hci_dev_unlock(hdev);
> +       }
>  }
>
>  static int le_scan_restart(struct hci_request *req, unsigned long opt)
> @@ -2222,7 +2253,12 @@ static int le_scan_restart(struct hci_request *req, unsigned long opt)
>
>                 memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
>                 ext_enable_cp.enable = LE_SCAN_ENABLE;
> -               ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
> +
> +               /* Mesh protocols requires duplicate filtering to be disabled */
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +               else
> +                       ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
>
>                 hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
>                             sizeof(ext_enable_cp), &ext_enable_cp);
> @@ -2231,7 +2267,13 @@ static int le_scan_restart(struct hci_request *req, unsigned long opt)
>
>                 memset(&cp, 0, sizeof(cp));
>                 cp.enable = LE_SCAN_ENABLE;
> -               cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
> +
> +               /* Mesh protocols requires duplicate filtering to be disabled */
> +               if (hci_dev_test_flag(hdev, HCI_MESH))
> +                       cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +               else
> +                       cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
> +
>                 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
>         }
>
> @@ -2344,6 +2386,21 @@ static int active_scan(struct hci_request *req, unsigned long opt)
>         return 0;
>  }
>
> +static int mesh_scan(struct hci_request *req, unsigned long opt)
> +{
> +       struct hci_dev *hdev = req->hdev;
> +       u16 window = hdev->le_scan_window;
> +
> +       BT_INFO("MESH-SCAN %s", hdev->name);
> +
> +       /* In Mesh mode we are always at least passive scanning,
> +        * with no filtering */
> +
> +       hci_req_start_scan(req, LE_SCAN_PASSIVE, window, window,
> +                          0x00, 0x00, false, false);
> +       return 0;
> +}
> +
>  static int interleaved_discov(struct hci_request *req, unsigned long opt)
>  {
>         int err;
> @@ -2398,8 +2455,16 @@ static void start_discovery(struct hci_dev *hdev, u8 *status)
>                 break;
>         case DISCOV_TYPE_LE:
>                 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
> -               hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery,
> -                            HCI_CMD_TIMEOUT, status);
> +               if (hci_dev_test_flag(hdev, HCI_MESH)) {
> +                       BT_INFO("LE Discovery - (passive)");
> +                       hci_req_sync(hdev, mesh_scan, DISCOV_LE_SCAN_INT,
> +                                       HCI_CMD_TIMEOUT, status);
> +               } else {
> +                       BT_INFO("LE Discovery - (active)");
> +                       hci_req_sync(hdev, active_scan,
> +                                       hdev->le_scan_int_discovery,
> +                                       HCI_CMD_TIMEOUT, status);
> +               }
>                 break;
>         default:
>                 *status = HCI_ERROR_UNSPECIFIED;
> @@ -2627,7 +2692,7 @@ static int powered_update_hci(struct hci_request *req, unsigned long opt)
>                     list_empty(&hdev->adv_instances)) {
>                         int err;
>
> -                       if (ext_adv_capable(hdev)) {
> +                       if (use_ext_adv(hdev)) {
>                                 err = __hci_req_setup_ext_adv_instance(req,
>                                                                        0x00);
>                                 if (!err)
> @@ -2640,7 +2705,7 @@ static int powered_update_hci(struct hci_request *req, unsigned long opt)
>                         }
>
>                         if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
> -                               if (!ext_adv_capable(hdev))
> +                               if (!use_ext_adv(hdev))
>                                         __hci_req_enable_advertising(req);
>                                 else if (!err)
>                                         __hci_req_enable_ext_advertising(req,
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index ad86caf41f91..b63bd01e254d 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -856,7 +856,7 @@ int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>         if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
>                 return 0;
>
> -       if (ext_adv_capable(hdev))
> +       if (use_ext_adv(hdev))
>                 return hci_set_ext_scan_rsp_data_sync(hdev, instance);
>
>         return __hci_set_scan_rsp_data_sync(hdev, instance);
> @@ -927,7 +927,7 @@ static int hci_start_adv_sync(struct hci_dev *hdev, u8 instance)
>  {
>         int err;
>
> -       if (ext_adv_capable(hdev))
> +       if (use_ext_adv(hdev))
>                 return hci_start_ext_adv_sync(hdev, instance);
>
>         err = hci_update_adv_data_sync(hdev, instance);
> @@ -951,7 +951,7 @@ int hci_enable_advertising_sync(struct hci_dev *hdev)
>         u32 flags;
>         u8 status;
>
> -       if (ext_adv_capable(hdev))
> +       if (use_ext_adv(hdev))
>                 return hci_enable_ext_advertising_sync(hdev,
>                                                        hdev->cur_adv_instance);
>
> @@ -1100,6 +1100,49 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
>                                      HCI_CMD_TIMEOUT);
>  }
>
> +int hci_mesh_send_sync(struct hci_dev *hdev, u8 *data, u8 len)
> +{
> +       struct hci_cp_le_set_adv_data cp_data;
> +       struct hci_cp_le_set_adv_param cp_param;
> +       u8 own_addr_type, enable = 0x00;
> +       int err;
> +
> +       memset(&cp_data, 0, sizeof(cp_data));
> +       cp_data.length = len + 1;
> +       cp_data.data[0] = len;
> +       memcpy(cp_data.data + 1, data, len);
> +
> +       __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
> +                                    sizeof(enable), &enable, HCI_CMD_TIMEOUT);
> +
> +       hci_update_random_address_sync(hdev, true, false, &own_addr_type);
> +
> +       memset(&cp_param, 0, sizeof(cp_param));
> +       cp_param.type = LE_ADV_NONCONN_IND;
> +       cp_param.min_interval = cpu_to_le16(DISCOV_LE_ADV_MESH_MIN);
> +       cp_param.max_interval = cpu_to_le16(DISCOV_LE_ADV_MESH_MAX);
> +       cp_param.own_address_type = 1;
> +       cp_param.channel_map = 7;
> +       cp_param.filter_policy = 3;
> +
> +       __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_PARAM,
> +                                      sizeof(cp_param), &cp_param,
> +                                      HCI_CMD_TIMEOUT);
> +
> +       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
> +                            sizeof(cp_data), &cp_data, HCI_CMD_TIMEOUT);
> +
> +       if (err)
> +               return err;
> +
> +       memcpy(hdev->adv_data, cp_data.data, sizeof(cp_data.data));
> +       hdev->adv_data_len = len;
> +
> +       enable = 0x01;
> +       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
> +                                    sizeof(enable), &enable, HCI_CMD_TIMEOUT);
> +}
> +
>  static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
>  {
>         struct hci_cp_le_set_adv_data cp;
> @@ -1128,7 +1171,7 @@ int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
>         if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
>                 return 0;
>
> -       if (ext_adv_capable(hdev))
> +       if (use_ext_adv(hdev))
>                 return hci_set_ext_adv_data_sync(hdev, instance);
>
>         return hci_set_adv_data_sync(hdev, instance);
> @@ -1140,7 +1183,7 @@ int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
>         struct adv_info *adv = NULL;
>         u16 timeout;
>
> -       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev))
> +       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !use_ext_adv(hdev))
>                 return -EPERM;
>
>         if (hdev->adv_instance_timeout)
> @@ -1170,7 +1213,7 @@ int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
>                 adv->remaining_time = adv->remaining_time - timeout;
>
>         /* Only use work for scheduling instances with legacy advertising */
> -       if (!ext_adv_capable(hdev)) {
> +       if (!use_ext_adv(hdev)) {
>                 hdev->adv_instance_timeout = timeout;
>                 queue_delayed_work(hdev->req_workqueue,
>                                    &hdev->adv_instance_expire,
> @@ -1209,10 +1252,13 @@ static int hci_clear_adv_sets_sync(struct hci_dev *hdev, struct sock *sk)
>  static int hci_clear_adv_sync(struct hci_dev *hdev, struct sock *sk, bool force)
>  {
>         struct adv_info *adv, *n;
> +       int err = 0;
>
>         if (ext_adv_capable(hdev))
>                 /* Remove all existing sets */
> -               return hci_clear_adv_sets_sync(hdev, sk);
> +               err = hci_clear_adv_sets_sync(hdev, sk);
> +       if (use_ext_adv(hdev))
> +               return err;
>
>         /* This is safe as long as there is no command send while the lock is
>          * held.
> @@ -1240,11 +1286,13 @@ static int hci_clear_adv_sync(struct hci_dev *hdev, struct sock *sk, bool force)
>  static int hci_remove_adv_sync(struct hci_dev *hdev, u8 instance,
>                                struct sock *sk)
>  {
> -       int err;
> +       int err = 0;
>
>         /* If we use extended advertising, instance has to be removed first. */
>         if (ext_adv_capable(hdev))
> -               return hci_remove_ext_adv_instance_sync(hdev, instance, sk);
> +               err = hci_remove_ext_adv_instance_sync(hdev, instance, sk);
> +       if (use_ext_adv(hdev))
> +               return err;
>
>         /* This is safe as long as there is no command send while the lock is
>          * held.
> @@ -1309,7 +1357,7 @@ int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
>         if (!hdev_is_powered(hdev) || hci_dev_test_flag(hdev, HCI_ADVERTISING))
>                 return 0;
>
> -       if (next && !ext_adv_capable(hdev))
> +       if (next && !use_ext_adv(hdev))
>                 hci_schedule_adv_instance_sync(hdev, next->instance, false);
>
>         return 0;
> @@ -1343,13 +1391,16 @@ int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type)
>  int hci_disable_advertising_sync(struct hci_dev *hdev)
>  {
>         u8 enable = 0x00;
> +       int err = 0;
>
>         /* If controller is not advertising we are done. */
>         if (!hci_dev_test_flag(hdev, HCI_LE_ADV))
>                 return 0;
>
>         if (ext_adv_capable(hdev))
> -               return hci_disable_ext_adv_instance_sync(hdev, 0x00);
> +               err = hci_disable_ext_adv_instance_sync(hdev, 0x00);
> +       if (use_ext_adv(hdev))
> +               return err;
>
>         return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
>                                      sizeof(enable), &enable, HCI_CMD_TIMEOUT);
> @@ -1362,7 +1413,11 @@ static int hci_le_set_ext_scan_enable_sync(struct hci_dev *hdev, u8 val,
>
>         memset(&cp, 0, sizeof(cp));
>         cp.enable = val;
> -       cp.filter_dup = filter_dup;
> +
> +       if (hci_dev_test_flag(hdev, HCI_MESH))
> +               cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +       else
> +               cp.filter_dup = filter_dup;
>
>         return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
>                                      sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> @@ -1378,7 +1433,11 @@ static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
>
>         memset(&cp, 0, sizeof(cp));
>         cp.enable = val;
> -       cp.filter_dup = filter_dup;
> +
> +       if (val && hci_dev_test_flag(hdev, HCI_MESH))
> +               cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
> +       else
> +               cp.filter_dup = filter_dup;
>
>         return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
>                                      sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> @@ -1676,7 +1735,7 @@ static int hci_pause_advertising_sync(struct hci_dev *hdev)
>                 return err;
>
>         /* If we are using software rotation, pause the loop */
> -       if (!ext_adv_capable(hdev))
> +       if (!use_ext_adv(hdev))
>                 cancel_adv_timeout(hdev);
>
>         hdev->advertising_paused = true;
> @@ -1704,7 +1763,7 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev)
>
>         bt_dev_dbg(hdev, "Resuming advertising instances");
>
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 /* Call for each tracked instance to be re-enabled */
>                 list_for_each_entry_safe(adv, tmp, &hdev->adv_instances, list) {
>                         err = hci_enable_ext_advertising_sync(hdev,
> @@ -2088,7 +2147,8 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev)
>         bt_dev_dbg(hdev, "ADV monitoring is %s",
>                    hci_is_adv_monitoring(hdev) ? "on" : "off");
>
> -       if (list_empty(&hdev->pend_le_conns) &&
> +       if (!hci_dev_test_flag(hdev, HCI_MESH) &&
> +           list_empty(&hdev->pend_le_conns) &&
>             list_empty(&hdev->pend_le_reports) &&
>             !hci_is_adv_monitoring(hdev)) {
>                 /* If there is no pending LE connections or devices
> @@ -2236,7 +2296,7 @@ static int hci_powered_update_adv_sync(struct hci_dev *hdev)
>          */
>         if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
>             list_empty(&hdev->adv_instances)) {
> -               if (ext_adv_capable(hdev)) {
> +               if (use_ext_adv(hdev)) {
>                         err = hci_setup_ext_adv_instance_sync(hdev, 0x00);
>                         if (!err)
>                                 hci_update_scan_rsp_data_sync(hdev, 0x00);
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index bf989ae03f9f..120798f039fe 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -129,6 +129,8 @@ static const u16 mgmt_commands[] = {
>         MGMT_OP_ADD_EXT_ADV_PARAMS,
>         MGMT_OP_ADD_EXT_ADV_DATA,
>         MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
> +       MGMT_OP_SET_MESH,
> +       MGMT_OP_MESH_SEND,
>  };
>
>  static const u16 mgmt_events[] = {
> @@ -994,7 +996,7 @@ static int rpa_expired_sync(struct hci_dev *hdev, void *data)
>          * controller happens in the hci_req_enable_advertising()
>          * function.
>          */
> -       if (ext_adv_capable(hdev))
> +       if (use_ext_adv(hdev))
>                 return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
>         else
>                 return hci_enable_advertising_sync(hdev);
> @@ -1015,13 +1017,43 @@ static void rpa_expired(struct work_struct *work)
>         hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
>  }
>
> +static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev);
> +static int mesh_send_done_sync(struct hci_dev *hdev, void *data)
> +{
> +       struct mgmt_pending_cmd *cmd = data;
> +
> +       bt_dev_dbg(hdev, "Send Mesh Packet Done");
> +       hci_disable_advertising_sync(hdev);
> +       hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
> +       send_settings_rsp(cmd->sk, MGMT_OP_SET_MESH, hdev);
> +       mgmt_pending_remove(cmd);
> +
> +       return 0;
> +}
> +
> +static void mesh_send_done(struct work_struct *work)
> +{
> +       struct mgmt_pending_cmd *cmd;
> +       struct hci_dev *hdev = container_of(work, struct hci_dev,
> +                                           mesh_send_done.work);
> +
> +       if (!hci_dev_test_flag(hdev, HCI_MESH_SENDING))
> +               return;
> +
> +       cmd = pending_find(MGMT_OP_MESH_SEND, hdev);
> +       hci_cmd_sync_queue(hdev, mesh_send_done_sync, cmd, NULL);
> +}
> +
>  static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
>  {
>         if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
>                 return;
>
> +       BT_INFO("MGMT ver %d.%d", MGMT_VERSION, MGMT_REVISION);
> +
>         INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
>         INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
> +       INIT_DELAYED_WORK(&hdev->mesh_send_done, mesh_send_done);
>
>         /* Non-mgmt controlled devices get this bit set
>          * implicitly so that pairing works for them, however
> @@ -1992,6 +2024,9 @@ static int set_le_sync(struct hci_dev *hdev, void *data)
>         u8 val = !!cp->val;
>         int err;
>
> +       hci_dev_clear_flag(hdev, HCI_MESH);
> +       hci_dev_clear_flag(hdev, HCI_MESH_ACTIVE);
> +
>         if (!val) {
>                 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
>                         hci_disable_advertising_sync(hdev);
> @@ -2010,7 +2045,7 @@ static int set_le_sync(struct hci_dev *hdev, void *data)
>          * update in powered_update_hci will take care of it.
>          */
>         if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
> -               if (ext_adv_capable(hdev)) {
> +               if (use_ext_adv(hdev)) {
>                         int status;
>
>                         status = hci_setup_ext_adv_instance_sync(hdev, 0x00);
> @@ -2027,6 +2062,159 @@ static int set_le_sync(struct hci_dev *hdev, void *data)
>         return err;
>  }
>
> +static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
> +{
> +       struct mgmt_pending_cmd *cmd = data;
> +       u8 status = mgmt_status(err);
> +       struct sock *sk = cmd->sk;
> +
> +       if (status) {
> +               mgmt_pending_foreach(MGMT_OP_SET_MESH, hdev, cmd_status_rsp,
> +                                                       &status);
> +               return;
> +       }
> +
> +       send_settings_rsp(sk, MGMT_OP_SET_MESH, hdev);
> +}
> +
> +static int set_mesh_sync(struct hci_dev *hdev, void *data)
> +{
> +       struct mgmt_pending_cmd *cmd = data;
> +       struct mgmt_cp_set_mesh *cp = cmd->param;
> +       size_t len = cmd->param_len;
> +
> +       memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
> +       hci_dev_clear_flag(hdev, HCI_MESH_ACTIVE);
> +
> +       if (cp->enable) {
> +               hci_dev_set_flag(hdev, HCI_MESH);
> +
> +               if (cp->active)
> +                       hci_dev_set_flag(hdev, HCI_MESH_ACTIVE);
> +
> +       } else
> +               hci_dev_clear_flag(hdev, HCI_MESH);
> +
> +       /* Truncate the passed ad_type list if too long */
> +       if (len - sizeof(*cp) <= sizeof(hdev->mesh_ad_types))
> +               memcpy(hdev->mesh_ad_types, cp->ad_types, len - sizeof(*cp));
> +       else
> +               memcpy(hdev->mesh_ad_types, cp->ad_types,
> +                                               sizeof(hdev->mesh_ad_types));
> +
> +       hci_update_passive_scan_sync(hdev);
> +       return 0;
> +}
> +
> +static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
> +{
> +       struct mgmt_cp_set_mesh *cp = data;
> +       struct mgmt_pending_cmd *cmd;
> +       int err = 0;
> +
> +       bt_dev_dbg(hdev, "sock %p", sk);
> +
> +       if (!lmp_le_capable(hdev))
> +               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH,
> +                                      MGMT_STATUS_NOT_SUPPORTED);
> +
> +       if ((cp->enable != 0x00 && cp->enable != 0x01) ||
> +                               (cp->active != 0x00 && cp->active != 0x01))
> +               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH,
> +                                      MGMT_STATUS_INVALID_PARAMS);
> +
> +       hci_dev_lock(hdev);
> +
> +       cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH, hdev, data, len);
> +       if (!cmd)
> +               err = -ENOMEM;
> +       else
> +               err = hci_cmd_sync_queue(hdev, set_mesh_sync, cmd,
> +                                               set_mesh_complete);
> +
> +
> +       send_settings_rsp(sk, MGMT_OP_SET_MESH, hdev);
> +       hci_dev_unlock(hdev);
> +       return err;
> +}
> +
> +static void mesh_send_complete(struct hci_dev *hdev, void *data, int err)
> +{
> +       struct mgmt_pending_cmd *cmd = data;
> +       struct mgmt_cp_mesh_send *cp = cmd->param;
> +       unsigned long mesh_send_interval;
> +       u8 mgmt_err = mgmt_status(err);
> +
> +       /* Report any errors here, but don't report completion */
> +
> +       if (mgmt_err) {
> +               hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
> +               mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_MESH_SEND, mgmt_err);
> +               mgmt_pending_remove(cmd);
> +               return;
> +       }
> +
> +       mesh_send_interval = msecs_to_jiffies((cp->cnt) * 25);
> +       queue_delayed_work(hdev->req_workqueue, &hdev->mesh_send_done,
> +                          mesh_send_interval);
> +}
> +
> +static int mesh_send_sync(struct hci_dev *hdev, void *data)
> +{
> +       struct mgmt_pending_cmd *cmd = data;
> +
> +       if (hci_dev_test_flag(hdev, HCI_LE_ADV))
> +               return MGMT_STATUS_BUSY;
> +
> +       return hci_mesh_send_sync(hdev, cmd->param, cmd->param_len);
> +}
> +
> +static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
> +{
> +       struct mgmt_pending_cmd *cmd;
> +       struct mgmt_cp_mesh_send *send = data;
> +       int err = 0;
> +
> +       bt_dev_dbg(hdev, "Send Mesh Packet Start...");
> +
> +       if (!hci_dev_test_flag(hdev, HCI_MESH) || len <= MGMT_MESH_SEND_SIZE ||
> +                                       len > (MGMT_MESH_SEND_SIZE + 29))
> +               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
> +                                      MGMT_STATUS_REJECTED);
> +
> +       hci_dev_lock(hdev);
> +       if (hci_dev_test_flag(hdev, HCI_MESH_SENDING) ||
> +                               hci_dev_test_flag(hdev, HCI_LE_ADV)) {
> +               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
> +                                                       MGMT_STATUS_BUSY);
> +               goto done;
> +       }
> +
> +
> +       hci_dev_set_flag(hdev, HCI_MESH_SENDING);
> +
> +       cmd = mgmt_pending_add(sk, MGMT_OP_MESH_SEND, hdev, send->data,
> +                               len - sizeof(struct mgmt_cp_mesh_send));
> +
> +       if (!cmd)
> +               err = -ENOMEM;
> +       else
> +               err = hci_cmd_sync_queue(hdev, mesh_send_sync, cmd,
> +                                               mesh_send_complete);
> +
> +       if (err < 0) {
> +               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
> +                                               MGMT_STATUS_FAILED);
> +
> +               if (cmd)
> +                       mgmt_pending_remove(cmd);
> +       }
> +
> +done:
> +       hci_dev_unlock(hdev);
> +       return err;
> +}
> +
>  static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
>  {
>         struct mgmt_mode *cp = data;
> @@ -5731,7 +5919,7 @@ static int set_adv_sync(struct hci_dev *hdev, void *data)
>                  */
>                 hdev->cur_adv_instance = 0x00;
>
> -               if (ext_adv_capable(hdev)) {
> +               if (use_ext_adv(hdev)) {
>                         hci_start_ext_adv_sync(hdev, 0x00);
>                 } else {
>                         hci_update_adv_data_sync(hdev, 0x00);
> @@ -5780,6 +5968,7 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
>         if (!hdev_is_powered(hdev) ||
>             (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
>              (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
> +           hci_dev_test_flag(hdev, HCI_MESH) ||
>             hci_conn_num(hdev, LE_LINK) > 0 ||
>             (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
>              hdev->le_scan_type == LE_SCAN_ACTIVE)) {
> @@ -7730,11 +7919,10 @@ static u32 get_supported_adv_flags(struct hci_dev *hdev)
>         /* In extended adv TX_POWER returned from Set Adv Param
>          * will be always valid.
>          */
> -       if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
> -           ext_adv_capable(hdev))
> +       if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) || use_ext_adv(hdev))
>                 flags |= MGMT_ADV_FLAG_TX_POWER;
>
> -       if (ext_adv_capable(hdev)) {
> +       if (use_ext_adv(hdev)) {
>                 flags |= MGMT_ADV_FLAG_SEC_1M;
>                 flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
>                 flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
> @@ -8703,7 +8891,10 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
>         { add_ext_adv_data,        MGMT_ADD_EXT_ADV_DATA_SIZE,
>                                                 HCI_MGMT_VAR_LEN },
>         { add_adv_patterns_monitor_rssi,
> -                                  MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
> +                                  MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE },
> +       { set_mesh,                MGMT_SET_MESH_SIZE,
> +                                               HCI_MGMT_VAR_LEN },
> +       { mesh_send,               MGMT_MESH_SEND_SIZE,
>                                                 HCI_MGMT_VAR_LEN },

Id split the patches into set_mesh and mesh_send.

>  };
>
> @@ -9526,7 +9717,8 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
>
>  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,
> +                      u32 instant)
>  {
>         char buf[512];
>         struct mgmt_ev_device_found *ev = (void *)buf;
> --
> 2.31.1
>
diff mbox series

Patch

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0d2a9216869b..74bc9d24be1e 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -333,6 +333,11 @@  enum {
 	HCI_QUALITY_REPORT,
 	HCI_OFFLOAD_CODECS_ENABLED,
 
+	HCI_MESH,
+	HCI_MESH_SENDING,
+	HCI_MESH_ACTIVE,
+	HCI_MESH_JIFFIES,
+
 	__HCI_NUM_FLAGS,
 };
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7bae8376fd6f..f3c0608eecda 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -345,6 +345,7 @@  struct hci_dev {
 	__u8		le_resolv_list_size;
 	__u8		le_num_of_adv_sets;
 	__u8		le_states[8];
+	__u8		mesh_ad_types[16];
 	__u8		commands[64];
 	__u8		hci_ver;
 	__u16		hci_rev;
@@ -581,6 +582,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,
@@ -1471,13 +1474,19 @@  void hci_conn_del_sysfs(struct hci_conn *conn);
 
 /* Use ext scanning if set ext scan param and ext scan enable is supported */
 #define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
-			   ((dev)->commands[37] & 0x40))
+			   ((dev)->commands[37] & 0x40) && \
+			   !hci_dev_test_flag(dev, HCI_MESH))
+
 /* Use ext create connection if command is supported */
 #define use_ext_conn(dev) ((dev)->commands[37] & 0x80)
 
 /* Extended advertising support */
 #define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))
 
+/* Use ext advertising if supported and not running Mesh */
+#define use_ext_adv(dev) (ext_adv_capable(dev) && \
+			  !hci_dev_test_flag(dev, HCI_MESH))
+
 /* ----- HCI protocols ----- */
 #define HCI_PROTO_DEFER             0x01
 
@@ -1759,6 +1768,8 @@  void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
 #define DISCOV_LE_RESTART_DELAY		msecs_to_jiffies(200)	/* msec */
 #define DISCOV_LE_FAST_ADV_INT_MIN	0x00A0	/* 100 msec */
 #define DISCOV_LE_FAST_ADV_INT_MAX	0x00F0	/* 150 msec */
+#define DISCOV_LE_ADV_MESH_MIN		0x00A0  /* 100 msec */
+#define DISCOV_LE_ADV_MESH_MAX		0x00A0  /* 100 msec */
 
 #define NAME_RESOLVE_DURATION		msecs_to_jiffies(10240)	/* 10.24 sec */
 
@@ -1810,7 +1821,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,
+		       u32 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);
diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
index 0336c1bc5d25..0339e6881750 100644
--- a/include/net/bluetooth/hci_sync.h
+++ b/include/net/bluetooth/hci_sync.h
@@ -83,6 +83,8 @@  int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
 struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev, bool ext,
 					     struct sock *sk);
 
+int hci_mesh_send_sync(struct hci_dev *hdev, u8 *data, u8 len);
+
 int hci_reset_sync(struct hci_dev *hdev);
 int hci_dev_open_sync(struct hci_dev *hdev);
 int hci_dev_close_sync(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cd6e1cf7e396..e3d2b59c5ae5 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -638,7 +638,7 @@  static void hci_conn_auto_accept(struct work_struct *work)
 
 static void le_disable_advertising(struct hci_dev *hdev)
 {
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		struct hci_cp_le_set_ext_adv_enable cp;
 
 		cp.enable = 0x00;
@@ -1063,7 +1063,7 @@  static void hci_req_directed_advertising(struct hci_request *req,
 	u8 own_addr_type;
 	u8 enable;
 
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		struct hci_cp_le_set_ext_adv_params cp;
 		bdaddr_t random_addr;
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9d8d2d9e5d1f..1316cd8561bb 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1486,6 +1486,8 @@  static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
 		hci_dev_set_flag(hdev, HCI_LE_SCAN);
 		if (hdev->le_scan_type == LE_SCAN_ACTIVE)
 			clear_pending_adv_report(hdev);
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			hci_discovery_set_state(hdev, DISCOVERY_FINDING);
 		break;
 
 	case LE_SCAN_DISABLE:
@@ -1500,7 +1502,7 @@  static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
 					  d->last_adv_addr_type, NULL,
 					  d->last_adv_rssi, d->last_adv_flags,
 					  d->last_adv_data,
-					  d->last_adv_data_len, NULL, 0);
+					  d->last_adv_data_len, NULL, 0, 0);
 		}
 
 		/* Cancel this timer so that we don't try to disable scanning
@@ -1516,6 +1518,9 @@  static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
 		 */
 		if (hci_dev_test_and_clear_flag(hdev, HCI_LE_SCAN_INTERRUPTED))
 			hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+		else if (!hci_dev_test_flag(hdev, HCI_LE_ADV) &&
+			 hdev->discovery.state == DISCOVERY_FINDING)
+			hci_req_reenable_advertising(hdev);
 
 		break;
 
@@ -2772,7 +2777,7 @@  static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 				  info->dev_class, HCI_RSSI_INVALID,
-				  flags, NULL, 0, NULL, 0);
+				  flags, NULL, 0, NULL, 0, 0);
 	}
 
 	hci_dev_unlock(hdev);
@@ -4433,7 +4438,7 @@  static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 					  info->dev_class, info->rssi,
-					  flags, NULL, 0, NULL, 0);
+					  flags, NULL, 0, NULL, 0, 0);
 		}
 	} else {
 		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -4457,7 +4462,7 @@  static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 
 			mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 					  info->dev_class, info->rssi,
-					  flags, NULL, 0, NULL, 0);
+					  flags, NULL, 0, NULL, 0, 0);
 		}
 	}
 
@@ -4688,7 +4693,7 @@  static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
 
 		mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
 				  info->dev_class, info->rssi,
-				  flags, info->data, eir_len, NULL, 0);
+				  flags, info->data, eir_len, NULL, 0, 0);
 	}
 
 	hci_dev_unlock(hdev);
@@ -5709,7 +5714,7 @@  static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
 static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 			       u8 bdaddr_type, bdaddr_t *direct_addr,
 			       u8 direct_addr_type, s8 rssi, u8 *data, u8 len,
-			       bool ext_adv)
+			       bool ext_adv, bool ctl_time, u32 instant)
 {
 	struct discovery_state *d = &hdev->discovery;
 	struct smp_irk *irk;
@@ -5757,7 +5762,7 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 	 * important to see if the address is matching the local
 	 * controller address.
 	 */
-	if (direct_addr) {
+	if (!hci_dev_test_flag(hdev, HCI_MESH) && direct_addr) {
 		direct_addr_type = ev_bdaddr_type(hdev, direct_addr_type,
 						  &bdaddr_resolved);
 
@@ -5805,6 +5810,18 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 		conn->le_adv_data_len = len;
 	}
 
+	if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND)
+		flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
+	else
+		flags = 0;
+
+	/* All scan results should be sent up for Mesh systems */
+	if (hci_dev_test_flag(hdev, HCI_MESH)) {
+		mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
+				  rssi, flags, data, len, NULL, 0, instant);
+		return;
+	}
+
 	/* Passive scanning shouldn't trigger any device found events,
 	 * except for devices marked as CONN_REPORT for which we do send
 	 * device found events, or advertisement monitoring requested.
@@ -5818,12 +5835,8 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 		    idr_is_empty(&hdev->adv_monitors_idr))
 			return;
 
-		if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND)
-			flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
-		else
-			flags = 0;
 		mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
-				  rssi, flags, data, len, NULL, 0);
+				  rssi, flags, data, len, NULL, 0, 0);
 		return;
 	}
 
@@ -5842,11 +5855,8 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 	 * and just sends a scan response event, then it is marked as
 	 * not connectable as well.
 	 */
-	if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND ||
-	    type == LE_ADV_SCAN_RSP)
+	if (type == LE_ADV_SCAN_RSP)
 		flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
-	else
-		flags = 0;
 
 	/* If there's nothing pending either store the data from this
 	 * event or send an immediate device found event if the data
@@ -5863,7 +5873,7 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 		}
 
 		mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
-				  rssi, flags, data, len, NULL, 0);
+				  rssi, flags, data, len, NULL, 0, 0);
 		return;
 	}
 
@@ -5882,7 +5892,7 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 					  d->last_adv_addr_type, NULL,
 					  d->last_adv_rssi, d->last_adv_flags,
 					  d->last_adv_data,
-					  d->last_adv_data_len, NULL, 0);
+					  d->last_adv_data_len, NULL, 0, 0);
 
 		/* If the new report will trigger a SCAN_REQ store it for
 		 * later merging.
@@ -5899,7 +5909,7 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 		 */
 		clear_pending_adv_report(hdev);
 		mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
-				  rssi, flags, data, len, NULL, 0);
+				  rssi, flags, data, len, NULL, 0, 0);
 		return;
 	}
 
@@ -5909,7 +5919,7 @@  static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 	 */
 	mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
 			  d->last_adv_addr_type, NULL, rssi, d->last_adv_flags,
-			  d->last_adv_data, d->last_adv_data_len, data, len);
+			  d->last_adv_data, d->last_adv_data_len, data, len, 0);
 	clear_pending_adv_report(hdev);
 }
 
@@ -5917,6 +5927,7 @@  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];
+	u32 instant = jiffies;
 
 	hci_dev_lock(hdev);
 
@@ -5934,7 +5945,8 @@  static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 			rssi = ev->data[ev->length];
 			process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
 					   ev->bdaddr_type, NULL, 0, rssi,
-					   ev->data, ev->length, false);
+					   ev->data, ev->length, false,
+					   false, instant);
 		} else {
 			bt_dev_err(hdev, "Dropping invalid advertising data");
 		}
@@ -5993,6 +6005,7 @@  static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	u8 num_reports = skb->data[0];
 	void *ptr = &skb->data[1];
+	u32 instant = jiffies;
 
 	hci_dev_lock(hdev);
 
@@ -6007,7 +6020,8 @@  static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 			process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
 					   ev->bdaddr_type, NULL, 0, ev->rssi,
 					   ev->data, ev->length,
-					   !(evt_type & LE_EXT_ADV_LEGACY_PDU));
+					   !(evt_type & LE_EXT_ADV_LEGACY_PDU),
+					   false, instant);
 		}
 
 		ptr += sizeof(*ev) + ev->length;
@@ -6197,6 +6211,7 @@  static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
 {
 	u8 num_reports = skb->data[0];
 	struct hci_ev_le_direct_adv_info *ev = (void *)&skb->data[1];
+	u32 instant = jiffies;
 
 	if (!num_reports || skb->len < num_reports * sizeof(*ev) + 1)
 		return;
@@ -6207,7 +6222,7 @@  static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
 		process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
 				   ev->bdaddr_type, &ev->direct_addr,
 				   ev->direct_addr_type, ev->rssi, NULL, 0,
-				   false);
+				   false, false, instant);
 
 	hci_dev_unlock(hdev);
 }
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 8b3205e4b23e..4cba7c3e2ba2 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -686,7 +686,12 @@  static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
 
 		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
 		ext_enable_cp.enable = LE_SCAN_ENABLE;
-		ext_enable_cp.filter_dup = filter_dup;
+
+		/* Mesh protocols requires duplicate filtering to be disabled */
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+		else
+			ext_enable_cp.filter_dup = filter_dup;
 
 		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
 			    sizeof(ext_enable_cp), &ext_enable_cp);
@@ -694,18 +699,31 @@  static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
 		struct hci_cp_le_set_scan_param param_cp;
 		struct hci_cp_le_set_scan_enable enable_cp;
 
+		memset(&enable_cp, 0, sizeof(enable_cp));
+		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+			    &enable_cp);
+
 		memset(&param_cp, 0, sizeof(param_cp));
 		param_cp.type = type;
 		param_cp.interval = cpu_to_le16(interval);
 		param_cp.window = cpu_to_le16(window);
 		param_cp.own_address_type = own_addr_type;
-		param_cp.filter_policy = filter_policy;
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			param_cp.filter_policy = 0;
+		else
+			param_cp.filter_policy = filter_policy;
 		hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
 			    &param_cp);
 
 		memset(&enable_cp, 0, sizeof(enable_cp));
 		enable_cp.enable = LE_SCAN_ENABLE;
-		enable_cp.filter_dup = filter_dup;
+
+		/* Mesh protocols requires duplicate filtering to be disabled */
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+		else
+			enable_cp.filter_dup = filter_dup;
+
 		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
 			    &enable_cp);
 	}
@@ -840,7 +858,7 @@  void __hci_req_pause_adv_instances(struct hci_request *req)
 	__hci_req_disable_advertising(req);
 
 	/* If we are using software rotation, pause the loop */
-	if (!ext_adv_capable(req->hdev))
+	if (!use_ext_adv(req->hdev))
 		cancel_adv_timeout(req->hdev);
 }
 
@@ -851,7 +869,7 @@  static void __hci_req_resume_adv_instances(struct hci_request *req)
 
 	bt_dev_dbg(req->hdev, "Resuming advertising instances");
 
-	if (ext_adv_capable(req->hdev)) {
+	if (use_ext_adv(req->hdev)) {
 		/* Call for each tracked instance to be re-enabled */
 		list_for_each_entry(adv, &req->hdev->adv_instances, list) {
 			__hci_req_enable_ext_advertising(req,
@@ -886,7 +904,7 @@  static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
 
 void __hci_req_disable_advertising(struct hci_request *req)
 {
-	if (ext_adv_capable(req->hdev)) {
+	if (use_ext_adv(req->hdev)) {
 		__hci_req_disable_ext_adv_instance(req, 0x00);
 
 	} else {
@@ -972,8 +990,13 @@  void __hci_req_enable_advertising(struct hci_request *req)
 
 	/* If the "connectable" instance flag was not set, then choose between
 	 * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
+	 * If the controller has been enabled for mesh, all advertisements should
+	 * non-connectable, and non-resolvable private. TODO: bgix
 	 */
-	connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
+	if (hci_dev_test_flag(hdev, HCI_MESH))
+		connectable = false;
+	else
+		connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
 		      mgmt_get_connectable(hdev);
 
 	if (!is_advertising_allowed(hdev, connectable))
@@ -1016,8 +1039,12 @@  void __hci_req_enable_advertising(struct hci_request *req)
 		else
 			cp.type = LE_ADV_NONCONN_IND;
 
-		if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
-		    hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
+		if (hci_dev_test_flag(hdev, HCI_MESH)) {
+			adv_min_interval = DISCOV_LE_ADV_MESH_MIN;
+			adv_max_interval = DISCOV_LE_ADV_MESH_MAX;
+			cp.filter_policy = 3;
+		} else if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
+			hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
 			adv_min_interval = DISCOV_LE_FAST_ADV_INT_MIN;
 			adv_max_interval = DISCOV_LE_FAST_ADV_INT_MAX;
 		}
@@ -1028,7 +1055,8 @@  void __hci_req_enable_advertising(struct hci_request *req)
 	cp.own_address_type = own_addr_type;
 	cp.channel_map = hdev->le_adv_channel_map;
 
-	hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
+	if (hdev->manufacturer != 0x000f || hdev->hci_rev != 0x16e4)
+		hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
 
 	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
 }
@@ -1041,7 +1069,7 @@  void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
 	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
 		return;
 
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		struct {
 			struct hci_cp_le_set_ext_scan_rsp_data cp;
 			u8 data[HCI_MAX_EXT_AD_LENGTH];
@@ -1093,7 +1121,7 @@  void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
 	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
 		return;
 
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		struct {
 			struct hci_cp_le_set_ext_adv_data cp;
 			u8 data[HCI_MAX_EXT_AD_LENGTH];
@@ -1189,7 +1217,7 @@  void hci_req_reenable_advertising(struct hci_dev *hdev)
 		__hci_req_schedule_adv_instance(&req, hdev->cur_adv_instance,
 						true);
 	} else {
-		if (ext_adv_capable(hdev)) {
+		if (use_ext_adv(hdev)) {
 			__hci_req_start_ext_adv(&req, 0x00);
 		} else {
 			__hci_req_update_adv_data(&req, 0x00);
@@ -1664,7 +1692,7 @@  int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
 				adv_instance->remaining_time - timeout;
 
 	/* Only use work for scheduling instances with legacy advertising */
-	if (!ext_adv_capable(hdev)) {
+	if (!use_ext_adv(hdev)) {
 		hdev->adv_instance_timeout = timeout;
 		queue_delayed_work(hdev->req_workqueue,
 			   &hdev->adv_instance_expire,
@@ -1680,7 +1708,7 @@  int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
 		return 0;
 
 	hdev->cur_adv_instance = instance;
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		__hci_req_start_ext_adv(req, instance);
 	} else {
 		__hci_req_update_adv_data(req, instance);
@@ -1752,7 +1780,7 @@  void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
 	    hci_dev_test_flag(hdev, HCI_ADVERTISING))
 		return;
 
-	if (next_instance && !ext_adv_capable(hdev))
+	if (next_instance && !use_ext_adv(hdev))
 		__hci_req_schedule_adv_instance(req, next_instance->instance,
 						false);
 }
@@ -2002,7 +2030,7 @@  static int discoverable_update(struct hci_request *req, unsigned long opt)
 		 * address in limited privacy mode.
 		 */
 		if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
-			if (ext_adv_capable(hdev))
+			if (use_ext_adv(hdev))
 				__hci_req_start_ext_adv(req, 0x00);
 			else
 				__hci_req_enable_advertising(req);
@@ -2151,7 +2179,8 @@  static void le_scan_disable_work(struct work_struct *work)
 
 	bt_dev_dbg(hdev, "");
 
-	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
+	if (!hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
+				hci_dev_test_flag(hdev, HCI_MESH))
 		return;
 
 	cancel_delayed_work(&hdev->le_scan_restart);
@@ -2197,9 +2226,11 @@  static void le_scan_disable_work(struct work_struct *work)
 	return;
 
 discov_stopped:
-	hci_dev_lock(hdev);
-	hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-	hci_dev_unlock(hdev);
+	if (!hci_dev_test_flag(hdev, HCI_MESH)) {
+		hci_dev_lock(hdev);
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+		hci_dev_unlock(hdev);
+	}
 }
 
 static int le_scan_restart(struct hci_request *req, unsigned long opt)
@@ -2222,7 +2253,12 @@  static int le_scan_restart(struct hci_request *req, unsigned long opt)
 
 		memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
 		ext_enable_cp.enable = LE_SCAN_ENABLE;
-		ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+
+		/* Mesh protocols requires duplicate filtering to be disabled */
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+		else
+			ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
 
 		hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
 			    sizeof(ext_enable_cp), &ext_enable_cp);
@@ -2231,7 +2267,13 @@  static int le_scan_restart(struct hci_request *req, unsigned long opt)
 
 		memset(&cp, 0, sizeof(cp));
 		cp.enable = LE_SCAN_ENABLE;
-		cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+
+		/* Mesh protocols requires duplicate filtering to be disabled */
+		if (hci_dev_test_flag(hdev, HCI_MESH))
+			cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+		else
+			cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+
 		hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 	}
 
@@ -2344,6 +2386,21 @@  static int active_scan(struct hci_request *req, unsigned long opt)
 	return 0;
 }
 
+static int mesh_scan(struct hci_request *req, unsigned long opt)
+{
+	struct hci_dev *hdev = req->hdev;
+	u16 window = hdev->le_scan_window;
+
+	BT_INFO("MESH-SCAN %s", hdev->name);
+
+	/* In Mesh mode we are always at least passive scanning,
+	 * with no filtering */
+
+	hci_req_start_scan(req, LE_SCAN_PASSIVE, window, window,
+			   0x00, 0x00, false, false);
+	return 0;
+}
+
 static int interleaved_discov(struct hci_request *req, unsigned long opt)
 {
 	int err;
@@ -2398,8 +2455,16 @@  static void start_discovery(struct hci_dev *hdev, u8 *status)
 		break;
 	case DISCOV_TYPE_LE:
 		timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
-		hci_req_sync(hdev, active_scan, hdev->le_scan_int_discovery,
-			     HCI_CMD_TIMEOUT, status);
+		if (hci_dev_test_flag(hdev, HCI_MESH)) {
+			BT_INFO("LE Discovery - (passive)");
+			hci_req_sync(hdev, mesh_scan, DISCOV_LE_SCAN_INT,
+					HCI_CMD_TIMEOUT, status);
+		} else {
+			BT_INFO("LE Discovery - (active)");
+			hci_req_sync(hdev, active_scan,
+					hdev->le_scan_int_discovery,
+					HCI_CMD_TIMEOUT, status);
+		}
 		break;
 	default:
 		*status = HCI_ERROR_UNSPECIFIED;
@@ -2627,7 +2692,7 @@  static int powered_update_hci(struct hci_request *req, unsigned long opt)
 		    list_empty(&hdev->adv_instances)) {
 			int err;
 
-			if (ext_adv_capable(hdev)) {
+			if (use_ext_adv(hdev)) {
 				err = __hci_req_setup_ext_adv_instance(req,
 								       0x00);
 				if (!err)
@@ -2640,7 +2705,7 @@  static int powered_update_hci(struct hci_request *req, unsigned long opt)
 			}
 
 			if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
-				if (!ext_adv_capable(hdev))
+				if (!use_ext_adv(hdev))
 					__hci_req_enable_advertising(req);
 				else if (!err)
 					__hci_req_enable_ext_advertising(req,
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index ad86caf41f91..b63bd01e254d 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -856,7 +856,7 @@  int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
 		return 0;
 
-	if (ext_adv_capable(hdev))
+	if (use_ext_adv(hdev))
 		return hci_set_ext_scan_rsp_data_sync(hdev, instance);
 
 	return __hci_set_scan_rsp_data_sync(hdev, instance);
@@ -927,7 +927,7 @@  static int hci_start_adv_sync(struct hci_dev *hdev, u8 instance)
 {
 	int err;
 
-	if (ext_adv_capable(hdev))
+	if (use_ext_adv(hdev))
 		return hci_start_ext_adv_sync(hdev, instance);
 
 	err = hci_update_adv_data_sync(hdev, instance);
@@ -951,7 +951,7 @@  int hci_enable_advertising_sync(struct hci_dev *hdev)
 	u32 flags;
 	u8 status;
 
-	if (ext_adv_capable(hdev))
+	if (use_ext_adv(hdev))
 		return hci_enable_ext_advertising_sync(hdev,
 						       hdev->cur_adv_instance);
 
@@ -1100,6 +1100,49 @@  static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
 				     HCI_CMD_TIMEOUT);
 }
 
+int hci_mesh_send_sync(struct hci_dev *hdev, u8 *data, u8 len)
+{
+	struct hci_cp_le_set_adv_data cp_data;
+	struct hci_cp_le_set_adv_param cp_param;
+	u8 own_addr_type, enable = 0x00;
+	int err;
+
+	memset(&cp_data, 0, sizeof(cp_data));
+	cp_data.length = len + 1;
+	cp_data.data[0] = len;
+	memcpy(cp_data.data + 1, data, len);
+
+	__hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
+				     sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+
+	hci_update_random_address_sync(hdev, true, false, &own_addr_type);
+
+	memset(&cp_param, 0, sizeof(cp_param));
+	cp_param.type = LE_ADV_NONCONN_IND;
+	cp_param.min_interval = cpu_to_le16(DISCOV_LE_ADV_MESH_MIN);
+	cp_param.max_interval = cpu_to_le16(DISCOV_LE_ADV_MESH_MAX);
+	cp_param.own_address_type = 1;
+	cp_param.channel_map = 7;
+	cp_param.filter_policy = 3;
+
+	__hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_PARAM,
+				       sizeof(cp_param), &cp_param,
+				       HCI_CMD_TIMEOUT);
+
+	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
+			     sizeof(cp_data), &cp_data, HCI_CMD_TIMEOUT);
+
+	if (err)
+		return err;
+
+	memcpy(hdev->adv_data, cp_data.data, sizeof(cp_data.data));
+	hdev->adv_data_len = len;
+
+	enable = 0x01;
+	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
+				     sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+}
+
 static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
 {
 	struct hci_cp_le_set_adv_data cp;
@@ -1128,7 +1171,7 @@  int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
 	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
 		return 0;
 
-	if (ext_adv_capable(hdev))
+	if (use_ext_adv(hdev))
 		return hci_set_ext_adv_data_sync(hdev, instance);
 
 	return hci_set_adv_data_sync(hdev, instance);
@@ -1140,7 +1183,7 @@  int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
 	struct adv_info *adv = NULL;
 	u16 timeout;
 
-	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev))
+	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !use_ext_adv(hdev))
 		return -EPERM;
 
 	if (hdev->adv_instance_timeout)
@@ -1170,7 +1213,7 @@  int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
 		adv->remaining_time = adv->remaining_time - timeout;
 
 	/* Only use work for scheduling instances with legacy advertising */
-	if (!ext_adv_capable(hdev)) {
+	if (!use_ext_adv(hdev)) {
 		hdev->adv_instance_timeout = timeout;
 		queue_delayed_work(hdev->req_workqueue,
 				   &hdev->adv_instance_expire,
@@ -1209,10 +1252,13 @@  static int hci_clear_adv_sets_sync(struct hci_dev *hdev, struct sock *sk)
 static int hci_clear_adv_sync(struct hci_dev *hdev, struct sock *sk, bool force)
 {
 	struct adv_info *adv, *n;
+	int err = 0;
 
 	if (ext_adv_capable(hdev))
 		/* Remove all existing sets */
-		return hci_clear_adv_sets_sync(hdev, sk);
+		err = hci_clear_adv_sets_sync(hdev, sk);
+	if (use_ext_adv(hdev))
+		return err;
 
 	/* This is safe as long as there is no command send while the lock is
 	 * held.
@@ -1240,11 +1286,13 @@  static int hci_clear_adv_sync(struct hci_dev *hdev, struct sock *sk, bool force)
 static int hci_remove_adv_sync(struct hci_dev *hdev, u8 instance,
 			       struct sock *sk)
 {
-	int err;
+	int err = 0;
 
 	/* If we use extended advertising, instance has to be removed first. */
 	if (ext_adv_capable(hdev))
-		return hci_remove_ext_adv_instance_sync(hdev, instance, sk);
+		err = hci_remove_ext_adv_instance_sync(hdev, instance, sk);
+	if (use_ext_adv(hdev))
+		return err;
 
 	/* This is safe as long as there is no command send while the lock is
 	 * held.
@@ -1309,7 +1357,7 @@  int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
 	if (!hdev_is_powered(hdev) || hci_dev_test_flag(hdev, HCI_ADVERTISING))
 		return 0;
 
-	if (next && !ext_adv_capable(hdev))
+	if (next && !use_ext_adv(hdev))
 		hci_schedule_adv_instance_sync(hdev, next->instance, false);
 
 	return 0;
@@ -1343,13 +1391,16 @@  int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type)
 int hci_disable_advertising_sync(struct hci_dev *hdev)
 {
 	u8 enable = 0x00;
+	int err = 0;
 
 	/* If controller is not advertising we are done. */
 	if (!hci_dev_test_flag(hdev, HCI_LE_ADV))
 		return 0;
 
 	if (ext_adv_capable(hdev))
-		return hci_disable_ext_adv_instance_sync(hdev, 0x00);
+		err = hci_disable_ext_adv_instance_sync(hdev, 0x00);
+	if (use_ext_adv(hdev))
+		return err;
 
 	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
 				     sizeof(enable), &enable, HCI_CMD_TIMEOUT);
@@ -1362,7 +1413,11 @@  static int hci_le_set_ext_scan_enable_sync(struct hci_dev *hdev, u8 val,
 
 	memset(&cp, 0, sizeof(cp));
 	cp.enable = val;
-	cp.filter_dup = filter_dup;
+
+	if (hci_dev_test_flag(hdev, HCI_MESH))
+		cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+	else
+		cp.filter_dup = filter_dup;
 
 	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
 				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
@@ -1378,7 +1433,11 @@  static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
 
 	memset(&cp, 0, sizeof(cp));
 	cp.enable = val;
-	cp.filter_dup = filter_dup;
+
+	if (val && hci_dev_test_flag(hdev, HCI_MESH))
+		cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+	else
+		cp.filter_dup = filter_dup;
 
 	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
 				     sizeof(cp), &cp, HCI_CMD_TIMEOUT);
@@ -1676,7 +1735,7 @@  static int hci_pause_advertising_sync(struct hci_dev *hdev)
 		return err;
 
 	/* If we are using software rotation, pause the loop */
-	if (!ext_adv_capable(hdev))
+	if (!use_ext_adv(hdev))
 		cancel_adv_timeout(hdev);
 
 	hdev->advertising_paused = true;
@@ -1704,7 +1763,7 @@  static int hci_resume_advertising_sync(struct hci_dev *hdev)
 
 	bt_dev_dbg(hdev, "Resuming advertising instances");
 
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		/* Call for each tracked instance to be re-enabled */
 		list_for_each_entry_safe(adv, tmp, &hdev->adv_instances, list) {
 			err = hci_enable_ext_advertising_sync(hdev,
@@ -2088,7 +2147,8 @@  int hci_update_passive_scan_sync(struct hci_dev *hdev)
 	bt_dev_dbg(hdev, "ADV monitoring is %s",
 		   hci_is_adv_monitoring(hdev) ? "on" : "off");
 
-	if (list_empty(&hdev->pend_le_conns) &&
+	if (!hci_dev_test_flag(hdev, HCI_MESH) &&
+	    list_empty(&hdev->pend_le_conns) &&
 	    list_empty(&hdev->pend_le_reports) &&
 	    !hci_is_adv_monitoring(hdev)) {
 		/* If there is no pending LE connections or devices
@@ -2236,7 +2296,7 @@  static int hci_powered_update_adv_sync(struct hci_dev *hdev)
 	 */
 	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
 	    list_empty(&hdev->adv_instances)) {
-		if (ext_adv_capable(hdev)) {
+		if (use_ext_adv(hdev)) {
 			err = hci_setup_ext_adv_instance_sync(hdev, 0x00);
 			if (!err)
 				hci_update_scan_rsp_data_sync(hdev, 0x00);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index bf989ae03f9f..120798f039fe 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -129,6 +129,8 @@  static const u16 mgmt_commands[] = {
 	MGMT_OP_ADD_EXT_ADV_PARAMS,
 	MGMT_OP_ADD_EXT_ADV_DATA,
 	MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
+	MGMT_OP_SET_MESH,
+	MGMT_OP_MESH_SEND,
 };
 
 static const u16 mgmt_events[] = {
@@ -994,7 +996,7 @@  static int rpa_expired_sync(struct hci_dev *hdev, void *data)
 	 * controller happens in the hci_req_enable_advertising()
 	 * function.
 	 */
-	if (ext_adv_capable(hdev))
+	if (use_ext_adv(hdev))
 		return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
 	else
 		return hci_enable_advertising_sync(hdev);
@@ -1015,13 +1017,43 @@  static void rpa_expired(struct work_struct *work)
 	hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
 }
 
+static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev);
+static int mesh_send_done_sync(struct hci_dev *hdev, void *data)
+{
+	struct mgmt_pending_cmd *cmd = data;
+
+	bt_dev_dbg(hdev, "Send Mesh Packet Done");
+	hci_disable_advertising_sync(hdev);
+	hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
+	send_settings_rsp(cmd->sk, MGMT_OP_SET_MESH, hdev);
+	mgmt_pending_remove(cmd);
+
+	return 0;
+}
+
+static void mesh_send_done(struct work_struct *work)
+{
+	struct mgmt_pending_cmd *cmd;
+	struct hci_dev *hdev = container_of(work, struct hci_dev,
+					    mesh_send_done.work);
+
+	if (!hci_dev_test_flag(hdev, HCI_MESH_SENDING))
+		return;
+
+	cmd = pending_find(MGMT_OP_MESH_SEND, hdev);
+	hci_cmd_sync_queue(hdev, mesh_send_done_sync, cmd, NULL);
+}
+
 static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
 {
 	if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
 		return;
 
+	BT_INFO("MGMT ver %d.%d", MGMT_VERSION, MGMT_REVISION);
+
 	INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
 	INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
+	INIT_DELAYED_WORK(&hdev->mesh_send_done, mesh_send_done);
 
 	/* Non-mgmt controlled devices get this bit set
 	 * implicitly so that pairing works for them, however
@@ -1992,6 +2024,9 @@  static int set_le_sync(struct hci_dev *hdev, void *data)
 	u8 val = !!cp->val;
 	int err;
 
+	hci_dev_clear_flag(hdev, HCI_MESH);
+	hci_dev_clear_flag(hdev, HCI_MESH_ACTIVE);
+
 	if (!val) {
 		if (hci_dev_test_flag(hdev, HCI_LE_ADV))
 			hci_disable_advertising_sync(hdev);
@@ -2010,7 +2045,7 @@  static int set_le_sync(struct hci_dev *hdev, void *data)
 	 * update in powered_update_hci will take care of it.
 	 */
 	if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
-		if (ext_adv_capable(hdev)) {
+		if (use_ext_adv(hdev)) {
 			int status;
 
 			status = hci_setup_ext_adv_instance_sync(hdev, 0x00);
@@ -2027,6 +2062,159 @@  static int set_le_sync(struct hci_dev *hdev, void *data)
 	return err;
 }
 
+static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
+{
+	struct mgmt_pending_cmd *cmd = data;
+	u8 status = mgmt_status(err);
+	struct sock *sk = cmd->sk;
+
+	if (status) {
+		mgmt_pending_foreach(MGMT_OP_SET_MESH, hdev, cmd_status_rsp,
+							&status);
+		return;
+	}
+
+	send_settings_rsp(sk, MGMT_OP_SET_MESH, hdev);
+}
+
+static int set_mesh_sync(struct hci_dev *hdev, void *data)
+{
+	struct mgmt_pending_cmd *cmd = data;
+	struct mgmt_cp_set_mesh *cp = cmd->param;
+	size_t len = cmd->param_len;
+
+	memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
+	hci_dev_clear_flag(hdev, HCI_MESH_ACTIVE);
+
+	if (cp->enable) {
+		hci_dev_set_flag(hdev, HCI_MESH);
+
+		if (cp->active)
+			hci_dev_set_flag(hdev, HCI_MESH_ACTIVE);
+
+	} else
+		hci_dev_clear_flag(hdev, HCI_MESH);
+
+	/* Truncate the passed ad_type list if too long */
+	if (len - sizeof(*cp) <= sizeof(hdev->mesh_ad_types))
+		memcpy(hdev->mesh_ad_types, cp->ad_types, len - sizeof(*cp));
+	else
+		memcpy(hdev->mesh_ad_types, cp->ad_types,
+						sizeof(hdev->mesh_ad_types));
+
+	hci_update_passive_scan_sync(hdev);
+	return 0;
+}
+
+static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+{
+	struct mgmt_cp_set_mesh *cp = data;
+	struct mgmt_pending_cmd *cmd;
+	int err = 0;
+
+	bt_dev_dbg(hdev, "sock %p", sk);
+
+	if (!lmp_le_capable(hdev))
+		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH,
+				       MGMT_STATUS_NOT_SUPPORTED);
+
+	if ((cp->enable != 0x00 && cp->enable != 0x01) ||
+				(cp->active != 0x00 && cp->active != 0x01))
+		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH,
+				       MGMT_STATUS_INVALID_PARAMS);
+
+	hci_dev_lock(hdev);
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH, hdev, data, len);
+	if (!cmd)
+		err = -ENOMEM;
+	else
+		err = hci_cmd_sync_queue(hdev, set_mesh_sync, cmd,
+						set_mesh_complete);
+
+
+	send_settings_rsp(sk, MGMT_OP_SET_MESH, hdev);
+	hci_dev_unlock(hdev);
+	return err;
+}
+
+static void mesh_send_complete(struct hci_dev *hdev, void *data, int err)
+{
+	struct mgmt_pending_cmd *cmd = data;
+	struct mgmt_cp_mesh_send *cp = cmd->param;
+	unsigned long mesh_send_interval;
+	u8 mgmt_err = mgmt_status(err);
+
+	/* Report any errors here, but don't report completion */
+
+	if (mgmt_err) {
+		hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
+		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_MESH_SEND, mgmt_err);
+		mgmt_pending_remove(cmd);
+		return;
+	}
+
+	mesh_send_interval = msecs_to_jiffies((cp->cnt) * 25);
+	queue_delayed_work(hdev->req_workqueue, &hdev->mesh_send_done,
+			   mesh_send_interval);
+}
+
+static int mesh_send_sync(struct hci_dev *hdev, void *data)
+{
+	struct mgmt_pending_cmd *cmd = data;
+
+	if (hci_dev_test_flag(hdev, HCI_LE_ADV))
+		return MGMT_STATUS_BUSY;
+
+	return hci_mesh_send_sync(hdev, cmd->param, cmd->param_len);
+}
+
+static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
+{
+	struct mgmt_pending_cmd *cmd;
+	struct mgmt_cp_mesh_send *send = data;
+	int err = 0;
+
+	bt_dev_dbg(hdev, "Send Mesh Packet Start...");
+
+	if (!hci_dev_test_flag(hdev, HCI_MESH) || len <= MGMT_MESH_SEND_SIZE ||
+					len > (MGMT_MESH_SEND_SIZE + 29))
+		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+				       MGMT_STATUS_REJECTED);
+
+	hci_dev_lock(hdev);
+	if (hci_dev_test_flag(hdev, HCI_MESH_SENDING) ||
+				hci_dev_test_flag(hdev, HCI_LE_ADV)) {
+		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+							MGMT_STATUS_BUSY);
+		goto done;
+	}
+
+
+	hci_dev_set_flag(hdev, HCI_MESH_SENDING);
+
+	cmd = mgmt_pending_add(sk, MGMT_OP_MESH_SEND, hdev, send->data,
+				len - sizeof(struct mgmt_cp_mesh_send));
+
+	if (!cmd)
+		err = -ENOMEM;
+	else
+		err = hci_cmd_sync_queue(hdev, mesh_send_sync, cmd,
+						mesh_send_complete);
+
+	if (err < 0) {
+		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
+						MGMT_STATUS_FAILED);
+
+		if (cmd)
+			mgmt_pending_remove(cmd);
+	}
+
+done:
+	hci_dev_unlock(hdev);
+	return err;
+}
+
 static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
 	struct mgmt_mode *cp = data;
@@ -5731,7 +5919,7 @@  static int set_adv_sync(struct hci_dev *hdev, void *data)
 		 */
 		hdev->cur_adv_instance = 0x00;
 
-		if (ext_adv_capable(hdev)) {
+		if (use_ext_adv(hdev)) {
 			hci_start_ext_adv_sync(hdev, 0x00);
 		} else {
 			hci_update_adv_data_sync(hdev, 0x00);
@@ -5780,6 +5968,7 @@  static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
 	if (!hdev_is_powered(hdev) ||
 	    (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
 	     (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
+	    hci_dev_test_flag(hdev, HCI_MESH) ||
 	    hci_conn_num(hdev, LE_LINK) > 0 ||
 	    (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
 	     hdev->le_scan_type == LE_SCAN_ACTIVE)) {
@@ -7730,11 +7919,10 @@  static u32 get_supported_adv_flags(struct hci_dev *hdev)
 	/* In extended adv TX_POWER returned from Set Adv Param
 	 * will be always valid.
 	 */
-	if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) ||
-	    ext_adv_capable(hdev))
+	if ((hdev->adv_tx_power != HCI_TX_POWER_INVALID) || use_ext_adv(hdev))
 		flags |= MGMT_ADV_FLAG_TX_POWER;
 
-	if (ext_adv_capable(hdev)) {
+	if (use_ext_adv(hdev)) {
 		flags |= MGMT_ADV_FLAG_SEC_1M;
 		flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
 		flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
@@ -8703,7 +8891,10 @@  static const struct hci_mgmt_handler mgmt_handlers[] = {
 	{ add_ext_adv_data,        MGMT_ADD_EXT_ADV_DATA_SIZE,
 						HCI_MGMT_VAR_LEN },
 	{ add_adv_patterns_monitor_rssi,
-				   MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
+				   MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE },
+	{ set_mesh,                MGMT_SET_MESH_SIZE,
+						HCI_MGMT_VAR_LEN },
+	{ mesh_send,               MGMT_MESH_SEND_SIZE,
 						HCI_MGMT_VAR_LEN },
 };
 
@@ -9526,7 +9717,8 @@  static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
 
 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,
+		       u32 instant)
 {
 	char buf[512];
 	struct mgmt_ev_device_found *ev = (void *)buf;