devices/usb/backend/
device_provider.rs

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
5use 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
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.
41pub 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
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
129/// ProviderInner listens to control socket.
130pub 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
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        // 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
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        // 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
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}