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