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