blob: 7e35d4cd8daf20664e9920feece3947b7ca01fbe [file] [log] [blame]
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "guest/usbforward/usb_server.h"
18
19#include <string>
20#include <vector>
21#include <strings.h>
22#include <cutils/log.h>
23#include <libusb/libusb.h>
24#include "common/libs/fs/shared_select.h"
25#include "guest/usbforward/protocol.h"
26
27namespace {
28void GetDeviceInfo(libusb_device* dev, DeviceInfo* info,
29 std::vector<InterfaceInfo>* ifaces) {
30 libusb_device_descriptor desc;
31 libusb_config_descriptor* conf;
32
33 memset(info, 0, sizeof(*info));
34
35 int res = libusb_get_device_descriptor(dev, &desc);
36 if (res < 0) {
37 // This shouldn't really happen.
38 ALOGE("libusb_get_device_descriptor failed %d", res);
39 return;
40 }
41
42 res = libusb_get_active_config_descriptor(dev, &conf);
43 if (res < 0) {
44 // This shouldn't really happen.
45 ALOGE("libusb_get_active_config_descriptor failed %d", res);
46 libusb_free_config_descriptor(conf);
47 return;
48 }
49
50 info->vendor_id = desc.idVendor;
51 info->product_id = desc.idProduct;
52 info->dev_version = desc.bcdDevice;
53 info->dev_class = desc.bDeviceClass;
54 info->dev_subclass = desc.bDeviceSubClass;
55 info->dev_protocol = desc.bDeviceProtocol;
56 info->speed = libusb_get_device_speed(dev);
57 info->num_configurations = desc.bNumConfigurations;
58 info->num_interfaces = conf->bNumInterfaces;
59 info->cur_configuration = conf->bConfigurationValue;
60 info->bus_id = libusb_get_bus_number(dev);
61 info->dev_id = libusb_get_device_address(dev);
62
63 if (ifaces != nullptr) {
64 for (int ifidx = 0; ifidx < conf->bNumInterfaces; ++ifidx) {
65 const libusb_interface& iface = conf->interface[ifidx];
66 for (int altidx = 0; altidx < iface.num_altsetting; ++altidx) {
67 const libusb_interface_descriptor& alt = iface.altsetting[altidx];
68 ifaces->push_back(InterfaceInfo{alt.bInterfaceClass,
69 alt.bInterfaceSubClass,
70 alt.bInterfaceProtocol, 0});
71 }
72 }
73 }
74 libusb_free_config_descriptor(conf);
75}
76
77uint16_t MakeDeviceKey(uint8_t bus_id, uint8_t dev_id) {
78 return bus_id << 8 | dev_id;
79}
80} // anonymous namespace
81
82USBServer::~USBServer() {
83 for (const auto& dev : attached_devices_) {
84 libusb_close(dev.second);
85 }
86
87 for (const auto& dev : devices_) {
88 libusb_unref_device(dev.second);
89 }
90}
91
92bool USBServer::Init() {
93 auto res = libusb_init(nullptr);
94 if (res < 0) {
95 // res is LIBUSB_ERROR in this context.
96 ALOGE("libusb_init failed %d", res);
97 return false;
98 }
99
100 libusb_device** devices;
101 int32_t cnt = libusb_get_device_list(nullptr, &devices);
102 if (cnt <= 0) {
103 ALOGE("libusb_get_device_list failed %d", cnt);
104 return false;
105 }
106
107 for (int index = 0; index < cnt; index++) {
108 auto key = MakeDeviceKey(libusb_get_bus_number(devices[index]),
109 libusb_get_device_address(devices[index]));
110
111 libusb_ref_device(devices[index]);
112 devices_[key] = devices[index];
113 }
114
115 return true;
116}
117
118void USBServer::HandleDeviceList() {
119 // Iterate all devices and send structure for every found device.
120 DeviceInfo info;
121 int32_t size = devices_.size();
122
123 // Write header: number of devices.
124 fd_->Write(&size, sizeof(size));
125
126 for (const auto& dev : devices_) {
127 std::vector<InterfaceInfo> ifaces;
128 GetDeviceInfo(dev.second, &info, &ifaces);
129 fd_->Write(&info, sizeof(info));
130 fd_->Write(ifaces.data(), ifaces.size() * sizeof(InterfaceInfo));
131 }
132}
133
134void USBServer::HandleAttach() {
135 AttachRequest req;
136 // If disconnected prematurely, don't send response.
137 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
138 // To simplify our lives, let's use status similar to USB/IP.
139 int32_t status = 1;
140
141 // Force nul-terminate path.
142 const auto key = MakeDeviceKey(req.bus_id, req.dev_id);
143 auto iter = devices_.find(key);
144 if (iter == devices_.end()) {
145 ALOGE("No device found for %x-%x", req.bus_id, req.dev_id);
146 fd_->Write(&status, sizeof(status));
147 return;
148 }
149
150 libusb_device_handle* handle;
151 auto res = libusb_open(iter->second, &handle);
152 if (res < 0) {
153 ALOGE("libusb_open failed %d", res);
154 fd_->Write(&status, sizeof(status));
155 return;
156 }
157
158 if (handle) attached_devices_[key] = handle;
159 // Indicate failure if we don't have the handle.
160 status = (handle == nullptr);
161 fd_->Write(&status, sizeof(status));
162}
163
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700164void USBServer::HandleControlTransfer() {
165 ControlTransfer req;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700166 // If disconnected prematurely, don't send response.
167 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
168
169 std::vector<uint8_t> data;
170 data.resize(req.length);
171
172 bool req_out = ((req.type & 0x80) == 0);
173
174 if (req_out && req.length) {
175 // If disconnected prematurely, don't send response.
176 if (fd_->Read(data.data(), req.length) != req.length) return;
177 }
178
179 int32_t status = 1;
180 int32_t len = 0;
181 auto handle_iter =
182 attached_devices_.find(MakeDeviceKey(req.bus_id, req.dev_id));
183
184 if (handle_iter != attached_devices_.end()) {
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700185 // Now that we read the whole request and we have a previously attached
186 // device, execute control transfer.
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700187 len = libusb_control_transfer(handle_iter->second, req.type, req.cmd,
188 req.value, req.index, data.data(), req.length,
189 req.timeout);
190
191 status = (len < 0);
192 if (status) {
193 ALOGE("USB request failed %d", len);
194 }
195 }
196
197 fd_->Write(&status, sizeof(status));
198
199 if (!status && !req_out) {
200 fd_->Write(&len, sizeof(len));
201 if (len > 0) {
202 fd_->Write(data.data(), len);
203 }
204 }
205}
206
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700207void USBServer::HandleDataTransfer() {
208 DataTransfer req;
209 // If disconnected prematurely, don't send response.
210 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
211
212 std::vector<uint8_t> data;
213 data.resize(req.length);
214
215 if (req.is_host_to_device && req.length) {
216 // If disconnected prematurely, don't send response.
217 if (fd_->Read(data.data(), req.length) != req.length) return;
218 }
219
220 int32_t status = 1;
221 int32_t len = 0;
222 auto handle_iter =
223 attached_devices_.find(MakeDeviceKey(req.bus_id, req.dev_id));
224
225 if (handle_iter != attached_devices_.end()) {
226 // Now that we read the whole request and we know device was previously
227 // attached we are good to execute data transfer.
228
229 // Claim and release default interface for the duration of a transfer.
230 libusb_claim_interface(handle_iter->second, 0);
231
232 int ret_len = 0;
233 ALOGI("Requesting %d bytes of data from EP %d with TO %d", req.length,
234 req.endpoint_id, req.timeout);
235
236 // TODO(ender): Remove the timeout modification below when read requests
237 // finally complete.
238 // As of now, USB driver seems to be blocking on read requests.
239 auto err = libusb_bulk_transfer(
240 handle_iter->second,
241 req.endpoint_id |
242 (req.is_host_to_device ? LIBUSB_ENDPOINT_OUT : LIBUSB_ENDPOINT_IN),
243 data.data(), req.length, &ret_len, req.timeout + 1000);
244 libusb_release_interface(handle_iter->second, 0);
245
246 status = (err != 0);
247 if (status) {
248 ALOGE("USB request failed %d, %d", err, errno);
249 } else {
250 ALOGI("Bulk transfer request result: %d / %d", err, ret_len);
251 len = ret_len;
252 }
253 }
254
255 fd_->Write(&status, sizeof(status));
256
257 if (!status && !req.is_host_to_device) {
258 fd_->Write(&len, sizeof(len));
259 if (len > 0) {
260 fd_->Write(data.data(), len);
261 }
262 }
263}
264
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700265void USBServer::Serve() {
266 avd::SharedFDSet rset;
267 while (true) {
268 rset.Zero();
269 rset.Set(fd_);
270 int ret = avd::Select(&rset, nullptr, nullptr, nullptr);
271
272 if (ret < 0) continue;
273
274 if (rset.IsSet(fd_)) {
275 uint32_t cmd;
276 char data;
277 if (fd_->Read(&cmd, sizeof(cmd)) < int(sizeof(cmd))) {
278 ALOGE("Could not read data from input stream: %s", fd_->StrError());
279 continue;
280 }
281
282 switch (cmd) {
283 case CmdDeviceList:
284 HandleDeviceList();
285 break;
286
287 case CmdAttach:
288 HandleAttach();
289
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700290 case CmdControlTransfer:
291 HandleControlTransfer();
292 break;
293
294 case CmdDataTransfer:
295 HandleDataTransfer();
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700296 break;
297
298 default:
299 ALOGE("Discarding unknown command %08x", cmd);
300 }
301 }
302 }
303}