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 "os/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 extern int GetAdapterIndex();
34
35 namespace bluetooth {
36 namespace os {
37
38 #define RETRY_ON_INTR(fn) \
39 do { \
40 } while ((fn) == -1 && errno == EINTR)
41
42 struct sockaddr_hci {
43 sa_family_t hci_family;
44 uint16_t hci_dev;
45 uint16_t hci_channel;
46 };
47
48 constexpr static uint8_t BTPROTO_HCI = 1;
49 constexpr static uint16_t HCI_CHANNEL_CONTROL = 3;
50 constexpr static uint16_t HCI_DEV_NONE = 0xffff;
51
btsocket_open_mgmt()52 static int btsocket_open_mgmt() {
53 int fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_HCI);
54 if (fd < 0) {
55 log::error("Failed to open BT socket.");
56 return -errno;
57 }
58
59 struct sockaddr_hci addr = {
60 .hci_family = AF_BLUETOOTH,
61 .hci_dev = HCI_DEV_NONE,
62 .hci_channel = HCI_CHANNEL_CONTROL,
63 };
64
65 int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
66 if (ret < 0) {
67 log::error("Failed to bind BT socket.");
68 close(fd);
69 return -errno;
70 }
71
72 return fd;
73 }
74
75 /*
76 * Given a vendor specification, e.g., MSFT extension, this function returns
77 * the vendor specific opcode.
78 *
79 * If the controller does not support MSFT extension or there are errors
80 * or failures in writing/reading the MGMT socket, the return opcode would
81 * be HCI_OP_NOP (0x0000).
82 */
getVendorSpecificCode(uint16_t vendor_specification)83 uint16_t Management::getVendorSpecificCode(uint16_t vendor_specification) {
84 int hci = GetAdapterIndex();
85 int fd = btsocket_open_mgmt();
86 uint16_t ret_opcode = HCI_OP_NOP;
87
88 if (fd < 0) {
89 log::error("Failed to open mgmt channel for hci {}, error= {}.", hci, fd);
90 return ret_opcode;
91 }
92
93 struct mgmt_pkt ev;
94 ev.opcode = MGMT_OP_GET_VS_OPCODE;
95 ev.index = HCI_DEV_NONE;
96 ev.len = sizeof(struct mgmt_cp_get_vs_opcode);
97
98 struct mgmt_cp_get_vs_opcode* cp = reinterpret_cast<struct mgmt_cp_get_vs_opcode*>(ev.data);
99 cp->hci_id = hci;
100 cp->vendor_specification = vendor_specification;
101
102 int ret;
103 struct pollfd writable[1];
104 writable[0].fd = fd;
105 writable[0].events = POLLOUT;
106
107 do {
108 ret = poll(writable, 1, MGMT_POLL_TIMEOUT_MS);
109 if (ret > 0) {
110 RETRY_ON_INTR(ret = write(fd, &ev, MGMT_PKT_HDR_SIZE + ev.len));
111 if (ret < 0) {
112 log::error("Failed to call MGMT opcode 0x{:04x}, errno {}", ev.opcode, -errno);
113 close(fd);
114 return ret_opcode;
115 }
116 break;
117 } else if (ret < 0) {
118 log::error("msft poll ret {} errno {}", ret, -errno);
119 }
120 } while (ret > 0);
121
122 if (ret <= 0) {
123 log::info("Skip because mgmt socket is not writable: ev.opcode 0x{:04x} ret {}", ev.opcode,
124 ret);
125 close(fd);
126 return ret_opcode;
127 }
128
129 struct pollfd fds[1];
130 struct mgmt_pkt cc_ev;
131 fds[0].fd = fd;
132 fds[0].events = POLLIN;
133
134 do {
135 ret = poll(fds, 1, MGMT_POLL_TIMEOUT_MS);
136 if (ret > 0) {
137 if (fds[0].revents & POLLIN) {
138 RETRY_ON_INTR(ret = read(fd, &cc_ev, sizeof(cc_ev)));
139 if (ret < 0) {
140 log::error("Failed to read mgmt socket: {}", -errno);
141 close(fd);
142 return ret_opcode;
143 } else if (ret == 0) { // unlikely to happen, just a safeguard.
144 log::error("Failed to read mgmt socket: EOF");
145 close(fd);
146 return ret_opcode;
147 }
148
149 if (cc_ev.opcode == MGMT_EV_COMMAND_COMPLETE) {
150 struct mgmt_ev_cmd_complete* cc =
151 reinterpret_cast<struct mgmt_ev_cmd_complete*>(cc_ev.data);
152 if (cc->opcode == ev.opcode && cc->status == 0) {
153 struct mgmt_rp_get_vs_opcode* rp =
154 reinterpret_cast<struct mgmt_rp_get_vs_opcode*>(cc->data);
155 if (rp->hci_id == hci) {
156 // If the controller supports the MSFT extension, the returned opcode
157 // will not be HCI_OP_NOP.
158 if (rp->opcode != HCI_OP_NOP) {
159 ret_opcode = rp->opcode;
160 }
161 close(fd);
162 return ret_opcode;
163 }
164 }
165 }
166 }
167 } else if (ret == 0) {
168 log::error("Timeout while waiting for response of calling MGMT opcode: 0x{:04x}", ev.opcode);
169 ret = -1;
170 }
171 } while (ret > 0);
172 close(fd);
173 return ret_opcode;
174 }
175
176 } // namespace os
177 } // namespace bluetooth
178