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::BackendDevice;
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::xhci::usb_hub::UsbHub;
30use crate::usb::xhci::xhci_backend_device::XhciBackendDevice;
31use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
32use crate::utils::AsyncJobQueue;
33use crate::utils::EventHandler;
34use crate::utils::EventLoop;
35use crate::utils::FailHandle;
36
37const SOCKET_TIMEOUT_MS: u64 = 2000;
38
39pub enum DeviceProvider {
42 Created { control_tube: Mutex<Tube> },
44 Started { inner: Arc<ProviderInner> },
46 Failed,
48}
49
50impl 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
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
106impl XhciBackendDeviceProvider for DeviceProvider {
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
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
129pub 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 devices: Mutex<HashMap<u8, DeviceContext>>,
139}
140
141struct DeviceContext {
142 event_handler: Arc<dyn EventHandler>,
143 device: Arc<Mutex<dyn BackendDevice>>,
144}
145
146impl ProviderInner {
147 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
164 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 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
209 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
235 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 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
285 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
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
321impl EventHandler for ProviderInner {
322 fn on_event(&self) -> anyhow::Result<()> {
323 self.on_event_helper()
324 .context("host backend device provider failed")
325 }
326}