linux/net/bluetooth/msft.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2020 Google Corporation
   4 */
   5
   6#include <net/bluetooth/bluetooth.h>
   7#include <net/bluetooth/hci_core.h>
   8#include <net/bluetooth/mgmt.h>
   9
  10#include "hci_request.h"
  11#include "mgmt_util.h"
  12#include "msft.h"
  13
  14#define MSFT_RSSI_THRESHOLD_VALUE_MIN           -127
  15#define MSFT_RSSI_THRESHOLD_VALUE_MAX           20
  16#define MSFT_RSSI_LOW_TIMEOUT_MAX               0x3C
  17
  18#define MSFT_OP_READ_SUPPORTED_FEATURES         0x00
  19struct msft_cp_read_supported_features {
  20        __u8   sub_opcode;
  21} __packed;
  22
  23struct msft_rp_read_supported_features {
  24        __u8   status;
  25        __u8   sub_opcode;
  26        __le64 features;
  27        __u8   evt_prefix_len;
  28        __u8   evt_prefix[];
  29} __packed;
  30
  31#define MSFT_OP_LE_MONITOR_ADVERTISEMENT        0x03
  32#define MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN 0x01
  33struct msft_le_monitor_advertisement_pattern {
  34        __u8 length;
  35        __u8 data_type;
  36        __u8 start_byte;
  37        __u8 pattern[];
  38};
  39
  40struct msft_le_monitor_advertisement_pattern_data {
  41        __u8 count;
  42        __u8 data[];
  43};
  44
  45struct msft_cp_le_monitor_advertisement {
  46        __u8 sub_opcode;
  47        __s8 rssi_high;
  48        __s8 rssi_low;
  49        __u8 rssi_low_interval;
  50        __u8 rssi_sampling_period;
  51        __u8 cond_type;
  52        __u8 data[];
  53} __packed;
  54
  55struct msft_rp_le_monitor_advertisement {
  56        __u8 status;
  57        __u8 sub_opcode;
  58        __u8 handle;
  59} __packed;
  60
  61#define MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT 0x04
  62struct msft_cp_le_cancel_monitor_advertisement {
  63        __u8 sub_opcode;
  64        __u8 handle;
  65} __packed;
  66
  67struct msft_rp_le_cancel_monitor_advertisement {
  68        __u8 status;
  69        __u8 sub_opcode;
  70} __packed;
  71
  72#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE      0x05
  73struct msft_cp_le_set_advertisement_filter_enable {
  74        __u8 sub_opcode;
  75        __u8 enable;
  76} __packed;
  77
  78struct msft_rp_le_set_advertisement_filter_enable {
  79        __u8 status;
  80        __u8 sub_opcode;
  81} __packed;
  82
  83struct msft_monitor_advertisement_handle_data {
  84        __u8  msft_handle;
  85        __u16 mgmt_handle;
  86        struct list_head list;
  87};
  88
  89struct msft_data {
  90        __u64 features;
  91        __u8  evt_prefix_len;
  92        __u8  *evt_prefix;
  93        struct list_head handle_map;
  94        __u16 pending_add_handle;
  95        __u16 pending_remove_handle;
  96        __u8 reregistering;
  97        __u8 filter_enabled;
  98};
  99
 100static int __msft_add_monitor_pattern(struct hci_dev *hdev,
 101                                      struct adv_monitor *monitor);
 102
 103bool msft_monitor_supported(struct hci_dev *hdev)
 104{
 105        return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
 106}
 107
 108static bool read_supported_features(struct hci_dev *hdev,
 109                                    struct msft_data *msft)
 110{
 111        struct msft_cp_read_supported_features cp;
 112        struct msft_rp_read_supported_features *rp;
 113        struct sk_buff *skb;
 114
 115        cp.sub_opcode = MSFT_OP_READ_SUPPORTED_FEATURES;
 116
 117        skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
 118                             HCI_CMD_TIMEOUT);
 119        if (IS_ERR(skb)) {
 120                bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)",
 121                           PTR_ERR(skb));
 122                return false;
 123        }
 124
 125        if (skb->len < sizeof(*rp)) {
 126                bt_dev_err(hdev, "MSFT supported features length mismatch");
 127                goto failed;
 128        }
 129
 130        rp = (struct msft_rp_read_supported_features *)skb->data;
 131
 132        if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES)
 133                goto failed;
 134
 135        if (rp->evt_prefix_len > 0) {
 136                msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len,
 137                                           GFP_KERNEL);
 138                if (!msft->evt_prefix)
 139                        goto failed;
 140        }
 141
 142        msft->evt_prefix_len = rp->evt_prefix_len;
 143        msft->features = __le64_to_cpu(rp->features);
 144
 145        if (msft->features & MSFT_FEATURE_MASK_CURVE_VALIDITY)
 146                hdev->msft_curve_validity = true;
 147
 148        kfree_skb(skb);
 149        return true;
 150
 151failed:
 152        kfree_skb(skb);
 153        return false;
 154}
 155
 156/* This function requires the caller holds hdev->lock */
 157static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
 158{
 159        struct adv_monitor *monitor;
 160        struct msft_data *msft = hdev->msft_data;
 161        int err;
 162
 163        while (1) {
 164                monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
 165                if (!monitor) {
 166                        /* All monitors have been reregistered */
 167                        msft->reregistering = false;
 168                        hci_update_background_scan(hdev);
 169                        return;
 170                }
 171
 172                msft->pending_add_handle = (u16)handle;
 173                err = __msft_add_monitor_pattern(hdev, monitor);
 174
 175                /* If success, we return and wait for monitor added callback */
 176                if (!err)
 177                        return;
 178
 179                /* Otherwise remove the monitor and keep registering */
 180                hci_free_adv_monitor(hdev, monitor);
 181                handle++;
 182        }
 183}
 184
 185void msft_do_open(struct hci_dev *hdev)
 186{
 187        struct msft_data *msft;
 188
 189        if (hdev->msft_opcode == HCI_OP_NOP)
 190                return;
 191
 192        bt_dev_dbg(hdev, "Initialize MSFT extension");
 193
 194        msft = kzalloc(sizeof(*msft), GFP_KERNEL);
 195        if (!msft)
 196                return;
 197
 198        if (!read_supported_features(hdev, msft)) {
 199                kfree(msft);
 200                return;
 201        }
 202
 203        INIT_LIST_HEAD(&msft->handle_map);
 204        hdev->msft_data = msft;
 205
 206        if (msft_monitor_supported(hdev)) {
 207                msft->reregistering = true;
 208                msft_set_filter_enable(hdev, true);
 209                reregister_monitor_on_restart(hdev, 0);
 210        }
 211}
 212
 213void msft_do_close(struct hci_dev *hdev)
 214{
 215        struct msft_data *msft = hdev->msft_data;
 216        struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
 217        struct adv_monitor *monitor;
 218
 219        if (!msft)
 220                return;
 221
 222        bt_dev_dbg(hdev, "Cleanup of MSFT extension");
 223
 224        hdev->msft_data = NULL;
 225
 226        list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) {
 227                monitor = idr_find(&hdev->adv_monitors_idr,
 228                                   handle_data->mgmt_handle);
 229
 230                if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
 231                        monitor->state = ADV_MONITOR_STATE_REGISTERED;
 232
 233                list_del(&handle_data->list);
 234                kfree(handle_data);
 235        }
 236
 237        kfree(msft->evt_prefix);
 238        kfree(msft);
 239}
 240
 241void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
 242{
 243        struct msft_data *msft = hdev->msft_data;
 244        u8 event;
 245
 246        if (!msft)
 247                return;
 248
 249        /* When the extension has defined an event prefix, check that it
 250         * matches, and otherwise just return.
 251         */
 252        if (msft->evt_prefix_len > 0) {
 253                if (skb->len < msft->evt_prefix_len)
 254                        return;
 255
 256                if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len))
 257                        return;
 258
 259                skb_pull(skb, msft->evt_prefix_len);
 260        }
 261
 262        /* Every event starts at least with an event code and the rest of
 263         * the data is variable and depends on the event code.
 264         */
 265        if (skb->len < 1)
 266                return;
 267
 268        event = *skb->data;
 269        skb_pull(skb, 1);
 270
 271        bt_dev_dbg(hdev, "MSFT vendor event %u", event);
 272}
 273
 274__u64 msft_get_features(struct hci_dev *hdev)
 275{
 276        struct msft_data *msft = hdev->msft_data;
 277
 278        return msft ? msft->features : 0;
 279}
 280
 281/* is_mgmt = true matches the handle exposed to userspace via mgmt.
 282 * is_mgmt = false matches the handle used by the msft controller.
 283 * This function requires the caller holds hdev->lock
 284 */
 285static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
 286                                (struct hci_dev *hdev, u16 handle, bool is_mgmt)
 287{
 288        struct msft_monitor_advertisement_handle_data *entry;
 289        struct msft_data *msft = hdev->msft_data;
 290
 291        list_for_each_entry(entry, &msft->handle_map, list) {
 292                if (is_mgmt && entry->mgmt_handle == handle)
 293                        return entry;
 294                if (!is_mgmt && entry->msft_handle == handle)
 295                        return entry;
 296        }
 297
 298        return NULL;
 299}
 300
 301static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,
 302                                             u8 status, u16 opcode,
 303                                             struct sk_buff *skb)
 304{
 305        struct msft_rp_le_monitor_advertisement *rp;
 306        struct adv_monitor *monitor;
 307        struct msft_monitor_advertisement_handle_data *handle_data;
 308        struct msft_data *msft = hdev->msft_data;
 309
 310        hci_dev_lock(hdev);
 311
 312        monitor = idr_find(&hdev->adv_monitors_idr, msft->pending_add_handle);
 313        if (!monitor) {
 314                bt_dev_err(hdev, "msft add advmon: monitor %u is not found!",
 315                           msft->pending_add_handle);
 316                status = HCI_ERROR_UNSPECIFIED;
 317                goto unlock;
 318        }
 319
 320        if (status)
 321                goto unlock;
 322
 323        rp = (struct msft_rp_le_monitor_advertisement *)skb->data;
 324        if (skb->len < sizeof(*rp)) {
 325                status = HCI_ERROR_UNSPECIFIED;
 326                goto unlock;
 327        }
 328
 329        handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL);
 330        if (!handle_data) {
 331                status = HCI_ERROR_UNSPECIFIED;
 332                goto unlock;
 333        }
 334
 335        handle_data->mgmt_handle = monitor->handle;
 336        handle_data->msft_handle = rp->handle;
 337        INIT_LIST_HEAD(&handle_data->list);
 338        list_add(&handle_data->list, &msft->handle_map);
 339
 340        monitor->state = ADV_MONITOR_STATE_OFFLOADED;
 341
 342unlock:
 343        if (status && monitor)
 344                hci_free_adv_monitor(hdev, monitor);
 345
 346        /* If in restart/reregister sequence, keep registering. */
 347        if (msft->reregistering)
 348                reregister_monitor_on_restart(hdev,
 349                                              msft->pending_add_handle + 1);
 350
 351        hci_dev_unlock(hdev);
 352
 353        if (!msft->reregistering)
 354                hci_add_adv_patterns_monitor_complete(hdev, status);
 355}
 356
 357static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
 358                                                    u8 status, u16 opcode,
 359                                                    struct sk_buff *skb)
 360{
 361        struct msft_cp_le_cancel_monitor_advertisement *cp;
 362        struct msft_rp_le_cancel_monitor_advertisement *rp;
 363        struct adv_monitor *monitor;
 364        struct msft_monitor_advertisement_handle_data *handle_data;
 365        struct msft_data *msft = hdev->msft_data;
 366        int err;
 367        bool pending;
 368
 369        if (status)
 370                goto done;
 371
 372        rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data;
 373        if (skb->len < sizeof(*rp)) {
 374                status = HCI_ERROR_UNSPECIFIED;
 375                goto done;
 376        }
 377
 378        hci_dev_lock(hdev);
 379
 380        cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
 381        handle_data = msft_find_handle_data(hdev, cp->handle, false);
 382
 383        if (handle_data) {
 384                monitor = idr_find(&hdev->adv_monitors_idr,
 385                                   handle_data->mgmt_handle);
 386                if (monitor)
 387                        hci_free_adv_monitor(hdev, monitor);
 388
 389                list_del(&handle_data->list);
 390                kfree(handle_data);
 391        }
 392
 393        /* If remove all monitors is required, we need to continue the process
 394         * here because the earlier it was paused when waiting for the
 395         * response from controller.
 396         */
 397        if (msft->pending_remove_handle == 0) {
 398                pending = hci_remove_all_adv_monitor(hdev, &err);
 399                if (pending) {
 400                        hci_dev_unlock(hdev);
 401                        return;
 402                }
 403
 404                if (err)
 405                        status = HCI_ERROR_UNSPECIFIED;
 406        }
 407
 408        hci_dev_unlock(hdev);
 409
 410done:
 411        hci_remove_adv_monitor_complete(hdev, status);
 412}
 413
 414static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
 415                                                       u8 status, u16 opcode,
 416                                                       struct sk_buff *skb)
 417{
 418        struct msft_cp_le_set_advertisement_filter_enable *cp;
 419        struct msft_rp_le_set_advertisement_filter_enable *rp;
 420        struct msft_data *msft = hdev->msft_data;
 421
 422        rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
 423        if (skb->len < sizeof(*rp))
 424                return;
 425
 426        /* Error 0x0C would be returned if the filter enabled status is
 427         * already set to whatever we were trying to set.
 428         * Although the default state should be disabled, some controller set
 429         * the initial value to enabled. Because there is no way to know the
 430         * actual initial value before sending this command, here we also treat
 431         * error 0x0C as success.
 432         */
 433        if (status != 0x00 && status != 0x0C)
 434                return;
 435
 436        hci_dev_lock(hdev);
 437
 438        cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
 439        msft->filter_enabled = cp->enable;
 440
 441        if (status == 0x0C)
 442                bt_dev_warn(hdev, "MSFT filter_enable is already %s",
 443                            cp->enable ? "on" : "off");
 444
 445        hci_dev_unlock(hdev);
 446}
 447
 448static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 449{
 450        struct adv_rssi_thresholds *r = &monitor->rssi;
 451
 452        if (r->high_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
 453            r->high_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX ||
 454            r->low_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
 455            r->low_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX)
 456                return false;
 457
 458        /* High_threshold_timeout is not supported,
 459         * once high_threshold is reached, events are immediately reported.
 460         */
 461        if (r->high_threshold_timeout != 0)
 462                return false;
 463
 464        if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX)
 465                return false;
 466
 467        /* Sampling period from 0x00 to 0xFF are all allowed */
 468        return true;
 469}
 470
 471static bool msft_monitor_pattern_valid(struct adv_monitor *monitor)
 472{
 473        return msft_monitor_rssi_valid(monitor);
 474        /* No additional check needed for pattern-based monitor */
 475}
 476
 477/* This function requires the caller holds hdev->lock */
 478static int __msft_add_monitor_pattern(struct hci_dev *hdev,
 479                                      struct adv_monitor *monitor)
 480{
 481        struct msft_cp_le_monitor_advertisement *cp;
 482        struct msft_le_monitor_advertisement_pattern_data *pattern_data;
 483        struct msft_le_monitor_advertisement_pattern *pattern;
 484        struct adv_pattern *entry;
 485        struct hci_request req;
 486        struct msft_data *msft = hdev->msft_data;
 487        size_t total_size = sizeof(*cp) + sizeof(*pattern_data);
 488        ptrdiff_t offset = 0;
 489        u8 pattern_count = 0;
 490        int err = 0;
 491
 492        if (!msft_monitor_pattern_valid(monitor))
 493                return -EINVAL;
 494
 495        list_for_each_entry(entry, &monitor->patterns, list) {
 496                pattern_count++;
 497                total_size += sizeof(*pattern) + entry->length;
 498        }
 499
 500        cp = kmalloc(total_size, GFP_KERNEL);
 501        if (!cp)
 502                return -ENOMEM;
 503
 504        cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
 505        cp->rssi_high = monitor->rssi.high_threshold;
 506        cp->rssi_low = monitor->rssi.low_threshold;
 507        cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout;
 508        cp->rssi_sampling_period = monitor->rssi.sampling_period;
 509
 510        cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
 511
 512        pattern_data = (void *)cp->data;
 513        pattern_data->count = pattern_count;
 514
 515        list_for_each_entry(entry, &monitor->patterns, list) {
 516                pattern = (void *)(pattern_data->data + offset);
 517                /* the length also includes data_type and offset */
 518                pattern->length = entry->length + 2;
 519                pattern->data_type = entry->ad_type;
 520                pattern->start_byte = entry->offset;
 521                memcpy(pattern->pattern, entry->value, entry->length);
 522                offset += sizeof(*pattern) + entry->length;
 523        }
 524
 525        hci_req_init(&req, hdev);
 526        hci_req_add(&req, hdev->msft_opcode, total_size, cp);
 527        err = hci_req_run_skb(&req, msft_le_monitor_advertisement_cb);
 528        kfree(cp);
 529
 530        if (!err)
 531                msft->pending_add_handle = monitor->handle;
 532
 533        return err;
 534}
 535
 536/* This function requires the caller holds hdev->lock */
 537int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
 538{
 539        struct msft_data *msft = hdev->msft_data;
 540
 541        if (!msft)
 542                return -EOPNOTSUPP;
 543
 544        if (msft->reregistering)
 545                return -EBUSY;
 546
 547        return __msft_add_monitor_pattern(hdev, monitor);
 548}
 549
 550/* This function requires the caller holds hdev->lock */
 551int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
 552                        u16 handle)
 553{
 554        struct msft_cp_le_cancel_monitor_advertisement cp;
 555        struct msft_monitor_advertisement_handle_data *handle_data;
 556        struct hci_request req;
 557        struct msft_data *msft = hdev->msft_data;
 558        int err = 0;
 559
 560        if (!msft)
 561                return -EOPNOTSUPP;
 562
 563        if (msft->reregistering)
 564                return -EBUSY;
 565
 566        handle_data = msft_find_handle_data(hdev, monitor->handle, true);
 567
 568        /* If no matched handle, just remove without telling controller */
 569        if (!handle_data)
 570                return -ENOENT;
 571
 572        cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
 573        cp.handle = handle_data->msft_handle;
 574
 575        hci_req_init(&req, hdev);
 576        hci_req_add(&req, hdev->msft_opcode, sizeof(cp), &cp);
 577        err = hci_req_run_skb(&req, msft_le_cancel_monitor_advertisement_cb);
 578
 579        if (!err)
 580                msft->pending_remove_handle = handle;
 581
 582        return err;
 583}
 584
 585void msft_req_add_set_filter_enable(struct hci_request *req, bool enable)
 586{
 587        struct hci_dev *hdev = req->hdev;
 588        struct msft_cp_le_set_advertisement_filter_enable cp;
 589
 590        cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
 591        cp.enable = enable;
 592
 593        hci_req_add(req, hdev->msft_opcode, sizeof(cp), &cp);
 594}
 595
 596int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
 597{
 598        struct hci_request req;
 599        struct msft_data *msft = hdev->msft_data;
 600        int err;
 601
 602        if (!msft)
 603                return -EOPNOTSUPP;
 604
 605        hci_req_init(&req, hdev);
 606        msft_req_add_set_filter_enable(&req, enable);
 607        err = hci_req_run_skb(&req, msft_le_set_advertisement_filter_enable_cb);
 608
 609        return err;
 610}
 611
 612bool msft_curve_validity(struct hci_dev *hdev)
 613{
 614        return hdev->msft_curve_validity;
 615}
 616