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