1 /******************************************************************************
2 *
3 * Copyright 2022 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /*
20 * TODO(b/249193511): Replace this MGMT interface with sockopt/ioctl.
21 * This file will be replaced such that it is not optimized for now.
22 */
23
24 #include "hal/mgmt.h"
25
26 #include <bluetooth/log.h>
27 #include <poll.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30
31 #include <cerrno>
32
33 #include "common/init_flags.h"
34 #include "os/log.h"
35
36 namespace bluetooth {
37 namespace hal {
38
39 #define RETRY_ON_INTR(fn) \
40 do { \
41 } while ((fn) == -1 && errno == EINTR)
42
43 struct sockaddr_hci {
44 sa_family_t hci_family;
45 unsigned short hci_dev;
46 unsigned short hci_channel;
47 };
48
49 constexpr static uint8_t BTPROTO_HCI = 1;
50 constexpr static uint16_t HCI_CHANNEL_CONTROL = 3;
51 constexpr static uint16_t HCI_DEV_NONE = 0xffff;
52
btsocket_open_mgmt(uint16_t hci)53 static int btsocket_open_mgmt(uint16_t hci) {
54 int fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_HCI);
55 if (fd < 0) {
56 log::error("Failed to open BT socket.");
57 return -errno;
58 }
59
60 struct sockaddr_hci addr = {
61 .hci_family = AF_BLUETOOTH,
62 .hci_dev = HCI_DEV_NONE,
63 .hci_channel = HCI_CHANNEL_CONTROL,
64 };
65
66 int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
67 if (ret < 0) {
68 log::error("Failed to bind BT socket.");
69 close(fd);
70 return -errno;
71 }
72
73 return fd;
74 }
75
76 /*
77 * Given a vendor specification, e.g., MSFT extension, this function returns
78 * the vendor specific opcode.
79 *
80 * If the controller does not support MSFT extension or there are errors
81 * or failures in writing/reading the MGMT socket, the return opcode would
82 * be HCI_OP_NOP (0x0000).
83 */
get_vs_opcode(uint16_t vendor_specification)84 uint16_t Mgmt::get_vs_opcode(uint16_t vendor_specification) {
85 int hci = bluetooth::common::InitFlags::GetAdapterIndex();
86 int fd = btsocket_open_mgmt(hci);
87 uint16_t ret_opcode = HCI_OP_NOP;
88
89 if (fd < 0) {
90 log::error("Failed to open mgmt channel for hci {}, error= {}.", hci, fd);
91 return ret_opcode;
92 }
93
94 struct mgmt_pkt ev;
95 ev.opcode = MGMT_OP_GET_VS_OPCODE;
96 ev.index = HCI_DEV_NONE;
97 ev.len = sizeof(struct mgmt_cp_get_vs_opcode);
98
99 struct mgmt_cp_get_vs_opcode* cp = reinterpret_cast<struct mgmt_cp_get_vs_opcode*>(ev.data);
100 cp->hci_id = hci;
101 cp->vendor_specification = MGMT_VS_OPCODE_MSFT;
102
103 int ret;
104 struct pollfd writable[1];
105 writable[0].fd = fd;
106 writable[0].events = POLLOUT;
107
108 do {
109 ret = poll(writable, 1, MGMT_POLL_TIMEOUT_MS);
110 if (ret > 0) {
111 RETRY_ON_INTR(ret = write(fd, &ev, MGMT_PKT_HDR_SIZE + ev.len));
112 if (ret < 0) {
113 log::error("Failed to call MGMT opcode 0x{:04x}, errno {}", ev.opcode, -errno);
114 close(fd);
115 return ret_opcode;
116 };
117 break;
118 } else if (ret < 0) {
119 log::error("msft poll ret {} errno {}", ret, -errno);
120 }
121 } while (ret > 0);
122
123 if (ret <= 0) {
124 log::info(
125 "Skip because mgmt socket is not writable: ev.opcode 0x{:04x} ret {}", ev.opcode, ret);
126 close(fd);
127 return ret_opcode;
128 }
129
130 struct pollfd fds[1];
131 struct mgmt_pkt cc_ev;
132 fds[0].fd = fd;
133 fds[0].events = POLLIN;
134
135 do {
136 ret = poll(fds, 1, MGMT_POLL_TIMEOUT_MS);
137 if (ret > 0) {
138 if (fds[0].revents & POLLIN) {
139 RETRY_ON_INTR(ret = read(fd, &cc_ev, sizeof(cc_ev)));
140 if (ret < 0) {
141 log::error("Failed to read mgmt socket: {}", -errno);
142 close(fd);
143 return ret_opcode;
144 }
145
146 if (cc_ev.opcode == MGMT_EV_COMMAND_COMPLETE) {
147 struct mgmt_ev_cmd_complete* cc = reinterpret_cast<struct mgmt_ev_cmd_complete*>(cc_ev.data);
148 if (cc->opcode == ev.opcode && cc->status == 0) {
149 struct mgmt_rp_get_vs_opcode* rp = reinterpret_cast<struct mgmt_rp_get_vs_opcode*>(cc->data);
150 if (rp->hci_id == hci) {
151 // If the controller supports the MSFT extension, the returned opcode
152 // will not be HCI_OP_NOP.
153 if (rp->opcode != HCI_OP_NOP) {
154 ret_opcode = rp->opcode;
155 }
156 close(fd);
157 return ret_opcode;
158 }
159 }
160 }
161 }
162 } else if (ret == 0) {
163 log::error("Timeout while waiting for response of calling MGMT opcode: 0x{:04x}", ev.opcode);
164 ret = -1;
165 }
166 } while (ret > 0);
167 close(fd);
168 return ret_opcode;
169 }
170
171 } // namespace hal
172 } // namespace bluetooth
173