xref: /aosp_15_r20/external/crosvm/devices/src/usb/backend/fido_backend/fido_passthrough.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2024 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::VecDeque;
6 use std::io::Error as IOError;
7 use std::io::ErrorKind;
8 use std::io::Read;
9 use std::sync::Arc;
10 use std::sync::RwLock;
11 
12 use base::debug;
13 use base::error;
14 use base::AsRawDescriptor;
15 use base::Event;
16 use base::RawDescriptor;
17 use base::WorkerThread;
18 use sync::Mutex;
19 use usb_util::parse_usbfs_descriptors;
20 use usb_util::ConfigDescriptorTree;
21 use usb_util::ControlRequestDataPhaseTransferDirection;
22 use usb_util::ControlRequestRecipient;
23 use usb_util::ControlRequestType;
24 use usb_util::DescriptorType;
25 use usb_util::DeviceDescriptorTree;
26 use usb_util::DeviceSpeed;
27 use usb_util::EndpointDirection;
28 use usb_util::EndpointType;
29 use usb_util::Error as UsbUtilError;
30 use usb_util::TransferBuffer;
31 use usb_util::TransferStatus;
32 use usb_util::UsbRequestSetup;
33 use zerocopy::AsBytes;
34 use zerocopy::FromBytes;
35 
36 use crate::usb::backend::device::BackendDevice;
37 use crate::usb::backend::device::DeviceState;
38 use crate::usb::backend::endpoint::ControlEndpointState;
39 use crate::usb::backend::endpoint::UsbEndpoint;
40 use crate::usb::backend::error::Error as BackendError;
41 use crate::usb::backend::error::Result as BackendResult;
42 use crate::usb::backend::fido_backend::constants;
43 use crate::usb::backend::fido_backend::error::Error;
44 use crate::usb::backend::fido_backend::error::Result;
45 use crate::usb::backend::fido_backend::fido_device::FidoDevice;
46 use crate::usb::backend::fido_backend::poll_thread::poll_for_pending_packets;
47 use crate::usb::backend::fido_backend::transfer::FidoTransfer;
48 use crate::usb::backend::fido_backend::transfer::FidoTransferHandle;
49 use crate::usb::backend::transfer::BackendTransferHandle;
50 use crate::usb::backend::transfer::BackendTransferType;
51 use crate::usb::backend::transfer::ControlTransferState;
52 use crate::usb::backend::transfer::GenericTransferHandle;
53 use crate::usb::xhci::xhci_backend_device::BackendType;
54 use crate::usb::xhci::xhci_backend_device::UsbDeviceAddress;
55 use crate::usb::xhci::xhci_backend_device::XhciBackendDevice;
56 use crate::utils::AsyncJobQueue;
57 use crate::utils::EventLoop;
58 
59 /// Host-level fido passthrough device that handles USB operations and relays them to the
60 /// appropriate virtual fido device.
61 pub struct FidoPassthroughDevice {
62     /// The virtual FIDO device implementation.
63     device: Arc<Mutex<FidoDevice>>,
64     /// The state of the device as seen by the backend provider.
65     state: Arc<RwLock<DeviceState>>,
66     /// The state of the control transfer exchange with the xhci layer.
67     control_transfer_state: Arc<RwLock<ControlTransferState>>,
68     transfer_job_queue: Arc<AsyncJobQueue>,
69     kill_evt: Event,
70     worker_thread: Option<WorkerThread<()>>,
71     pending_in_transfers:
72         Arc<Mutex<VecDeque<(FidoTransferHandle, Arc<Mutex<Option<FidoTransfer>>>)>>>,
73 }
74 
75 impl FidoPassthroughDevice {
new( device: Arc<Mutex<FidoDevice>>, state: DeviceState, event_loop: Arc<EventLoop>, ) -> Result<Self>76     pub fn new(
77         device: Arc<Mutex<FidoDevice>>,
78         state: DeviceState,
79         event_loop: Arc<EventLoop>,
80     ) -> Result<Self> {
81         let control_transfer_state = ControlTransferState {
82             ctl_ep_state: ControlEndpointState::SetupStage,
83             control_request_setup: UsbRequestSetup::new(0, 0, 0, 0, 0),
84             executed: false,
85         };
86         let job_queue = AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncFidoQueue)?;
87         Ok(FidoPassthroughDevice {
88             device,
89             state: Arc::new(RwLock::new(state)),
90             control_transfer_state: Arc::new(RwLock::new(control_transfer_state)),
91             transfer_job_queue: job_queue,
92             kill_evt: Event::new().unwrap(),
93             worker_thread: None,
94             pending_in_transfers: Arc::new(Mutex::new(VecDeque::new())),
95         })
96     }
97 
98     /// This function is called from the low-level event handler when the monitored `fd` is ready
99     /// to transmit data from the host to the guest.
read_hidraw_file(&mut self) -> Result<()>100     pub fn read_hidraw_file(&mut self) -> Result<()> {
101         let mut device = self.device.lock();
102         // Device has already stopped working, just return early.
103         if device.is_device_lost {
104             return Ok(());
105         }
106         if !device.is_active {
107             // We should NEVER be polling on the fd and wake up if no transactions have been
108             // initiated from the guest first.
109             error!("Fido device received fd poll event from inactive device. This is a bug.");
110             return Err(Error::InconsistentFidoDeviceState);
111         }
112 
113         let mut packet = vec![0; constants::U2FHID_PACKET_SIZE * 2];
114 
115         if device.guest_key.lock().pending_in_packets.len() >= constants::U2FHID_MAX_IN_PENDING {
116             return Err(Error::PendingInQueueFull);
117         }
118 
119         let read_result = device.fd.lock().read(&mut packet);
120         match read_result {
121             Ok(n) => {
122                 // We read too much, the device is misbehaving
123                 if n != constants::U2FHID_PACKET_SIZE {
124                     return Err(Error::ReadHidrawDevice(IOError::new(
125                         ErrorKind::Other,
126                         format!("Read too many bytes ({n}), the hidraw device is misbehaving."),
127                     )));
128                 }
129                 // This is safe because we just checked the size of n is exactly U2FHID_PACKET_SIZE
130                 device
131                     .recv_from_host(packet[..constants::U2FHID_PACKET_SIZE].try_into().unwrap())?;
132             }
133             Err(e) => {
134                 error!("U2F hidraw read error: {e:#}, resetting and detaching device",);
135                 device.set_active(false);
136                 device.is_device_lost = true;
137                 return Err(Error::ReadHidrawDevice(e));
138             }
139         }
140         Ok(())
141     }
142 
143     /// This function is called by a queued job to handle all communication related to USB control
144     /// transfer packets between the guest and the virtual security key.
handle_control( transfer: &mut FidoTransfer, device: &Arc<Mutex<FidoDevice>>, ) -> Result<()>145     pub fn handle_control(
146         transfer: &mut FidoTransfer,
147         device: &Arc<Mutex<FidoDevice>>,
148     ) -> Result<()> {
149         transfer.actual_length = 0;
150         let request_setup = match &transfer.buffer {
151             TransferBuffer::Vector(v) => {
152                 UsbRequestSetup::read_from_prefix(v).ok_or_else(|| Error::InvalidDataBufferSize)?
153             }
154             _ => {
155                 return Err(Error::UnsupportedTransferBufferType);
156             }
157         };
158 
159         let mut request_setup_out = request_setup.as_bytes().to_vec();
160         let is_device_to_host =
161             request_setup.get_direction() == ControlRequestDataPhaseTransferDirection::DeviceToHost;
162         let descriptor_type = (request_setup.value >> 8) as u8;
163 
164         // Get Device Descriptor request
165         if descriptor_type == (DescriptorType::Device as u8) && is_device_to_host {
166             // If the descriptor is larger than the actual requested data, we only allocate space
167             // for the request size. This is common for USB3 control setup to request only the
168             // initial 8 bytes instead of the full descriptor.
169             let buf_size = std::cmp::min(
170                 request_setup.length.into(),
171                 constants::U2FHID_DEVICE_DESC.len(),
172             );
173             let mut buffer: Vec<u8> = constants::U2FHID_DEVICE_DESC[..buf_size].to_vec();
174             transfer.actual_length = buffer.len();
175             request_setup_out.append(&mut buffer);
176         }
177 
178         if request_setup.get_recipient() == ControlRequestRecipient::Interface {
179             // It's a request for the HID report descriptor
180             if is_device_to_host && descriptor_type == constants::HID_GET_REPORT_DESC {
181                 let mut buffer: Vec<u8> = constants::HID_REPORT_DESC.to_vec();
182                 transfer.actual_length = buffer.len();
183                 request_setup_out.append(&mut buffer);
184             }
185         }
186 
187         if request_setup.get_type() == ControlRequestType::Class {
188             match request_setup.request {
189                 constants::HID_GET_IDLE => {
190                     let mut buffer: Vec<u8> = vec![0u8, 1];
191                     buffer[0] = device.lock().guest_key.lock().idle;
192                     transfer.actual_length = 1;
193                     request_setup_out.append(&mut buffer);
194                 }
195                 constants::HID_SET_IDLE => {
196                     device.lock().guest_key.lock().idle = (request_setup.value >> 8) as u8;
197                 }
198                 _ => {
199                     debug!(
200                         "Received unsupported setup request code of Class type: {}",
201                         request_setup.request
202                     );
203                 }
204             }
205         }
206 
207         // Store the response
208         transfer.buffer = TransferBuffer::Vector(request_setup_out);
209         Ok(())
210     }
211 
212     /// This function is called by a queued job to handle all USB OUT requests from the guest down
213     /// to the host by writing the given `FidoTransfer` data into the hidraw file.
handle_interrupt_out( transfer: &mut FidoTransfer, device: &Arc<Mutex<FidoDevice>>, ) -> Result<()>214     pub fn handle_interrupt_out(
215         transfer: &mut FidoTransfer,
216         device: &Arc<Mutex<FidoDevice>>,
217     ) -> Result<()> {
218         let mut packet = [0u8; constants::U2FHID_PACKET_SIZE];
219         let buffer = match &transfer.buffer {
220             TransferBuffer::Vector(v) => v,
221             _ => {
222                 return Err(Error::UnsupportedTransferBufferType);
223             }
224         };
225         if buffer.len() > constants::U2FHID_PACKET_SIZE {
226             error!(
227                 "Buffer size is bigger than u2f-hid packet size: {}",
228                 buffer.len()
229             );
230             return Err(Error::InvalidDataBufferSize);
231         }
232         packet.copy_from_slice(buffer);
233         let written = device.lock().recv_from_guest(packet)?;
234         transfer.actual_length = written;
235         Ok(())
236     }
237 }
238 
239 impl Drop for FidoPassthroughDevice {
drop(&mut self)240     fn drop(&mut self) {
241         self.device.lock().is_device_lost = true;
242         if let Err(e) = self.kill_evt.signal() {
243             error!(
244                 "Failed to send signal to stop poll worker thread, \
245                 it might have already stopped. {e:#}"
246             );
247         }
248     }
249 }
250 
251 impl AsRawDescriptor for FidoPassthroughDevice {
as_raw_descriptor(&self) -> RawDescriptor252     fn as_raw_descriptor(&self) -> RawDescriptor {
253         self.device.lock().as_raw_descriptor()
254     }
255 }
256 
257 impl BackendDevice for FidoPassthroughDevice {
submit_backend_transfer( &mut self, transfer: BackendTransferType, ) -> BackendResult<BackendTransferHandle>258     fn submit_backend_transfer(
259         &mut self,
260         transfer: BackendTransferType,
261     ) -> BackendResult<BackendTransferHandle> {
262         let transfer = match transfer {
263             BackendTransferType::FidoDevice(transfer) => transfer,
264             _ => return Err(BackendError::MalformedBackendTransfer),
265         };
266 
267         let endpoint = transfer.endpoint;
268         let arc_transfer = Arc::new(Mutex::new(Some(transfer)));
269         let cancel_handle = FidoTransferHandle {
270             weak_transfer: Arc::downgrade(&arc_transfer),
271         };
272 
273         match endpoint {
274             constants::U2FHID_CONTROL_ENDPOINT => {
275                 let arc_transfer_local = arc_transfer.clone();
276                 let fido_device = self.device.clone();
277                 self.transfer_job_queue
278                     .queue_job(move || {
279                         let mut lock = arc_transfer_local.lock();
280                         match lock.take() {
281                             Some(mut transfer) => {
282                                 if let Err(e) = FidoPassthroughDevice::handle_control(
283                                     &mut transfer,
284                                     &fido_device,
285                                 ) {
286                                     error!(
287                                         "Fido device handle control failed, cancelling transfer:\
288                                         {e:#}"
289                                     );
290                                     drop(lock);
291                                     if let Err(e) = cancel_handle.cancel() {
292                                         error!(
293                                             "Failed to cancel transfer, dropping request: {e:#}"
294                                         );
295                                         return;
296                                     }
297                                 }
298                                 transfer.complete_transfer();
299                             }
300                             None => {
301                                 error!(
302                                     "USB transfer disappeared in handle_control. Dropping request."
303                                 );
304                             }
305                         }
306                     })
307                     .map_err(BackendError::QueueAsyncJob)?;
308             }
309             constants::U2FHID_OUT_ENDPOINT => {
310                 let arc_transfer_local = arc_transfer.clone();
311                 let fido_device = self.device.clone();
312                 self.transfer_job_queue
313                     .queue_job(move || {
314                         let mut lock = arc_transfer_local.lock();
315                         match lock.take() {
316                             Some(mut transfer) => {
317                                 if let Err(e) = FidoPassthroughDevice::handle_interrupt_out(
318                                     &mut transfer,
319                                     &fido_device,
320                                 ) {
321                                     error!(
322                                         "Fido device handle interrupt out failed,\
323                                         cancelling transfer: {e:#}"
324                                     );
325                                     drop(lock);
326                                     if let Err(e) = cancel_handle.cancel() {
327                                         error!(
328                                             "Failed to cancel transfer, dropping request: {e:#}"
329                                         );
330                                         return;
331                                     }
332                                 }
333                                 transfer.complete_transfer();
334                             }
335                             None => {
336                                 error!("Interrupt out transfer disappeared. Dropping request.");
337                             }
338                         }
339                     })
340                     .map_err(BackendError::QueueAsyncJob)?;
341             }
342             constants::U2FHID_IN_ENDPOINT => {
343                 let handle = FidoTransferHandle {
344                     weak_transfer: Arc::downgrade(&arc_transfer.clone()),
345                 };
346                 self.pending_in_transfers
347                     .lock()
348                     .push_back((handle, arc_transfer.clone()));
349 
350                 // Make sure to arm the timer for both transfer and host packet polling as we wait
351                 // for transaction requests to be fulfilled by the host or xhci transfer to time
352                 // out.
353                 if let Err(e) = self.device.lock().guest_key.lock().timer.arm() {
354                     error!("Unable to start U2F guest key timer. U2F packets may be lost. {e:#}");
355                 }
356                 if let Err(e) = self.device.lock().transfer_timer.arm() {
357                     error!("Unable to start transfer poll timer. Transfers might stall. {e:#}");
358                 }
359             }
360             _ => {
361                 error!("Wrong endpoint requested: {endpoint}");
362                 return Err(BackendError::MalformedBackendTransfer);
363             }
364         }
365 
366         // Start the worker thread if it hasn't been created yet
367         if self.worker_thread.is_none()
368             && (endpoint == constants::U2FHID_IN_ENDPOINT
369                 || endpoint == constants::U2FHID_OUT_ENDPOINT)
370         {
371             let device = self.device.clone();
372             let pending_in_transfers = self.pending_in_transfers.clone();
373             self.worker_thread = Some(WorkerThread::start("fido poll thread", move |kill_evt| {
374                 if let Err(e) = poll_for_pending_packets(device, pending_in_transfers, kill_evt) {
375                     error!("Poll worker thread errored: {e:#}");
376                 }
377             }));
378         }
379 
380         let cancel_handle = FidoTransferHandle {
381             weak_transfer: Arc::downgrade(&arc_transfer),
382         };
383         Ok(BackendTransferHandle::new(cancel_handle))
384     }
385 
detach_event_handler(&self, _event_loop: &Arc<EventLoop>) -> BackendResult<()>386     fn detach_event_handler(&self, _event_loop: &Arc<EventLoop>) -> BackendResult<()> {
387         self.device.lock().set_active(false);
388         Ok(())
389     }
390 
request_transfer_buffer(&mut self, size: usize) -> TransferBuffer391     fn request_transfer_buffer(&mut self, size: usize) -> TransferBuffer {
392         TransferBuffer::Vector(vec![0u8; size])
393     }
394 
build_bulk_transfer( &mut self, _ep_addr: u8, _transfer_buffer: TransferBuffer, _stream_id: Option<u16>, ) -> BackendResult<BackendTransferType>395     fn build_bulk_transfer(
396         &mut self,
397         _ep_addr: u8,
398         _transfer_buffer: TransferBuffer,
399         _stream_id: Option<u16>,
400     ) -> BackendResult<BackendTransferType> {
401         // Fido devices don't support bulk transfer requests
402         Err(BackendError::MalformedBackendTransfer)
403     }
404 
build_interrupt_transfer( &mut self, ep_addr: u8, transfer_buffer: TransferBuffer, ) -> BackendResult<BackendTransferType>405     fn build_interrupt_transfer(
406         &mut self,
407         ep_addr: u8,
408         transfer_buffer: TransferBuffer,
409     ) -> BackendResult<BackendTransferType> {
410         Ok(BackendTransferType::FidoDevice(FidoTransfer::new(
411             ep_addr,
412             transfer_buffer,
413         )))
414     }
415 
get_control_transfer_state(&mut self) -> Arc<RwLock<ControlTransferState>>416     fn get_control_transfer_state(&mut self) -> Arc<RwLock<ControlTransferState>> {
417         self.control_transfer_state.clone()
418     }
419 
get_device_state(&mut self) -> Arc<RwLock<DeviceState>>420     fn get_device_state(&mut self) -> Arc<RwLock<DeviceState>> {
421         self.state.clone()
422     }
423 
get_active_config_descriptor(&mut self) -> BackendResult<ConfigDescriptorTree>424     fn get_active_config_descriptor(&mut self) -> BackendResult<ConfigDescriptorTree> {
425         // There is only a config descriptor for u2f virtual keys.
426         self.get_config_descriptor_by_index(0)
427     }
428 
get_config_descriptor(&mut self, config: u8) -> BackendResult<ConfigDescriptorTree>429     fn get_config_descriptor(&mut self, config: u8) -> BackendResult<ConfigDescriptorTree> {
430         let device_descriptor = self.get_device_descriptor_tree()?;
431         if let Some(config_descriptor) = device_descriptor.get_config_descriptor(config) {
432             return Ok(config_descriptor.clone());
433         }
434         Err(BackendError::GetConfigDescriptor(
435             UsbUtilError::DescriptorParse,
436         ))
437     }
438 
get_config_descriptor_by_index( &mut self, config_index: u8, ) -> BackendResult<ConfigDescriptorTree>439     fn get_config_descriptor_by_index(
440         &mut self,
441         config_index: u8,
442     ) -> BackendResult<ConfigDescriptorTree> {
443         let device_descriptor = self.get_device_descriptor_tree()?;
444         if let Some(config_descriptor) =
445             device_descriptor.get_config_descriptor_by_index(config_index)
446         {
447             return Ok(config_descriptor.clone());
448         }
449         Err(BackendError::GetConfigDescriptor(
450             UsbUtilError::DescriptorParse,
451         ))
452     }
453 
get_device_descriptor_tree(&mut self) -> BackendResult<DeviceDescriptorTree>454     fn get_device_descriptor_tree(&mut self) -> BackendResult<DeviceDescriptorTree> {
455         // Skip the first two fields of length and descriptor type as we don't need them in our
456         // DeviceDescriptor structure.
457         let mut descbuf: Vec<u8> = constants::U2FHID_DEVICE_DESC.to_vec();
458         let mut configbuf: Vec<u8> = constants::U2FHID_CONFIG_DESC.to_vec();
459         descbuf.append(&mut configbuf);
460         parse_usbfs_descriptors(&descbuf).map_err(BackendError::GetDeviceDescriptor)
461     }
462 
get_active_configuration(&mut self) -> BackendResult<u8>463     fn get_active_configuration(&mut self) -> BackendResult<u8> {
464         let descriptor_tree = self.get_device_descriptor_tree()?;
465         if descriptor_tree.bNumConfigurations != 1 {
466             error!(
467                 "Fido devices should only have one configuration, found {}",
468                 descriptor_tree.bNumConfigurations
469             );
470         } else if let Some(config_descriptor) = descriptor_tree.get_config_descriptor_by_index(0) {
471             return Ok(config_descriptor.bConfigurationValue);
472         }
473         Err(BackendError::GetActiveConfig(UsbUtilError::DescriptorParse))
474     }
475 
set_active_configuration(&mut self, config: u8) -> BackendResult<()>476     fn set_active_configuration(&mut self, config: u8) -> BackendResult<()> {
477         // Fido devices only have one configuration so we should do nothing here.
478         // Return an error if the configuration number is unexpected.
479         if config != 0 {
480             error!(
481                 "Requested to set fido active configuration of {config}, but only 0 is allowed."
482             );
483             return Err(BackendError::BadBackendProviderState);
484         }
485         Ok(())
486     }
487 
clear_feature(&mut self, _value: u16, _index: u16) -> BackendResult<TransferStatus>488     fn clear_feature(&mut self, _value: u16, _index: u16) -> BackendResult<TransferStatus> {
489         // Nothing to do here, just return.
490         Ok(TransferStatus::Completed)
491     }
492 
create_endpoints(&mut self, _config_descriptor: &ConfigDescriptorTree) -> BackendResult<()>493     fn create_endpoints(&mut self, _config_descriptor: &ConfigDescriptorTree) -> BackendResult<()> {
494         let mut endpoints = Vec::new();
495         let device_state = self.get_device_state();
496         // We ignore the config descriptor because u2f-hid endpoints are already defined by the
497         // protocol and are unchanging.
498         // Endpoint 1 (OUT)
499         endpoints.push(UsbEndpoint::new(
500             device_state.read().unwrap().fail_handle.clone(),
501             device_state.read().unwrap().job_queue.clone(),
502             1,
503             EndpointDirection::HostToDevice,
504             EndpointType::Interrupt,
505         ));
506         // Endpoint 1 (IN)
507         endpoints.push(UsbEndpoint::new(
508             device_state.read().unwrap().fail_handle.clone(),
509             device_state.read().unwrap().job_queue.clone(),
510             1,
511             EndpointDirection::DeviceToHost,
512             EndpointType::Interrupt,
513         ));
514         device_state.write().unwrap().endpoints = endpoints;
515         Ok(())
516     }
517 }
518 
519 impl XhciBackendDevice for FidoPassthroughDevice {
get_backend_type(&self) -> BackendType520     fn get_backend_type(&self) -> BackendType {
521         BackendType::Usb2
522     }
523 
get_vid(&self) -> u16524     fn get_vid(&self) -> u16 {
525         // Google vendor ID
526         0x18d1
527     }
528 
get_pid(&self) -> u16529     fn get_pid(&self) -> u16 {
530         // Unique Product ID
531         0xf1d0
532     }
533 
set_address(&mut self, _address: UsbDeviceAddress)534     fn set_address(&mut self, _address: UsbDeviceAddress) {
535         // Nothing to do here
536     }
537 
reset(&mut self) -> BackendResult<()>538     fn reset(&mut self) -> BackendResult<()> {
539         let mut device_lock = self.device.lock();
540         device_lock.set_active(false);
541         device_lock.guest_key.lock().reset();
542         device_lock.transaction_manager.lock().reset();
543         Ok(())
544     }
545 
get_speed(&self) -> Option<DeviceSpeed>546     fn get_speed(&self) -> Option<DeviceSpeed> {
547         Some(DeviceSpeed::Full)
548     }
549 
alloc_streams(&self, _ep: u8, _num_streams: u16) -> BackendResult<()>550     fn alloc_streams(&self, _ep: u8, _num_streams: u16) -> BackendResult<()> {
551         // FIDO devices don't support bulk/streams so we ignore this request.
552         Ok(())
553     }
554 
free_streams(&self, _ep: u8) -> BackendResult<()>555     fn free_streams(&self, _ep: u8) -> BackendResult<()> {
556         // FIDO devices don't support bulk/streams so we ignore this request.
557         Ok(())
558     }
559 
stop(&mut self)560     fn stop(&mut self) {
561         // Transition the FIDO device into inactive mode and mark device as lost.
562         // The FIDO device cannot error on reset so we can unwrap safely.
563         self.reset().unwrap();
564         self.device.lock().is_device_lost = true;
565     }
566 }
567