diff --git a/system/gd/rust/linux/mgmt/Cargo.toml b/system/gd/rust/linux/mgmt/Cargo.toml index 042b25b00177e91392908e2d1464d20ec92798c6..ca38dd178ff88a49c14da84c8321f49f5da5da60 100644 --- a/system/gd/rust/linux/mgmt/Cargo.toml +++ b/system/gd/rust/linux/mgmt/Cargo.toml @@ -32,6 +32,7 @@ regex = "1.5" serde_json = "1.0" syslog = "6" tokio = { version = "1.0", features = ["fs", "macros", "rt-multi-thread", "sync"] } +libc = "0.2" [build-dependencies] pkg-config = "0.3.19" diff --git a/system/gd/rust/linux/mgmt/src/state_machine.rs b/system/gd/rust/linux/mgmt/src/state_machine.rs index 8647c68e8df66c5fa94e43298931454083cf1086..e9de581723a16e6562a348a31a0704b271136e4f 100644 --- a/system/gd/rust/linux/mgmt/src/state_machine.rs +++ b/system/gd/rust/linux/mgmt/src/state_machine.rs @@ -5,6 +5,7 @@ use bt_utils::socket::{ BtSocket, HciChannels, MgmtCommand, MgmtCommandResponse, MgmtEvent, HCI_DEV_NONE, }; +use libc; use log::{debug, error, info, warn}; use nix::sys::signal::{self, Signal}; use nix::unistd::Pid; @@ -36,6 +37,10 @@ pub const INDEX_REMOVED_DEBOUNCE_TIME: Duration = Duration::from_millis(150); /// to avoid dead process + PID not cleaned up from happening. pub const PID_RUNNING_CHECK_PERIOD: Duration = Duration::from_secs(60); +const HCI_BIND_MAX_RETRY: i32 = 2; + +const HCI_BIND_RETRY_INTERVAL: Duration = Duration::from_millis(10); + #[derive(Debug, PartialEq, Copy, Clone)] #[repr(u32)] pub enum ProcessState { @@ -362,19 +367,37 @@ fn configure_hci(hci_tx: mpsc::Sender<Message>) { x => debug!("Socket open at fd: {}", x), } - // Bind to control channel (which is used for mgmt commands). We provide - // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands. - match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) { - -1 => { - panic!( - "Failed to bind control channel with errno={}", - std::io::Error::last_os_error().raw_os_error().unwrap_or(0) - ); + tokio::spawn(async move { + // Bind to control channel (which is used for mgmt commands). We provide + // HCI_DEV_NONE because we don't actually need a valid HCI dev for some MGMT commands. + let mut bind_succ = false; + for _i in 0..HCI_BIND_MAX_RETRY { + match btsock.bind_channel(HciChannels::Control, HCI_DEV_NONE) { + -1 => { + match std::io::Error::last_os_error().raw_os_error().unwrap_or(0) { + libc::EINVAL => { + // If MGMT hasn't been initialized EINVAL will be returned. + // Just wait for a short time and try again. + debug!("Got EINVAL in bind. Wait and try again"); + tokio::time::sleep(HCI_BIND_RETRY_INTERVAL).await; + continue; + } + others => { + panic!("Failed to bind control channel with errno={}", others); + } + } + } + _ => { + bind_succ = true; + break; + } + }; + } + + if !bind_succ { + panic!("bind failed too many times!!"); } - _ => (), - }; - tokio::spawn(async move { debug!("Spawned hci notify task"); // Make this into an AsyncFD and start using it for IO