1use std::collections::HashMap;
6use std::fs::File;
7use std::mem;
8use std::sync::Arc;
9use std::time::Duration;
10
11use anyhow::Context;
12use base::error;
13use base::AsRawDescriptor;
14use base::EventType;
15use base::RawDescriptor;
16use base::Tube;
17use sync::Mutex;
18use vm_control::UsbControlAttachedDevice;
19use vm_control::UsbControlCommand;
20use vm_control::UsbControlResult;
21use vm_control::USB_CONTROL_MAX_PORTS;
22
23use crate::usb::backend::device::BackendDeviceType;
24use crate::usb::backend::device::DeviceState;
25use crate::usb::backend::error::Error;
26use crate::usb::backend::error::Result;
27use crate::usb::backend::fido_backend::fido_provider::attach_security_key;
28use crate::usb::backend::host_backend::host_backend_device_provider::attach_host_backend_device;
29use crate::usb::backend::utils::UsbUtilEventHandler;
30use crate::usb::xhci::usb_hub::UsbHub;
31use crate::usb::xhci::xhci_backend_device::XhciBackendDevice;
32use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
33use crate::utils::AsyncJobQueue;
34use crate::utils::EventHandler;
35use crate::utils::EventLoop;
36use crate::utils::FailHandle;
37
38const SOCKET_TIMEOUT_MS: u64 = 2000;
39
40pub enum DeviceProvider {
43 Created { control_tube: Mutex<Tube> },
45 Started { inner: Arc<ProviderInner> },
47 Failed,
49}
50
51impl DeviceProvider {
52 pub fn new() -> Result<(Tube, DeviceProvider)> {
53 let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?;
54 control_tube
55 .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
56 .map_err(Error::SetupControlTube)?;
57 control_tube
58 .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
59 .map_err(Error::SetupControlTube)?;
60
61 let provider = DeviceProvider::Created {
62 control_tube: Mutex::new(child_tube),
63 };
64 Ok((control_tube, provider))
65 }
66
67 fn start_helper(
68 &mut self,
69 fail_handle: Arc<dyn FailHandle>,
70 event_loop: Arc<EventLoop>,
71 hub: Arc<UsbHub>,
72 ) -> Result<()> {
73 match mem::replace(self, DeviceProvider::Failed) {
74 DeviceProvider::Created { control_tube } => {
75 let job_queue =
76 AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
77 let inner = Arc::new(ProviderInner::new(
78 fail_handle,
79 job_queue,
80 event_loop.clone(),
81 control_tube,
82 hub,
83 ));
84 let handler: Arc<dyn EventHandler> = inner.clone();
85 event_loop
86 .add_event(
87 &*inner.control_tube.lock(),
88 EventType::Read,
89 Arc::downgrade(&handler),
90 )
91 .map_err(Error::AddToEventLoop)?;
92 *self = DeviceProvider::Started { inner };
93 Ok(())
94 }
95 DeviceProvider::Started { .. } => {
96 error!("Usb device provider has already started");
97 Err(Error::BadBackendProviderState)
98 }
99 DeviceProvider::Failed => {
100 error!("Usb device provider has already failed");
101 Err(Error::BadBackendProviderState)
102 }
103 }
104 }
105}
106
107impl XhciBackendDeviceProvider for DeviceProvider {
108 fn start(
109 &mut self,
110 fail_handle: Arc<dyn FailHandle>,
111 event_loop: Arc<EventLoop>,
112 hub: Arc<UsbHub>,
113 ) -> Result<()> {
114 self.start_helper(fail_handle, event_loop, hub)
115 }
116
117 fn attach_device(&self, file: File) {
118 if let DeviceProvider::Started { inner } = self {
119 match inner.handle_attach_device(file) {
120 UsbControlResult::Ok { port } => {
121 base::info!("Attached USB device at startup, port {}", port);
122 }
123 result => {
124 base::error!("Failed to attach USB device at startup: {}", result);
125 }
126 }
127 } else {
128 base::error!("Cannot attach USB device: DeviceProvider not started");
129 }
130 }
131
132 fn keep_rds(&self) -> Vec<RawDescriptor> {
133 match self {
134 DeviceProvider::Created { control_tube } => {
135 vec![control_tube.lock().as_raw_descriptor()]
136 }
137 _ => {
138 error!("Trying to get keepfds when DeviceProvider is not in created state");
139 vec![]
140 }
141 }
142 }
143}
144
145pub struct ProviderInner {
147 fail_handle: Arc<dyn FailHandle>,
148 job_queue: Arc<AsyncJobQueue>,
149 event_loop: Arc<EventLoop>,
150 control_tube: Mutex<Tube>,
151 usb_hub: Arc<UsbHub>,
152
153 devices: Mutex<HashMap<u8, Arc<UsbUtilEventHandler>>>,
155}
156
157impl ProviderInner {
158 fn new(
159 fail_handle: Arc<dyn FailHandle>,
160 job_queue: Arc<AsyncJobQueue>,
161 event_loop: Arc<EventLoop>,
162 control_tube: Mutex<Tube>,
163 usb_hub: Arc<UsbHub>,
164 ) -> ProviderInner {
165 ProviderInner {
166 fail_handle,
167 job_queue,
168 event_loop,
169 control_tube,
170 usb_hub,
171 devices: Mutex::new(HashMap::new()),
172 }
173 }
174
175 fn attach_backend(
176 &self,
177 device: Arc<Mutex<BackendDeviceType>>,
178 event_handler: Arc<UsbUtilEventHandler>,
179 event_type: EventType,
180 ) -> UsbControlResult {
181 let hub_port = match self.usb_hub.connect_backend(device.clone()) {
182 Ok(port) => port,
183 Err(e) => {
184 error!("failed to connect device to hub: {}", e);
185 return UsbControlResult::NoAvailablePort;
186 }
187 };
188
189 let port_id = hub_port.port_id();
190 if let Err(e) = event_handler.activate(event_type, Arc::downgrade(&hub_port)) {
191 error!("failed to activate USB event handler: {}", e);
192 let _ = self.usb_hub.disconnect_port(port_id);
193 return UsbControlResult::FailedToOpenDevice;
194 }
195
196 self.devices.lock().insert(port_id, event_handler);
197 UsbControlResult::Ok { port: port_id }
198 }
199
200 fn handle_attach_device(&self, usb_file: File) -> UsbControlResult {
201 let (host_device, event_handler) = match attach_host_backend_device(
202 usb_file,
203 self.event_loop.clone(),
204 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
205 ) {
206 Ok((host_device, event_handler)) => (host_device, event_handler),
207 Err(e) => {
208 error!("could not construct USB device from the given file: {}", e);
209 return UsbControlResult::NoSuchDevice;
210 }
211 };
212
213 if let Err(e) = host_device.lock().reset() {
216 error!("failed to reset device during attach: {:?}", e);
217 }
218
219 self.attach_backend(host_device, event_handler, EventType::ReadWrite)
220 }
221
222 fn handle_detach_device(&self, port: u8) -> UsbControlResult {
223 match self.usb_hub.disconnect_port(port) {
224 Ok(()) => {
225 if let Some(event_handler) = self.devices.lock().remove(&port) {
229 event_handler.signal_detach();
230 }
231 UsbControlResult::Ok { port }
232 }
233 Err(e) => {
234 error!("failed to disconnect device from port {}: {}", port, e);
235 UsbControlResult::NoSuchDevice
236 }
237 }
238 }
239
240 fn handle_attach_security_key(&self, hidraw: File) -> UsbControlResult {
241 let (fido_device, event_handler) = match attach_security_key(
242 hidraw,
243 self.event_loop.clone(),
244 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
245 ) {
246 Ok((fido_device, event_handler)) => (fido_device, event_handler),
247 Err(e) => {
248 error!(
249 "could not create a virtual fido device from the given file: {}",
250 e
251 );
252 return UsbControlResult::NoSuchDevice;
253 }
254 };
255
256 if let Err(e) = fido_device.lock().reset() {
260 error!("failed to reset fido device during attach: {:?}", e);
261 }
262
263 self.attach_backend(fido_device, event_handler, EventType::Read)
264 }
265
266 fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
267 let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
268 for (result_index, &port_id) in ports.iter().enumerate() {
269 match self.usb_hub.get_port(port_id).and_then(|p| {
270 p.backend_device()
271 .as_ref()
272 .map(|d| d.lock())
273 .map(|d| (d.get_vid(), d.get_pid()))
274 }) {
275 Some((vendor_id, product_id)) => {
276 devices[result_index] = UsbControlAttachedDevice {
277 port: port_id,
278 vendor_id,
279 product_id,
280 }
281 }
282 None => continue,
283 }
284 }
285 UsbControlResult::Devices(devices)
286 }
287
288 fn on_event_helper(&self) -> Result<()> {
289 let tube = self.control_tube.lock();
290 let cmd = tube.recv().map_err(Error::ReadControlTube)?;
291 let result = match cmd {
292 UsbControlCommand::AttachDevice { file } => self.handle_attach_device(file),
293 UsbControlCommand::AttachSecurityKey { file } => self.handle_attach_security_key(file),
294 UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
295 UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
296 };
297 tube.send(&result).map_err(Error::WriteControlTube)?;
298 Ok(())
299 }
300}
301
302impl EventHandler for ProviderInner {
303 fn on_event(&self) -> anyhow::Result<()> {
304 self.on_event_helper()
305 .context("host backend device provider failed")
306 }
307}