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

Commit 33233f0c authored by Myles Watson's avatar Myles Watson Committed by Gerrit Code Review
Browse files

Merge changes from topic "msft_module"

* changes:
  floss: shim/stack: add MsftExtensionManager
  gd/hci: add a msft module to handle Microsoft Extension
  gd/hal: add getMsftOpcode to hci_hal_host
  gd/hal: use the MGMT socket to interface with kernel
parents 287965ab be3cea62
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -22,7 +22,10 @@ source_set("BluetoothHalSources") {
}

source_set("BluetoothHalSources_hci_host") {
  sources = [ "hci_hal_host.cc" ]
  sources = [
    "hci_hal_host.cc",
    "mgmt.cc",
  ]

  configs += [ "//bt/system/gd:gd_defaults" ]
  deps = [ "//bt/system/gd:gd_default_deps" ]
+6 −0
Original line number Diff line number Diff line
@@ -97,6 +97,12 @@ class HciHal : public ::bluetooth::Module {
  // V5.2, Vol 4, Part E, Section 5.4.5) to the Bluetooth controller.
  // Packets must be processed in order.
  virtual void sendIsoData(HciPacket data) = 0;

  // Get the MSFT opcode (as specified in Microsoft-defined Bluetooth HCI
  // extensions)
  virtual uint16_t getMsftOpcode() {
    return 0;
  }
};
// LINT.ThenChange(fuzz/fuzz_hci_hal.h)

+5 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include "gd/common/init_flags.h"
#include "hal/hci_hal.h"
#include "hal/mgmt.h"
#include "hal/snoop_logger.h"
#include "metrics/counter_metrics.h"
#include "os/log.h"
@@ -266,6 +267,10 @@ class HciHalHost : public HciHal {
    write_to_fd(packet);
  }

  uint16_t getMsftOpcode() override {
    return Mgmt().get_vs_opcode(MGMT_VS_OPCODE_MSFT);
  }

 protected:
  void ListDependencies(ModuleList* list) const {
    list->add<metrics::CounterMetrics>();

system/gd/hal/mgmt.cc

0 → 100644
+169 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2022 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/*
 * TODO(b/249193511): Replace this MGMT interface with sockopt/ioctl.
 * This file will be replaced such that it is not optimized for now.
 */

#include "hal/mgmt.h"

#include <errno.h>
#include <poll.h>
#include <sys/socket.h>
#include <unistd.h>

#include "common/init_flags.h"
#include "os/log.h"

namespace bluetooth {
namespace hal {

#define RETRY_ON_INTR(fn) \
  do {                    \
  } while ((fn) == -1 && errno == EINTR)

struct sockaddr_hci {
  sa_family_t hci_family;
  unsigned short hci_dev;
  unsigned short hci_channel;
};

constexpr static uint8_t BTPROTO_HCI = 1;
constexpr static uint16_t HCI_CHANNEL_CONTROL = 3;
constexpr static uint16_t HCI_DEV_NONE = 0xffff;

static int btsocket_open_mgmt(uint16_t hci) {
  int fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_HCI);
  if (fd < 0) {
    LOG_ERROR("Failed to open BT socket.");
    return -errno;
  }

  struct sockaddr_hci addr = {
      .hci_family = AF_BLUETOOTH,
      .hci_dev = HCI_DEV_NONE,
      .hci_channel = HCI_CHANNEL_CONTROL,
  };

  int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
  if (ret < 0) {
    LOG_ERROR("Failed to bind BT socket.");
    close(fd);
    return -errno;
  }

  return fd;
}

/*
 * Given a vendor specification, e.g., MSFT extension, this function returns
 * the vendor specific opcode.
 *
 * If the controller does not support MSFT extension or there are errors
 * or failures in writing/reading the MGMT socket, the return opcode would
 * be HCI_OP_NOP (0x0000).
 */
uint16_t Mgmt::get_vs_opcode(uint16_t vendor_specification) {
  int hci = bluetooth::common::InitFlags::GetAdapterIndex();
  int fd = btsocket_open_mgmt(hci);
  uint16_t ret_opcode = HCI_OP_NOP;

  if (fd < 0) {
    LOG_ERROR("Failed to open mgmt channel for hci %d, error= %d.", hci, fd);
    return ret_opcode;
  }

  struct mgmt_pkt ev;
  ev.opcode = MGMT_OP_GET_VS_OPCODE;
  ev.index = HCI_DEV_NONE;
  ev.len = sizeof(struct mgmt_cp_get_vs_opcode);

  struct mgmt_cp_get_vs_opcode* cp = reinterpret_cast<struct mgmt_cp_get_vs_opcode*>(ev.data);
  cp->hci_id = hci;
  cp->vendor_specification = MGMT_VS_OPCODE_MSFT;

  int ret;
  struct pollfd writable[1];
  writable[0].fd = fd;
  writable[0].events = POLLOUT;

  do {
    ret = poll(writable, 1, MGMT_POLL_TIMEOUT_MS);
    if (ret > 0) {
      RETRY_ON_INTR(ret = write(fd, &ev, MGMT_PKT_HDR_SIZE + ev.len));
      if (ret < 0) {
        LOG_ERROR("Failed to call MGMT opcode 0x%4.4x, errno %d", ev.opcode, -errno);
        close(fd);
        return ret_opcode;
      };
      break;
    } else if (ret < 0) {
      LOG_ERROR("msft poll ret %d errno %d", ret, -errno);
    }
  } while (ret > 0);

  if (ret <= 0) {
    LOG_INFO("Skip because mgmt socket is not writable: ev.opcode 0x%4.4x ret %d", ev.opcode, ret);
    close(fd);
    return ret_opcode;
  }

  struct pollfd fds[1];
  struct mgmt_pkt cc_ev;
  fds[0].fd = fd;
  fds[0].events = POLLIN;

  do {
    ret = poll(fds, 1, MGMT_POLL_TIMEOUT_MS);
    if (ret > 0) {
      if (fds[0].revents & POLLIN) {
        RETRY_ON_INTR(ret = read(fd, &cc_ev, sizeof(cc_ev)));
        if (ret < 0) {
          LOG_ERROR("Failed to read mgmt socket: %d", -errno);
          close(fd);
          return ret_opcode;
        }

        if (cc_ev.opcode == MGMT_EV_COMMAND_COMPLETE) {
          struct mgmt_ev_cmd_complete* cc = reinterpret_cast<struct mgmt_ev_cmd_complete*>(cc_ev.data);
          if (cc->opcode == ev.opcode && cc->status == 0) {
            struct mgmt_rp_get_vs_opcode* rp = reinterpret_cast<struct mgmt_rp_get_vs_opcode*>(cc->data);
            if (rp->hci_id == hci) {
              // If the controller supports the MSFT extension, the returned opcode
              // will not be HCI_OP_NOP.
              if (rp->opcode != HCI_OP_NOP) {
                ret_opcode = rp->opcode;
              }
              close(fd);
              return ret_opcode;
            }
          }
        }
      }
    } else if (ret == 0) {
      LOG_ERROR("Timeout while waiting for response of calling MGMT opcode: 0x%4.4x", ev.opcode);
      ret = -1;
    }
  } while (ret > 0);
  close(fd);
  return ret_opcode;
}

}  // namespace hal
}  // namespace bluetooth

system/gd/hal/mgmt.h

0 → 100644
+65 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright (C) 2022 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#pragma once

#include <inttypes.h>

namespace bluetooth {
namespace hal {

#define HCI_OP_NOP 0x0000

#define MGMT_EV_SIZE_MAX 1024
#define MGMT_PKT_HDR_SIZE 6
struct mgmt_pkt {
  uint16_t opcode;
  uint16_t index;
  uint16_t len;
  uint8_t data[MGMT_EV_SIZE_MAX];
} __attribute__((packed));

#define MGMT_EV_COMMAND_COMPLETE 0x1
struct mgmt_ev_cmd_complete {
  uint16_t opcode;
  uint8_t status;
  uint8_t data[];
} __attribute__((packed));

#define MGMT_OP_GET_VS_OPCODE 0x0059
#define MGMT_VS_OPCODE_MSFT 0x0001
struct mgmt_cp_get_vs_opcode {
  uint16_t hci_id;
  uint16_t vendor_specification;
} __attribute__((packed));

struct mgmt_rp_get_vs_opcode {
  uint16_t hci_id;
  uint16_t opcode;
} __attribute__((packed));

#define MGMT_POLL_TIMEOUT_MS 2000

// This class provides an interface to interact with the kernel.
class Mgmt {
 public:
  uint16_t get_vs_opcode(uint16_t vendor_specification);
};

}  // namespace hal
}  // namespace bluetooth
Loading