1 // Copyright 2023 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::collections::HashMap; 6 use std::fs::File; 7 use std::mem; 8 use std::sync::Arc; 9 use std::time::Duration; 10 11 use anyhow::Context; 12 use base::error; 13 use base::AsRawDescriptor; 14 use base::EventType; 15 use base::RawDescriptor; 16 use base::Tube; 17 use sync::Mutex; 18 use vm_control::UsbControlAttachedDevice; 19 use vm_control::UsbControlCommand; 20 use vm_control::UsbControlResult; 21 use vm_control::USB_CONTROL_MAX_PORTS; 22 23 use crate::usb::backend::device::BackendDevice; 24 use crate::usb::backend::device::DeviceState; 25 use crate::usb::backend::error::Error; 26 use crate::usb::backend::error::Result; 27 use crate::usb::backend::fido_backend::fido_provider::attach_security_key; 28 use crate::usb::backend::host_backend::host_backend_device_provider::attach_host_backend_device; 29 use crate::usb::xhci::usb_hub::UsbHub; 30 use crate::usb::xhci::xhci_backend_device::XhciBackendDevice; 31 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider; 32 use crate::utils::AsyncJobQueue; 33 use crate::utils::EventHandler; 34 use crate::utils::EventLoop; 35 use crate::utils::FailHandle; 36 37 const SOCKET_TIMEOUT_MS: u64 = 2000; 38 39 /// Device provider is an xhci backend device provider that provides generic semantics to handle 40 /// various types of backend devices and connects them to the xhci layer. 41 pub enum DeviceProvider { 42 // The provider is created but not yet started. 43 Created { control_tube: Mutex<Tube> }, 44 // The provider is started on an event loop. 45 Started { inner: Arc<ProviderInner> }, 46 // The provider has failed. 47 Failed, 48 } 49 50 impl DeviceProvider { new() -> Result<(Tube, DeviceProvider)>51 pub fn new() -> Result<(Tube, DeviceProvider)> { 52 let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?; 53 control_tube 54 .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS))) 55 .map_err(Error::SetupControlTube)?; 56 control_tube 57 .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS))) 58 .map_err(Error::SetupControlTube)?; 59 60 let provider = DeviceProvider::Created { 61 control_tube: Mutex::new(child_tube), 62 }; 63 Ok((control_tube, provider)) 64 } 65 start_helper( &mut self, fail_handle: Arc<dyn FailHandle>, event_loop: Arc<EventLoop>, hub: Arc<UsbHub>, ) -> Result<()>66 fn start_helper( 67 &mut self, 68 fail_handle: Arc<dyn FailHandle>, 69 event_loop: Arc<EventLoop>, 70 hub: Arc<UsbHub>, 71 ) -> Result<()> { 72 match mem::replace(self, DeviceProvider::Failed) { 73 DeviceProvider::Created { control_tube } => { 74 let job_queue = 75 AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?; 76 let inner = Arc::new(ProviderInner::new( 77 fail_handle, 78 job_queue, 79 event_loop.clone(), 80 control_tube, 81 hub, 82 )); 83 let handler: Arc<dyn EventHandler> = inner.clone(); 84 event_loop 85 .add_event( 86 &*inner.control_tube.lock(), 87 EventType::Read, 88 Arc::downgrade(&handler), 89 ) 90 .map_err(Error::AddToEventLoop)?; 91 *self = DeviceProvider::Started { inner }; 92 Ok(()) 93 } 94 DeviceProvider::Started { .. } => { 95 error!("Usb device provider has already started"); 96 Err(Error::BadBackendProviderState) 97 } 98 DeviceProvider::Failed => { 99 error!("Usb device provider has already failed"); 100 Err(Error::BadBackendProviderState) 101 } 102 } 103 } 104 } 105 106 impl XhciBackendDeviceProvider for DeviceProvider { start( &mut self, fail_handle: Arc<dyn FailHandle>, event_loop: Arc<EventLoop>, hub: Arc<UsbHub>, ) -> Result<()>107 fn start( 108 &mut self, 109 fail_handle: Arc<dyn FailHandle>, 110 event_loop: Arc<EventLoop>, 111 hub: Arc<UsbHub>, 112 ) -> Result<()> { 113 self.start_helper(fail_handle, event_loop, hub) 114 } 115 keep_rds(&self) -> Vec<RawDescriptor>116 fn keep_rds(&self) -> Vec<RawDescriptor> { 117 match self { 118 DeviceProvider::Created { control_tube } => { 119 vec![control_tube.lock().as_raw_descriptor()] 120 } 121 _ => { 122 error!("Trying to get keepfds when DeviceProvider is not in created state"); 123 vec![] 124 } 125 } 126 } 127 } 128 129 /// ProviderInner listens to control socket. 130 pub struct ProviderInner { 131 fail_handle: Arc<dyn FailHandle>, 132 job_queue: Arc<AsyncJobQueue>, 133 event_loop: Arc<EventLoop>, 134 control_tube: Mutex<Tube>, 135 usb_hub: Arc<UsbHub>, 136 137 // Map of USB hub port number to per-device context. 138 devices: Mutex<HashMap<u8, DeviceContext>>, 139 } 140 141 struct DeviceContext { 142 event_handler: Arc<dyn EventHandler>, 143 device: Arc<Mutex<dyn BackendDevice>>, 144 } 145 146 impl ProviderInner { new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, event_loop: Arc<EventLoop>, control_tube: Mutex<Tube>, usb_hub: Arc<UsbHub>, ) -> ProviderInner147 fn new( 148 fail_handle: Arc<dyn FailHandle>, 149 job_queue: Arc<AsyncJobQueue>, 150 event_loop: Arc<EventLoop>, 151 control_tube: Mutex<Tube>, 152 usb_hub: Arc<UsbHub>, 153 ) -> ProviderInner { 154 ProviderInner { 155 fail_handle, 156 job_queue, 157 event_loop, 158 control_tube, 159 usb_hub, 160 devices: Mutex::new(HashMap::new()), 161 } 162 } 163 handle_attach_device(&self, usb_file: File) -> UsbControlResult164 fn handle_attach_device(&self, usb_file: File) -> UsbControlResult { 165 let (host_device, event_handler) = match attach_host_backend_device( 166 usb_file, 167 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()), 168 ) { 169 Ok((host_device, event_handler)) => (host_device, event_handler), 170 Err(e) => { 171 error!("could not construct USB device from the given file: {}", e); 172 return UsbControlResult::NoSuchDevice; 173 } 174 }; 175 176 if let Err(e) = self.event_loop.add_event( 177 &*host_device.lock(), 178 EventType::ReadWrite, 179 Arc::downgrade(&event_handler), 180 ) { 181 error!("failed to add USB device to event handler: {}", e); 182 return UsbControlResult::FailedToOpenDevice; 183 } 184 185 // Resetting the device is used to make sure it is in a known state, but it may 186 // still function if the reset fails. 187 if let Err(e) = host_device.lock().reset() { 188 error!("failed to reset device after attach: {:?}", e); 189 } 190 191 let device_ctx = DeviceContext { 192 event_handler, 193 device: host_device.clone(), 194 }; 195 196 let port = self.usb_hub.connect_backend(host_device); 197 match port { 198 Ok(port) => { 199 self.devices.lock().insert(port, device_ctx); 200 UsbControlResult::Ok { port } 201 } 202 Err(e) => { 203 error!("failed to connect device to hub: {}", e); 204 UsbControlResult::NoAvailablePort 205 } 206 } 207 } 208 handle_detach_device(&self, port: u8) -> UsbControlResult209 fn handle_detach_device(&self, port: u8) -> UsbControlResult { 210 match self.usb_hub.disconnect_port(port) { 211 Ok(()) => { 212 if let Some(device_ctx) = self.devices.lock().remove(&port) { 213 let _ = device_ctx.event_handler.on_event(); 214 215 if let Err(e) = device_ctx 216 .device 217 .lock() 218 .detach_event_handler(&self.event_loop) 219 { 220 error!( 221 "failed to remove poll change handler from event loop: {}", 222 e 223 ); 224 } 225 } 226 UsbControlResult::Ok { port } 227 } 228 Err(e) => { 229 error!("failed to disconnect device from port {}: {}", port, e); 230 UsbControlResult::NoSuchDevice 231 } 232 } 233 } 234 handle_attach_security_key(&self, hidraw: File) -> UsbControlResult235 fn handle_attach_security_key(&self, hidraw: File) -> UsbControlResult { 236 let (fido_device, event_handler) = match attach_security_key( 237 hidraw, 238 self.event_loop.clone(), 239 DeviceState::new(self.fail_handle.clone(), self.job_queue.clone()), 240 ) { 241 Ok((fido_device, event_handler)) => (fido_device, event_handler), 242 Err(e) => { 243 error!( 244 "could not create a virtual fido device from the given file: {}", 245 e 246 ); 247 return UsbControlResult::NoSuchDevice; 248 } 249 }; 250 251 if let Err(e) = self.event_loop.add_event( 252 &*fido_device.lock(), 253 EventType::Read, 254 Arc::downgrade(&event_handler), 255 ) { 256 error!("failed to add fido device to event handler: {}", e); 257 return UsbControlResult::FailedToOpenDevice; 258 } 259 260 let device_ctx = DeviceContext { 261 event_handler, 262 device: fido_device.clone(), 263 }; 264 265 // Reset the device to make sure it's in a usable state. 266 // Resetting it also stops polling on the FD, since we only poll when there is an active 267 // transaction. 268 if let Err(e) = fido_device.lock().reset() { 269 error!("failed to reset fido device after attach: {:?}", e); 270 } 271 272 let port = self.usb_hub.connect_backend(fido_device); 273 match port { 274 Ok(port) => { 275 self.devices.lock().insert(port, device_ctx); 276 UsbControlResult::Ok { port } 277 } 278 Err(e) => { 279 error!("failed to connect device to hub: {}", e); 280 UsbControlResult::NoAvailablePort 281 } 282 } 283 } 284 handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult285 fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult { 286 let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default(); 287 for (result_index, &port_id) in ports.iter().enumerate() { 288 match self.usb_hub.get_port(port_id).and_then(|p| { 289 p.backend_device() 290 .as_ref() 291 .map(|d| d.lock()) 292 .map(|d| (d.get_vid(), d.get_pid())) 293 }) { 294 Some((vendor_id, product_id)) => { 295 devices[result_index] = UsbControlAttachedDevice { 296 port: port_id, 297 vendor_id, 298 product_id, 299 } 300 } 301 None => continue, 302 } 303 } 304 UsbControlResult::Devices(devices) 305 } 306 on_event_helper(&self) -> Result<()>307 fn on_event_helper(&self) -> Result<()> { 308 let tube = self.control_tube.lock(); 309 let cmd = tube.recv().map_err(Error::ReadControlTube)?; 310 let result = match cmd { 311 UsbControlCommand::AttachDevice { file } => self.handle_attach_device(file), 312 UsbControlCommand::AttachSecurityKey { file } => self.handle_attach_security_key(file), 313 UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port), 314 UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports), 315 }; 316 tube.send(&result).map_err(Error::WriteControlTube)?; 317 Ok(()) 318 } 319 } 320 321 impl EventHandler for ProviderInner { on_event(&self) -> anyhow::Result<()>322 fn on_event(&self) -> anyhow::Result<()> { 323 self.on_event_helper() 324 .context("host backend device provider failed") 325 } 326 } 327