1use std::collections::HashMap;
6use std::fs::File;
7use std::mem;
8use std::sync::Arc;
9use std::thread;
10use std::time::Duration;
11
12use anyhow::Context;
13use base::error;
14use base::warn;
15use base::AsRawDescriptor;
16use base::EventType;
17use base::RawDescriptor;
18use base::Tube;
19use sync::Mutex;
20use vm_control::UsbControlAttachedDevice;
21use vm_control::UsbControlCommand;
22use vm_control::UsbControlResult;
23use vm_control::USB_CONTROL_MAX_PORTS;
24
25use crate::usb::backend::device::BackendDeviceType;
26use crate::usb::backend::device::DeviceState;
27use crate::usb::backend::error::Error;
28use crate::usb::backend::error::Result;
29use crate::usb::backend::fido_backend::fido_provider::attach_security_key;
30use crate::usb::backend::host_backend::host_backend_device_provider::attach_host_backend_device;
31use crate::usb::backend::utils::UsbUtilEventHandler;
32use crate::usb::xhci::usb_hub::Error as UsbHubError;
33use crate::usb::xhci::usb_hub::UsbHub;
34use crate::usb::xhci::xhci_backend_device::XhciBackendDevice;
35use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
36use crate::utils::AsyncJobQueue;
37use crate::utils::EventHandler;
38use crate::utils::EventLoop;
39use crate::utils::FailHandle;
40
41const SOCKET_TIMEOUT_MS: u64 = 2000;
42
43pub enum DeviceProvider {
46 Created { control_tube: Mutex<Tube> },
48 Started { inner: Arc<ProviderInner> },
50 Failed,
52}
53
54impl DeviceProvider {
55 pub fn new() -> Result<(Tube, DeviceProvider)> {
56 let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?;
57 control_tube
58 .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
59 .map_err(Error::SetupControlTube)?;
60 control_tube
61 .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
62 .map_err(Error::SetupControlTube)?;
63
64 let provider = DeviceProvider::Created {
65 control_tube: Mutex::new(child_tube),
66 };
67 Ok((control_tube, provider))
68 }
69
70 fn start_helper(
71 &mut self,
72 fail_handle: Arc<dyn FailHandle>,
73 event_loop: Arc<EventLoop>,
74 hub: Arc<UsbHub>,
75 ) -> Result<()> {
76 match mem::replace(self, DeviceProvider::Failed) {
77 DeviceProvider::Created { control_tube } => {
78 let job_queue =
79 AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
80 let (control_event_loop, join_handle) =
87 EventLoop::start("usb_provider".to_string(), None)
88 .map_err(Error::StartEventLoop)?;
89 let control_event_loop = Arc::new(control_event_loop);
90 let inner = Arc::new(ProviderInner::new(
91 fail_handle,
92 job_queue,
93 event_loop,
94 control_event_loop.clone(),
95 join_handle,
96 control_tube,
97 hub,
98 ));
99 let handler: Arc<dyn EventHandler> = inner.clone();
100 control_event_loop
101 .add_event(
102 &*inner.control_tube.lock(),
103 EventType::Read,
104 Arc::downgrade(&handler),
105 )
106 .map_err(Error::AddToEventLoop)?;
107 *self = DeviceProvider::Started { inner };
108 Ok(())
109 }
110 DeviceProvider::Started { .. } => {
111 error!("Usb device provider has already started");
112 Err(Error::BadBackendProviderState)
113 }
114 DeviceProvider::Failed => {
115 error!("Usb device provider has already failed");
116 Err(Error::BadBackendProviderState)
117 }
118 }
119 }
120}
121
122impl XhciBackendDeviceProvider for DeviceProvider {
123 fn start(
124 &mut self,
125 fail_handle: Arc<dyn FailHandle>,
126 event_loop: Arc<EventLoop>,
127 hub: Arc<UsbHub>,
128 ) -> Result<()> {
129 self.start_helper(fail_handle, event_loop, hub)
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>,
152 control_event_loop: Arc<EventLoop>,
155 control_event_loop_join_handle: Option<thread::JoinHandle<()>>,
156 control_tube: Mutex<Tube>,
157 usb_hub: Arc<UsbHub>,
158
159 devices: Mutex<HashMap<u8, Arc<UsbUtilEventHandler>>>,
161}
162
163impl ProviderInner {
164 fn new(
165 fail_handle: Arc<dyn FailHandle>,
166 job_queue: Arc<AsyncJobQueue>,
167 event_loop: Arc<EventLoop>,
168 control_event_loop: Arc<EventLoop>,
169 control_event_loop_join_handle: thread::JoinHandle<()>,
170 control_tube: Mutex<Tube>,
171 usb_hub: Arc<UsbHub>,
172 ) -> ProviderInner {
173 ProviderInner {
174 fail_handle,
175 job_queue,
176 event_loop,
177 control_event_loop,
178 control_event_loop_join_handle: Some(control_event_loop_join_handle),
179 control_tube,
180 usb_hub,
181 devices: Mutex::new(HashMap::new()),
182 }
183 }
184
185 fn attach_backend(
186 &self,
187 device: Arc<Mutex<BackendDeviceType>>,
188 event_handler: Arc<UsbUtilEventHandler>,
189 event_type: EventType,
190 ) -> UsbControlResult {
191 let hub_port = match self.usb_hub.connect_backend(device.clone()) {
192 Ok(port) => port,
193 Err(e) => {
194 error!("failed to connect device to hub: {}", e);
195 return UsbControlResult::NoAvailablePort;
196 }
197 };
198
199 let port_id = hub_port.port_id();
200 if let Err(e) = event_handler.activate(event_type, Arc::downgrade(&hub_port)) {
201 error!("failed to activate USB event handler: {}", e);
202 let _ = self.usb_hub.disconnect_port(port_id);
203 return UsbControlResult::FailedToOpenDevice;
204 }
205
206 self.devices.lock().insert(port_id, event_handler);
207 UsbControlResult::Ok { port: port_id }
208 }
209
210 fn handle_attach_device(&self, usb_file: File) -> UsbControlResult {
211 let (host_device, event_handler) = match attach_host_backend_device(
212 usb_file,
213 self.event_loop.clone(),
214 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
215 ) {
216 Ok((host_device, event_handler)) => (host_device, event_handler),
217 Err(e) => {
218 error!("could not construct USB device from the given file: {}", e);
219 return UsbControlResult::FailedToInitHostDevice;
222 }
223 };
224
225 if let Err(e) = host_device.lock().reset() {
228 error!("failed to reset device during attach: {:?}", e);
229 }
230
231 self.attach_backend(host_device, event_handler, EventType::ReadWrite)
232 }
233
234 fn handle_detach_device(&self, port: u8) -> UsbControlResult {
235 match self.usb_hub.disconnect_port(port) {
236 Ok(()) => {}
237 Err(e @ UsbHubError::Detach { .. }) => {
238 warn!(
242 "detached device from port {}, but failed to notify the guest: {}",
243 port, e
244 );
245 }
246 Err(e) => {
247 error!("failed to disconnect device from port {}: {}", port, e);
248 return UsbControlResult::NoSuchDevice;
249 }
250 }
251
252 if let Some(event_handler) = self.devices.lock().remove(&port) {
256 event_handler.signal_detach();
257 }
258 UsbControlResult::Ok { port }
259 }
260
261 fn handle_attach_security_key(&self, hidraw: File) -> UsbControlResult {
262 let (fido_device, event_handler) = match attach_security_key(
263 hidraw,
264 self.event_loop.clone(),
265 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()),
266 ) {
267 Ok((fido_device, event_handler)) => (fido_device, event_handler),
268 Err(e) => {
269 error!(
270 "could not create a virtual fido device from the given file: {}",
271 e
272 );
273 return UsbControlResult::NoSuchDevice;
274 }
275 };
276
277 if let Err(e) = fido_device.lock().reset() {
281 error!("failed to reset fido device during attach: {:?}", e);
282 }
283
284 self.attach_backend(fido_device, event_handler, EventType::Read)
285 }
286
287 fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
288 let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
289 for (result_index, &port_id) in ports.iter().enumerate() {
290 match self.usb_hub.get_port(port_id).and_then(|p| {
291 p.backend_device()
292 .as_ref()
293 .map(|d| d.lock())
294 .map(|d| (d.get_vid(), d.get_pid()))
295 }) {
296 Some((vendor_id, product_id)) => {
297 devices[result_index] = UsbControlAttachedDevice {
298 port: port_id,
299 vendor_id,
300 product_id,
301 }
302 }
303 None => continue,
304 }
305 }
306 UsbControlResult::Devices(devices)
307 }
308
309 fn on_event_helper(&self) -> Result<()> {
310 let tube = self.control_tube.lock();
311 let cmd = tube.recv().map_err(Error::ReadControlTube)?;
312 let result = match cmd {
313 UsbControlCommand::AttachDevice { file } => self.handle_attach_device(file),
314 UsbControlCommand::AttachSecurityKey { file } => self.handle_attach_security_key(file),
315 UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
316 UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
317 };
318 tube.send(&result).map_err(Error::WriteControlTube)?;
319 Ok(())
320 }
321}
322
323impl EventHandler for ProviderInner {
324 fn on_event(&self) -> anyhow::Result<()> {
325 self.on_event_helper()
326 .context("host backend device provider failed")
327 }
328}
329
330impl Drop for ProviderInner {
331 fn drop(&mut self) {
332 self.control_event_loop.stop();
335 if let Some(join_handle) = self.control_event_loop_join_handle.take() {
336 let _ = join_handle.join();
337 }
338 }
339}