/* * Copyright (C) 2022 The Android Open Source Project * Copyright (C) 2024 KonstaKANG * * 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. */ #define LOG_TAG "android.hardware.bluetooth.service.rpi" #include "net_bluetooth_mgmt.h" #include #include #include #include #include #include #include #include #include // Definitions imported from #define BTPROTO_HCI 1 // Definitions imported from #define HCI_CHANNEL_USER 1 #define HCI_CHANNEL_CONTROL 3 #define HCI_DEV_NONE 0xffff struct sockaddr_hci { sa_family_t hci_family; unsigned short hci_dev; unsigned short hci_channel; }; // Definitions imported from #define MGMT_OP_READ_INDEX_LIST 0x0003 #define MGMT_EV_INDEX_ADDED 0x0004 #define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_PKT_SIZE_MAX 1024 #define MGMT_INDEX_NONE 0xFFFF #define WRITE_NO_INTR(fn) \ do { \ } while ((fn) == -1 && errno == EINTR) struct mgmt_pkt { uint16_t opcode; uint16_t index; uint16_t len; uint8_t data[MGMT_PKT_SIZE_MAX]; } __attribute__((packed)); struct mgmt_ev_read_index_list { uint16_t opcode; uint8_t status; uint16_t num_controllers; uint16_t index[]; } __attribute__((packed)); namespace aidl::android::hardware::bluetooth::impl { // Wait indefinitely for the selected HCI interface to be enabled in the // bluetooth driver. int NetBluetoothMgmt::waitHciDev(int hci_interface) { ALOGI("waiting for hci interface %d", hci_interface); int ret = -1; struct mgmt_pkt cmd; struct pollfd pollfd; struct sockaddr_hci hci_addr = { .hci_family = AF_BLUETOOTH, .hci_dev = HCI_DEV_NONE, .hci_channel = HCI_CHANNEL_CONTROL, }; // Open and bind a socket to the bluetooth control interface in the // kernel driver, used to send control commands and receive control // events. int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (fd < 0) { ALOGE("unable to open raw bluetooth socket: %s", strerror(errno)); return -1; } if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) { ALOGE("unable to bind bluetooth control channel: %s", strerror(errno)); goto end; } // Send the control command [Read Index List]. cmd = { .opcode = MGMT_OP_READ_INDEX_LIST, .index = MGMT_INDEX_NONE, .len = 0, }; if (write(fd, &cmd, 6) != 6) { ALOGE("error writing mgmt command: %s", strerror(errno)); goto end; } // Poll the control socket waiting for the command response, // and subsequent [Index Added] events. The loops continue without // timeout until the selected hci interface is detected. pollfd = {.fd = fd, .events = POLLIN}; for (;;) { ret = poll(&pollfd, 1, -1); // Poll interrupted, try again. if (ret == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } // Poll failure, abandon. if (ret == -1) { ALOGE("poll error: %s", strerror(errno)); break; } // Spurious wakeup, try again. if (ret == 0 || (pollfd.revents & POLLIN) == 0) { continue; } // Read the next control event. struct mgmt_pkt ev {}; ret = read(fd, &ev, sizeof(ev)); if (ret < 0) { ALOGE("error reading mgmt event: %s", strerror(errno)); goto end; } // Received [Read Index List] command response. if (ev.opcode == MGMT_EV_CMD_COMPLETE) { struct mgmt_ev_read_index_list* data = (struct mgmt_ev_read_index_list*)ev.data; // Prefer the exact hci_interface for (int i = 0; i < data->num_controllers; i++) { if (data->index[i] == hci_interface) { ALOGI("hci interface %d found", data->index[i]); ret = data->index[i]; goto end; } } // Accept a larger one if we can't find the exact one for (int i = 0; i < data->num_controllers; i++) { if (data->index[i] >= hci_interface) { ALOGI("hci interface %d found", data->index[i]); ret = data->index[i]; goto end; } } } // Received [Index Added] event. if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) { ALOGI("hci interface %d added", hci_interface); ret = hci_interface; goto end; } } end: ::close(fd); return ret; } int NetBluetoothMgmt::findRfKill() { char rfkill_type[64]; char type[16]; int fd, size, i; for(i = 0; rfkill_state_ == NULL; i++) { snprintf(rfkill_type, sizeof(rfkill_type), "/sys/class/rfkill/rfkill%d/type", i); if ((fd = open(rfkill_type, O_RDONLY)) < 0) { ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno); return -1; } size = read(fd, &type, sizeof(type)); ::close(fd); if ((size >= 9) && !memcmp(type, "bluetooth", 9)) { ::asprintf(&rfkill_state_, "/sys/class/rfkill/rfkill%d/state", i); break; } } return 0; } int NetBluetoothMgmt::rfKill(int block) { int fd; char on = (block)?'1':'0'; if (findRfKill() != 0) return 0; fd = open(rfkill_state_, O_WRONLY); if (fd < 0) { ALOGE( "Unable to open /dev/rfkill"); return -1; } ssize_t len; WRITE_NO_INTR(len = write(fd, &on, 1)); if (len < 0) { ALOGE( "Failed to change rfkill state"); ::close(fd); return -1; } ::close(fd); return 0; } int NetBluetoothMgmt::openHci(int hci_interface) { ALOGI("opening hci interface %d", hci_interface); // Block Bluetooth. rfkill_state_ = NULL; rfKill(1); // Wait for the HCI interface to complete initialization or to come online. int hci = waitHciDev(hci_interface); if (hci < 0) { ALOGE("hci interface %d not found", hci_interface); return -1; } // Open the raw HCI socket. int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (fd < 0) { ALOGE("unable to open raw bluetooth socket: %s", strerror(errno)); return -1; } struct sockaddr_hci hci_addr = { .hci_family = AF_BLUETOOTH, .hci_dev = static_cast(hci), .hci_channel = HCI_CHANNEL_USER, }; // Bind the socket to the selected interface. if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) { ALOGE("unable to bind bluetooth user channel: %s", strerror(errno)); ::close(fd); return -1; } ALOGI("hci interface %d ready", hci); bt_fd_ = fd; return fd; } void NetBluetoothMgmt::closeHci() { if (bt_fd_ != -1) { ::close(bt_fd_); bt_fd_ = -1; } // Unblock Bluetooth. rfKill(0); free(rfkill_state_); } } // namespace aidl::android::hardware::bluetooth::impl