Skip to main content

trouble_host/
connection_manager.rs

1use core::cell::RefCell;
2use core::future::poll_fn;
3#[cfg(feature = "security")]
4use core::future::Future;
5use core::task::{Context, Poll};
6
7use bt_hci::param::{AddrKind, BdAddr, ConnHandle, DisconnectReason, LeConnRole, Status};
8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
9use embassy_sync::channel::Channel;
10use embassy_sync::waitqueue::WakerRegistration;
11#[cfg(feature = "security")]
12use embassy_time::TimeoutError;
13
14use crate::connection::{ConnParams, Connection, ConnectionEvent, SecurityLevel};
15use crate::host::EventHandler;
16use crate::pdu::Pdu;
17use crate::prelude::sar::PacketReassembly;
18#[cfg(feature = "security")]
19use crate::security_manager::{SecurityEventData, SecurityManager};
20use crate::{config, Address, Error, Identity, PacketPool};
21
22struct State<'d, P> {
23    connections: &'d mut [ConnectionStorage<P>],
24    central_waker: WakerRegistration,
25    peripheral_waker: WakerRegistration,
26    disconnect_waker: WakerRegistration,
27    default_link_credits: usize,
28    default_att_mtu: u16,
29}
30
31impl<P> State<'_, P> {
32    fn print(&self, verbose: bool) {
33        for (idx, storage) in self.connections.iter().enumerate() {
34            if verbose || storage.state != ConnectionState::Disconnected {
35                debug!("[link][idx = {}] state = {:?}", idx, storage);
36            }
37        }
38    }
39
40    fn inc_ref(&mut self, index: u8) {
41        let state = &mut self.connections[index as usize];
42        state.refcount = unwrap!(
43            state.refcount.checked_add(1),
44            "Too many references to the same connection"
45        );
46    }
47}
48
49type EventChannel = Channel<NoopRawMutex, ConnectionEvent, { config::CONNECTION_EVENT_QUEUE_SIZE }>;
50type GattChannel<P> = Channel<NoopRawMutex, Pdu<P>, { config::L2CAP_RX_QUEUE_SIZE }>;
51
52pub(crate) struct ConnectionManager<'d, P: PacketPool> {
53    state: RefCell<State<'d, P::Packet>>,
54    outbound: Channel<NoopRawMutex, (ConnHandle, Pdu<P::Packet>), { config::L2CAP_TX_QUEUE_SIZE }>,
55    #[cfg(feature = "security")]
56    pub(crate) security_manager: SecurityManager<{ crate::BI_COUNT }>,
57}
58
59impl<'d, P: PacketPool> ConnectionManager<'d, P> {
60    pub(crate) fn new(connections: &'d mut [ConnectionStorage<P::Packet>], default_att_mtu: u16) -> Self {
61        Self {
62            state: RefCell::new(State {
63                connections,
64                central_waker: WakerRegistration::new(),
65                peripheral_waker: WakerRegistration::new(),
66                disconnect_waker: WakerRegistration::new(),
67                default_link_credits: 0,
68                default_att_mtu,
69            }),
70            outbound: Channel::new(),
71            #[cfg(feature = "security")]
72            security_manager: SecurityManager::new(),
73        }
74    }
75
76    pub(crate) fn role(&self, index: u8) -> LeConnRole {
77        self.with_mut(|state| {
78            let state = &mut state.connections[index as usize];
79            state.role.unwrap()
80        })
81    }
82
83    pub(crate) fn handle(&self, index: u8) -> ConnHandle {
84        self.with_mut(|state| {
85            let state = &mut state.connections[index as usize];
86            state.handle.unwrap()
87        })
88    }
89
90    pub(crate) fn is_connected(&self, index: u8) -> bool {
91        self.with_mut(|state| {
92            let state = &mut state.connections[index as usize];
93            state.state == ConnectionState::Connected
94        })
95    }
96
97    pub(crate) async fn next(&self, index: u8) -> ConnectionEvent {
98        poll_fn(|cx| self.with_mut(|state| state.connections[index as usize].events.poll_receive(cx))).await
99    }
100
101    #[cfg(feature = "gatt")]
102    pub(crate) async fn next_gatt(&self, index: u8) -> Pdu<P::Packet> {
103        poll_fn(|cx| self.with_mut(|state| state.connections[index as usize].gatt.poll_receive(cx))).await
104    }
105
106    pub(crate) async fn post_event(&self, index: u8, event: ConnectionEvent) {
107        poll_fn(|cx| self.with_mut(|state| state.connections[index as usize].events.poll_ready_to_send(cx))).await;
108        self.with_mut(|state| state.connections[index as usize].events.try_send(event).unwrap());
109    }
110
111    pub(crate) fn post_handle_event(&self, handle: ConnHandle, event: ConnectionEvent) -> Result<(), Error> {
112        self.with_mut(|state| {
113            for entry in state.connections.iter_mut() {
114                if entry.state == ConnectionState::Connected && Some(handle) == entry.handle {
115                    if let ConnectionEvent::ConnectionParamsUpdated {
116                        conn_interval,
117                        peripheral_latency,
118                        supervision_timeout,
119                    } = event
120                    {
121                        entry.params = ConnParams {
122                            conn_interval,
123                            peripheral_latency,
124                            supervision_timeout,
125                        }
126                    }
127
128                    entry.events.try_send(event).map_err(|_| Error::OutOfMemory)?;
129                    return Ok(());
130                }
131            }
132            Err(Error::NotFound)
133        })
134    }
135
136    #[cfg(feature = "gatt")]
137    pub(crate) fn post_gatt(&self, handle: ConnHandle, pdu: Pdu<P::Packet>) -> Result<(), Error> {
138        self.with_mut(|state| {
139            for entry in state.connections.iter() {
140                if entry.state == ConnectionState::Connected && Some(handle) == entry.handle {
141                    entry.gatt.try_send(pdu).map_err(|_| Error::OutOfMemory)?;
142                    return Ok(());
143                }
144            }
145            Err(Error::NotFound)
146        })
147    }
148
149    #[cfg(feature = "gatt")]
150    pub(crate) fn post_gatt_client(&self, handle: ConnHandle, pdu: Pdu<P::Packet>) -> Result<(), Error> {
151        self.with_mut(|state| {
152            for entry in state.connections.iter() {
153                if entry.state == ConnectionState::Connected && Some(handle) == entry.handle {
154                    entry.gatt_client.try_send(pdu).map_err(|_| Error::OutOfMemory)?;
155                    return Ok(());
156                }
157            }
158            Err(Error::NotFound)
159        })
160    }
161
162    #[cfg(feature = "gatt")]
163    pub(crate) async fn next_gatt_client(&self, index: u8) -> Pdu<P::Packet> {
164        poll_fn(|cx| self.with_mut(|state| state.connections[index as usize].gatt_client.poll_receive(cx))).await
165    }
166
167    pub(crate) fn peer_addr_kind(&self, index: u8) -> AddrKind {
168        self.with_mut(|state| {
169            let state = &mut state.connections[index as usize];
170            state.peer_addr_kind.unwrap_or_default()
171        })
172    }
173
174    pub(crate) fn peer_address(&self, index: u8) -> BdAddr {
175        self.with_mut(|state| {
176            let state = &mut state.connections[index as usize];
177            match state.peer_identity {
178                Some(identity) => identity.bd_addr, // TODO: If irk is used, this addr might be outdated.
179                _ => BdAddr::default(),
180            }
181        })
182    }
183
184    pub(crate) fn peer_identity(&self, index: u8) -> Identity {
185        self.with_mut(|state| {
186            let state = &mut state.connections[index as usize];
187            state.peer_identity.unwrap()
188        })
189    }
190
191    pub(crate) fn params(&self, index: u8) -> ConnParams {
192        self.with_mut(|state| {
193            let state = &mut state.connections[index as usize];
194            state.params
195        })
196    }
197
198    pub(crate) fn set_att_mtu(&self, index: u8, mtu: u16) {
199        self.with_mut(|state| {
200            state.connections[index as usize].att_mtu = mtu;
201        })
202    }
203
204    pub(crate) fn request_disconnect(&self, index: u8, reason: DisconnectReason) {
205        self.with_mut(|state| {
206            let entry = &mut state.connections[index as usize];
207            if entry.state == ConnectionState::Connected {
208                entry.state = ConnectionState::DisconnectRequest(reason);
209                state.disconnect_waker.wake();
210            }
211        })
212    }
213
214    pub(crate) fn request_handle_disconnect(&self, handle: ConnHandle, reason: DisconnectReason) {
215        self.with_mut(|state| {
216            for entry in state.connections.iter_mut() {
217                if entry.state == ConnectionState::Connected && Some(handle) == entry.handle {
218                    entry.state = ConnectionState::DisconnectRequest(reason);
219                    state.disconnect_waker.wake();
220                    break;
221                }
222            }
223        })
224    }
225
226    pub(crate) fn poll_disconnecting<'m>(
227        &'m self,
228        cx: Option<&mut Context<'_>>,
229    ) -> Poll<DisconnectRequest<'m, 'd, P::Packet>> {
230        let mut state = self.state.borrow_mut();
231        if let Some(cx) = cx {
232            state.disconnect_waker.register(cx.waker());
233        }
234        for (idx, storage) in state.connections.iter().enumerate() {
235            if let ConnectionState::DisconnectRequest(reason) = storage.state {
236                return Poll::Ready(DisconnectRequest {
237                    index: idx,
238                    handle: storage.handle.unwrap(),
239                    reason,
240                    state: &self.state,
241                });
242            }
243        }
244        Poll::Pending
245    }
246
247    pub(crate) fn get_connected_handle(&'d self, h: ConnHandle) -> Option<Connection<'d, P>> {
248        let mut state = self.state.borrow_mut();
249        for (index, storage) in state.connections.iter().enumerate() {
250            match (storage.handle, &storage.state) {
251                (Some(handle), ConnectionState::Connected) if handle == h => {
252                    state.inc_ref(index as u8);
253                    return Some(Connection::new(index as u8, self));
254                }
255                _ => {}
256            }
257        }
258        None
259    }
260
261    pub(crate) fn get_connection_by_peer_address(&'d self, peer_address: Address) -> Option<Connection<'d, P>> {
262        let mut state = self.state.borrow_mut();
263        for (index, storage) in state.connections.iter().enumerate() {
264            if storage.state == ConnectionState::Connected && storage.peer_addr_kind == Some(peer_address.kind) {
265                if let Some(peer) = &storage.peer_identity {
266                    if peer.match_address(&peer_address.addr) {
267                        state.inc_ref(index as u8);
268                        return Some(Connection::new(index as u8, self));
269                    }
270                }
271            }
272        }
273        None
274    }
275
276    pub(crate) fn with_connected_handle<F: FnOnce(&mut ConnectionStorage<P::Packet>) -> Result<R, Error>, R>(
277        &self,
278        h: ConnHandle,
279        f: F,
280    ) -> Result<R, Error> {
281        let mut state = self.state.borrow_mut();
282        for storage in state.connections.iter_mut() {
283            match (storage.handle, &storage.state) {
284                (Some(handle), ConnectionState::Connected) if handle == h => {
285                    return f(storage);
286                }
287                (Some(handle), ConnectionState::Connecting) if handle == h => {
288                    return f(storage);
289                }
290                _ => {}
291            }
292        }
293        Err(Error::Disconnected)
294    }
295
296    pub(crate) fn received(&self, h: ConnHandle) -> Result<(), Error> {
297        self.with_connected_handle(h, |storage| {
298            #[cfg(feature = "connection-metrics")]
299            storage.metrics.received(1);
300            Ok(())
301        })
302    }
303
304    pub(crate) fn is_handle_connected(&self, h: ConnHandle) -> bool {
305        self.with_connected_handle(h, |_storage| Ok(())).is_ok()
306    }
307
308    pub(crate) fn reassembly<F: FnOnce(&mut PacketReassembly<P::Packet>) -> Result<R, Error>, R>(
309        &self,
310        h: ConnHandle,
311        f: F,
312    ) -> Result<R, Error> {
313        self.with_connected_handle(h, |storage| f(&mut storage.reassembly))
314    }
315
316    pub(crate) fn disconnected(&self, h: ConnHandle, reason: Status) -> Result<(), Error> {
317        let mut state = self.state.borrow_mut();
318        for (idx, storage) in state.connections.iter_mut().enumerate() {
319            if Some(h) == storage.handle && storage.state != ConnectionState::Disconnected {
320                storage.state = ConnectionState::Disconnected;
321                storage.reassembly.clear();
322                let _ = storage.events.try_send(ConnectionEvent::Disconnected { reason });
323                #[cfg(feature = "gatt")]
324                storage.gatt.clear();
325                #[cfg(feature = "connection-metrics")]
326                storage.metrics.reset();
327                #[cfg(feature = "security")]
328                {
329                    storage.security_level = SecurityLevel::NoEncryption;
330                    storage.bondable = false;
331                    let _ = self.security_manager.disconnect(h, storage.peer_identity);
332                }
333                return Ok(());
334            }
335        }
336        warn!("[link][disconnect] connection handle {:?} not found", h);
337        Err(Error::NotFound)
338    }
339
340    pub(crate) fn connect(
341        &self,
342        handle: ConnHandle,
343        peer_addr_kind: AddrKind,
344        peer_addr: BdAddr,
345        role: LeConnRole,
346        params: ConnParams,
347    ) -> Result<(), Error> {
348        let mut state = self.state.borrow_mut();
349        let default_credits = state.default_link_credits;
350        let default_att_mtu = state.default_att_mtu;
351        for (idx, storage) in state.connections.iter_mut().enumerate() {
352            if ConnectionState::Disconnected == storage.state && storage.refcount == 0 {
353                storage.events.clear();
354                storage.reassembly.clear();
355                storage.state = ConnectionState::Connecting;
356                storage.link_credits = default_credits;
357                // Default ATT MTU is 23
358                storage.att_mtu = 23;
359                storage.handle.replace(handle);
360                storage.peer_addr_kind.replace(peer_addr_kind);
361                storage.peer_identity.replace(Identity {
362                    bd_addr: peer_addr,
363                    #[cfg(feature = "security")]
364                    irk: None,
365                });
366                storage.role.replace(role);
367                storage.params = params;
368
369                match role {
370                    LeConnRole::Central => {
371                        state.central_waker.wake();
372                    }
373                    LeConnRole::Peripheral => {
374                        state.peripheral_waker.wake();
375                    }
376                }
377                return Ok(());
378            }
379        }
380        warn!("[link][connect] no available slot found for handle {:?}", handle);
381        Err(Error::NotFound)
382    }
383
384    pub(crate) fn poll_accept(
385        &'d self,
386        role: LeConnRole,
387        peers: &[(AddrKind, &BdAddr)],
388        cx: Option<&mut Context<'_>>,
389    ) -> Poll<Connection<'d, P>> {
390        let mut state = self.state.borrow_mut();
391        if let Some(cx) = cx {
392            match role {
393                LeConnRole::Central => {
394                    state.central_waker.register(cx.waker());
395                }
396                LeConnRole::Peripheral => {
397                    state.peripheral_waker.register(cx.waker());
398                }
399            }
400        }
401        for (idx, storage) in state.connections.iter_mut().enumerate() {
402            if let ConnectionState::Connecting = storage.state {
403                let handle = storage.handle.unwrap();
404                let r = storage.role.unwrap();
405                if r == role {
406                    if !peers.is_empty() {
407                        for peer in peers.iter() {
408                            // TODO: Accept advertsing peers which use IRK
409                            if storage.peer_addr_kind.unwrap() == peer.0
410                                && storage.peer_identity.unwrap().bd_addr == *peer.1
411                            {
412                                storage.state = ConnectionState::Connected;
413                                debug!("[link][poll_accept] connection accepted: state: {:?}", storage);
414                                assert_eq!(storage.refcount, 0);
415                                state.inc_ref(idx as u8);
416                                return Poll::Ready(Connection::new(idx as u8, self));
417                            }
418                        }
419                    } else {
420                        storage.state = ConnectionState::Connected;
421                        assert_eq!(storage.refcount, 0);
422                        debug!("[link][poll_accept] connection accepted: state: {:?}", storage);
423
424                        assert_eq!(storage.refcount, 0);
425                        state.inc_ref(idx as u8);
426                        return Poll::Ready(Connection::new(idx as u8, self));
427                    }
428                }
429            }
430        }
431        Poll::Pending
432    }
433
434    fn with_mut<F: FnOnce(&mut State<'d, P::Packet>) -> R, R>(&self, f: F) -> R {
435        let mut state = self.state.borrow_mut();
436        f(&mut state)
437    }
438
439    pub(crate) fn log_status(&self, verbose: bool) {
440        let state = self.state.borrow();
441        state.print(verbose);
442    }
443
444    pub(crate) fn inc_ref(&self, index: u8) {
445        self.with_mut(|state| {
446            state.inc_ref(index);
447        });
448    }
449
450    pub(crate) fn dec_ref(&self, index: u8) {
451        self.with_mut(|state| {
452            let conn = &mut state.connections[index as usize];
453            conn.refcount = unwrap!(
454                conn.refcount.checked_sub(1),
455                "bug: dropping a connection with refcount 0"
456            );
457            if conn.refcount == 0 && conn.state == ConnectionState::Connected {
458                conn.state = ConnectionState::DisconnectRequest(DisconnectReason::RemoteUserTerminatedConn);
459                state.disconnect_waker.wake();
460            }
461        });
462    }
463
464    pub(crate) async fn accept(&'d self, role: LeConnRole, peers: &[(AddrKind, &BdAddr)]) -> Connection<'d, P> {
465        poll_fn(|cx| self.poll_accept(role, peers, Some(cx))).await
466    }
467
468    pub(crate) fn set_link_credits(&self, credits: usize) {
469        let mut state = self.state.borrow_mut();
470        state.default_link_credits = credits;
471        for storage in state.connections.iter_mut() {
472            storage.link_credits = credits;
473        }
474    }
475
476    pub(crate) fn set_default_att_mtu(&self, att_mtu: u16) {
477        let mut state = self.state.borrow_mut();
478        state.default_att_mtu = att_mtu;
479    }
480
481    pub(crate) fn confirm_sent(&self, handle: ConnHandle, packets: usize) -> Result<(), Error> {
482        let mut state = self.state.borrow_mut();
483        for storage in state.connections.iter_mut() {
484            match storage.state {
485                ConnectionState::Connected if handle == storage.handle.unwrap() => {
486                    storage.link_credits += packets;
487                    storage.link_credit_waker.wake();
488                    return Ok(());
489                }
490                _ => {}
491            }
492        }
493        Err(Error::NotFound)
494    }
495
496    pub(crate) fn poll_request_to_send(
497        &self,
498        handle: ConnHandle,
499        packets: usize,
500        cx: Option<&mut Context<'_>>,
501    ) -> Poll<Result<PacketGrant<'_, 'd, P::Packet>, Error>> {
502        let mut state = self.state.borrow_mut();
503        for storage in state.connections.iter_mut() {
504            match storage.state {
505                ConnectionState::Connected if storage.handle.unwrap() == handle => {
506                    if packets <= storage.link_credits {
507                        storage.link_credits -= packets;
508
509                        return Poll::Ready(Ok(PacketGrant::new(&self.state, handle, packets)));
510                    } else {
511                        if let Some(cx) = cx {
512                            storage.link_credit_waker.register(cx.waker());
513                        }
514                        #[cfg(feature = "connection-metrics")]
515                        storage.metrics.blocked_send();
516
517                        return Poll::Pending;
518                    }
519                }
520                _ => {}
521            }
522        }
523        warn!("[link][pool_request_to_send] connection {:?} not found", handle);
524        Poll::Ready(Err(Error::NotFound))
525    }
526
527    pub(crate) fn get_att_mtu(&self, index: u8) -> u16 {
528        self.with_mut(|state| state.connections[index as usize].att_mtu)
529    }
530
531    pub(crate) async fn send(&self, index: u8, pdu: Pdu<P::Packet>) {
532        let handle = self.with_mut(|state| state.connections[index as usize].handle.unwrap());
533        self.outbound.send((handle, pdu)).await
534    }
535
536    pub(crate) fn try_send(&self, index: u8, pdu: Pdu<P::Packet>) -> Result<(), Error> {
537        let handle = self.with_mut(|state| state.connections[index as usize].handle.unwrap());
538        self.outbound.try_send((handle, pdu)).map_err(|_| Error::OutOfMemory)
539    }
540
541    pub(crate) fn try_outbound(&self, handle: ConnHandle, pdu: Pdu<P::Packet>) -> Result<(), Error> {
542        self.outbound.try_send((handle, pdu)).map_err(|_| Error::OutOfMemory)
543    }
544
545    pub(crate) async fn outbound(&self) -> (ConnHandle, Pdu<P::Packet>) {
546        self.outbound.receive().await
547    }
548
549    pub(crate) fn get_att_mtu_handle(&self, conn: ConnHandle) -> u16 {
550        let mut state = self.state.borrow_mut();
551        for storage in state.connections.iter_mut() {
552            match storage.state {
553                ConnectionState::Connected if storage.handle.unwrap() == conn => {
554                    return storage.att_mtu;
555                }
556                _ => {}
557            }
558        }
559        state.default_att_mtu
560    }
561
562    pub(crate) fn exchange_att_mtu(&self, conn: ConnHandle, mtu: u16) -> u16 {
563        let mut state = self.state.borrow_mut();
564        debug!("exchange_att_mtu: {}, current default: {}", mtu, state.default_att_mtu);
565        let default_att_mtu = state.default_att_mtu;
566        for storage in state.connections.iter_mut() {
567            match storage.state {
568                ConnectionState::Connected if storage.handle.unwrap() == conn => {
569                    storage.att_mtu = default_att_mtu.min(mtu);
570                    return storage.att_mtu;
571                }
572                _ => {}
573            }
574        }
575        mtu
576    }
577
578    pub(crate) fn pass_key_confirm(&self, index: u8, confirm: bool) -> Result<(), Error> {
579        #[cfg(feature = "security")]
580        {
581            if self.state.borrow_mut().connections[index as usize].state == ConnectionState::Connected {
582                self.security_manager.handle_pass_key_confirm(
583                    confirm,
584                    self,
585                    &self.state.borrow().connections[index as usize],
586                )
587            } else {
588                Err(Error::Disconnected)
589            }
590        }
591        #[cfg(not(feature = "security"))]
592        Err(Error::NotSupported)
593    }
594
595    pub(crate) fn pass_key_input(&self, index: u8, pass_key: u32) -> Result<(), Error> {
596        #[cfg(feature = "security")]
597        {
598            if self.state.borrow_mut().connections[index as usize].state == ConnectionState::Connected {
599                self.security_manager.handle_pass_key_input(
600                    pass_key,
601                    self,
602                    &self.state.borrow().connections[index as usize],
603                )
604            } else {
605                Err(Error::Disconnected)
606            }
607        }
608        #[cfg(not(feature = "security"))]
609        Err(Error::NotSupported)
610    }
611
612    pub(crate) fn request_security(&self, index: u8) -> Result<(), Error> {
613        #[cfg(feature = "security")]
614        {
615            let current_level = self.get_security_level(index)?;
616            if current_level != SecurityLevel::NoEncryption {
617                return Err(Error::NotSupported);
618            }
619            self.security_manager
620                .initiate(self, &self.state.borrow().connections[index as usize])
621        }
622        #[cfg(not(feature = "security"))]
623        Err(Error::NotSupported)
624    }
625
626    pub(crate) fn get_security_level(&self, index: u8) -> Result<SecurityLevel, Error> {
627        let state = self.state.borrow();
628        match state.connections[index as usize].state {
629            ConnectionState::Connected => {
630                #[cfg(feature = "security")]
631                {
632                    Ok(state.connections[index as usize].security_level)
633                }
634                #[cfg(not(feature = "security"))]
635                Ok(SecurityLevel::NoEncryption)
636            }
637            _ => Err(Error::Disconnected),
638        }
639    }
640
641    pub(crate) fn get_bondable(&self, index: u8) -> Result<bool, Error> {
642        let state = self.state.borrow();
643        match state.connections[index as usize].state {
644            ConnectionState::Connected => {
645                #[cfg(feature = "security")]
646                {
647                    Ok(state.connections[index as usize].bondable)
648                }
649                #[cfg(not(feature = "security"))]
650                Ok(false)
651            }
652            _ => Err(Error::Disconnected),
653        }
654    }
655
656    pub(crate) fn set_bondable(&self, index: u8, bondable: bool) -> Result<(), Error> {
657        #[cfg(feature = "security")]
658        {
659            let mut state = self.state.borrow_mut();
660            match state.connections[index as usize].state {
661                ConnectionState::Connected => {
662                    state.connections[index as usize].bondable = bondable;
663                    Ok(())
664                }
665                _ => Err(Error::Disconnected),
666            }
667        }
668        #[cfg(not(feature = "security"))]
669        Err(Error::NotSupported)
670    }
671
672    pub(crate) fn handle_security_channel(
673        &self,
674        handle: ConnHandle,
675        pdu: Pdu<P::Packet>,
676        event_handler: &dyn EventHandler,
677    ) -> Result<(), Error> {
678        #[cfg(feature = "security")]
679        {
680            let state = self.state.borrow();
681            for storage in state.connections.iter() {
682                match storage.state {
683                    ConnectionState::Connected if storage.handle.unwrap() == handle => {
684                        if let Err(error) = self.security_manager.handle_l2cap_command(pdu, self, storage) {
685                            error!("Failed to handle security manager packet, {:?}", error);
686                            return Err(error);
687                        }
688                        break;
689                    }
690                    _ => (),
691                }
692            }
693        }
694        Ok(())
695    }
696
697    pub(crate) fn handle_security_hci_event(&self, event: bt_hci::event::EventPacket) -> Result<(), Error> {
698        #[cfg(feature = "security")]
699        {
700            self.security_manager.handle_hci_event(event, self)?;
701        }
702        Ok(())
703    }
704
705    pub(crate) fn handle_security_hci_le_event(&self, event: bt_hci::event::le::LeEventPacket) -> Result<(), Error> {
706        #[cfg(feature = "security")]
707        {
708            self.security_manager.handle_hci_le_event(event, self)?;
709        }
710        Ok(())
711    }
712
713    #[cfg(feature = "security")]
714    pub(crate) async fn handle_security_event<'h, C>(
715        &self,
716        host: &crate::host::BleHost<'h, C, P>,
717        _event: crate::security_manager::SecurityEventData,
718    ) -> Result<(), crate::BleHostError<C::Error>>
719    where
720        C: crate::ControllerCmdSync<bt_hci::cmd::le::LeLongTermKeyRequestReply>
721            + crate::ControllerCmdAsync<bt_hci::cmd::le::LeEnableEncryption>
722            + crate::ControllerCmdSync<bt_hci::cmd::link_control::Disconnect>,
723    {
724        use bt_hci::cmd::le::{LeEnableEncryption, LeLongTermKeyRequestReply};
725        use bt_hci::cmd::link_control::Disconnect;
726
727        match _event {
728            crate::security_manager::SecurityEventData::SendLongTermKey(handle) => {
729                let conn_info = self.state.borrow().connections.iter().find_map(|connection| {
730                    match (connection.handle, connection.peer_identity) {
731                        (Some(connection_handle), Some(identity)) => {
732                            if handle == connection_handle {
733                                Some((connection_handle, identity))
734                            } else {
735                                None
736                            }
737                        }
738                        (_, _) => None,
739                    }
740                });
741
742                if let Some((conn, identity)) = conn_info {
743                    if let Some(ltk) = self.security_manager.get_peer_long_term_key(&identity) {
744                        let _ = host
745                            .command(LeLongTermKeyRequestReply::new(handle, ltk.to_le_bytes()))
746                            .await?;
747                    } else {
748                        warn!("[host] Long term key request reply failed, no long term key");
749                        // Send disconnect event to the controller
750                        host.command(Disconnect::new(conn, DisconnectReason::AuthenticationFailure))
751                            .await?;
752                        unwrap!(self.disconnected(conn, Status::AUTHENTICATION_FAILURE));
753                    }
754                } else {
755                    warn!("[host] Long term key request reply failed, unknown peer")
756                }
757            }
758            crate::security_manager::SecurityEventData::EnableEncryption(handle, bond_info) => {
759                let connection_data =
760                    self.state
761                        .borrow()
762                        .connections
763                        .iter()
764                        .enumerate()
765                        .find_map(
766                            |(index, connection)| match (connection.handle, connection.peer_identity) {
767                                (Some(connection_handle), Some(identity)) => {
768                                    if handle == connection_handle {
769                                        Some((index, connection.role, identity))
770                                    } else {
771                                        None
772                                    }
773                                }
774                                (_, _) => None,
775                            },
776                        );
777                if let Some((index, role, identity)) = connection_data {
778                    if let Some(ltk) = self.security_manager.get_peer_long_term_key(&identity) {
779                        if let Some(LeConnRole::Central) = role {
780                            host.async_command(LeEnableEncryption::new(handle, [0; 8], 0, ltk.to_le_bytes()))
781                                .await?;
782                        }
783                    } else {
784                        warn!("[host] Enable encryption failed, no long term key")
785                    }
786                } else {
787                    warn!("[host] Enable encryption failed, unknown peer")
788                }
789            }
790            crate::security_manager::SecurityEventData::Timeout => {
791                warn!("[host] Pairing timeout");
792                self.security_manager.cancel_timeout();
793            }
794            crate::security_manager::SecurityEventData::TimerChange => (),
795        }
796        Ok(())
797    }
798
799    #[cfg(feature = "security")]
800    pub(crate) fn poll_security_events(
801        &self,
802    ) -> impl Future<Output = Result<SecurityEventData, TimeoutError>> + use<'_, P> {
803        self.security_manager.poll_events()
804    }
805
806    #[cfg(feature = "connection-metrics")]
807    pub(crate) fn metrics<F: FnOnce(&Metrics) -> R, R>(&self, index: u8, f: F) -> R {
808        self.with_mut(|state| {
809            let state = &state.connections[index as usize];
810            f(&state.metrics)
811        })
812    }
813}
814
815pub struct DisconnectRequest<'a, 'd, P> {
816    index: usize,
817    handle: ConnHandle,
818    reason: DisconnectReason,
819    state: &'a RefCell<State<'d, P>>,
820}
821
822impl<P> DisconnectRequest<'_, '_, P> {
823    pub fn handle(&self) -> ConnHandle {
824        self.handle
825    }
826
827    pub fn reason(&self) -> DisconnectReason {
828        self.reason
829    }
830
831    pub fn confirm(self) {
832        let mut state = self.state.borrow_mut();
833        state.connections[self.index].state = ConnectionState::Disconnecting(self.reason);
834    }
835}
836pub struct ConnectionStorage<P> {
837    pub state: ConnectionState,
838    pub handle: Option<ConnHandle>,
839    pub role: Option<LeConnRole>,
840    pub peer_addr_kind: Option<AddrKind>,
841    pub peer_identity: Option<Identity>,
842    pub params: ConnParams,
843    pub att_mtu: u16,
844    pub link_credits: usize,
845    pub link_credit_waker: WakerRegistration,
846    pub refcount: u8,
847    #[cfg(feature = "connection-metrics")]
848    pub metrics: Metrics,
849    #[cfg(feature = "security")]
850    pub security_level: SecurityLevel,
851    #[cfg(feature = "security")]
852    pub bondable: bool,
853    pub events: EventChannel,
854    pub reassembly: PacketReassembly<P>,
855    #[cfg(feature = "gatt")]
856    pub gatt: GattChannel<P>,
857    #[cfg(feature = "gatt")]
858    pub(crate) gatt_client: GattChannel<P>,
859}
860
861/// Connection metrics
862#[cfg(feature = "connection-metrics")]
863#[derive(Debug)]
864pub struct Metrics {
865    /// Number of ACL packets sent for this connection.
866    pub num_sent: usize,
867    /// Number of ACL packets received on this connection.
868    pub num_received: usize,
869    /// Time of last sent packet.
870    pub last_sent: embassy_time::Instant,
871    /// Time of last received packet.
872    pub last_received: embassy_time::Instant,
873    /// Number of times a sender was blocked from sending.
874    pub blocked_sends: usize,
875}
876
877#[cfg(feature = "connection-metrics")]
878impl Metrics {
879    pub(crate) const fn new() -> Self {
880        Self {
881            num_sent: 0,
882            num_received: 0,
883            last_sent: embassy_time::Instant::MIN,
884            last_received: embassy_time::Instant::MIN,
885            blocked_sends: 0,
886        }
887    }
888    pub(crate) fn sent(&mut self, num: usize) {
889        self.num_sent = self.num_sent.wrapping_add(num);
890        self.last_sent = embassy_time::Instant::now();
891    }
892
893    pub(crate) fn received(&mut self, num: usize) {
894        self.num_received = self.num_received.wrapping_add(num);
895        self.last_received = embassy_time::Instant::now();
896    }
897
898    pub(crate) fn blocked_send(&mut self) {
899        self.blocked_sends = self.blocked_sends.wrapping_add(1);
900    }
901
902    pub(crate) fn reset(&mut self) {
903        *self = Self::new();
904    }
905}
906
907#[cfg(feature = "connection-metrics")]
908#[cfg(feature = "defmt")]
909impl defmt::Format for Metrics {
910    fn format(&self, f: defmt::Formatter<'_>) {
911        defmt::write!(
912            f,
913            "sent = {}, since_sent = {} ms, recvd = {}, since_recvd = {} ms, blocked sends = {}",
914            self.num_sent,
915            self.last_sent.elapsed().as_millis(),
916            self.num_received,
917            self.last_received.elapsed().as_millis(),
918            self.blocked_sends,
919        );
920    }
921}
922
923impl<P> ConnectionStorage<P> {
924    pub(crate) const fn new() -> ConnectionStorage<P> {
925        ConnectionStorage {
926            state: ConnectionState::Disconnected,
927            handle: None,
928            role: None,
929            peer_addr_kind: None,
930            peer_identity: None,
931            params: ConnParams::new(),
932            att_mtu: 23,
933            link_credits: 0,
934            link_credit_waker: WakerRegistration::new(),
935            refcount: 0,
936            #[cfg(feature = "connection-metrics")]
937            metrics: Metrics::new(),
938            #[cfg(feature = "security")]
939            security_level: SecurityLevel::NoEncryption,
940            events: EventChannel::new(),
941            #[cfg(feature = "gatt")]
942            gatt: GattChannel::new(),
943            #[cfg(feature = "gatt")]
944            gatt_client: GattChannel::new(),
945            reassembly: PacketReassembly::new(),
946            #[cfg(feature = "security")]
947            bondable: false,
948        }
949    }
950}
951
952impl<P> core::fmt::Debug for ConnectionStorage<P> {
953    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
954        let mut d = f.debug_struct("ConnectionStorage");
955        let d = d
956            .field("state", &self.state)
957            .field("handle", &self.handle)
958            .field("role", &self.role)
959            .field("peer_identity", &self.peer_identity)
960            .field("refcount", &self.refcount);
961        #[cfg(feature = "connection-metrics")]
962        let d = d.field("metrics", &self.metrics);
963        d.finish()
964    }
965}
966
967#[cfg(feature = "defmt")]
968impl<P> defmt::Format for ConnectionStorage<P> {
969    fn format(&self, f: defmt::Formatter<'_>) {
970        defmt::write!(
971            f,
972            "state = {}, conn = {}, flow = {}",
973            self.state,
974            self.handle,
975            self.link_credits,
976        );
977
978        defmt::write!(
979            f,
980            ", role = {}, peer = {}, ref = {}, sar = {}",
981            self.role,
982            self.peer_identity,
983            self.refcount,
984            self.reassembly,
985        );
986
987        #[cfg(feature = "connection-metrics")]
988        defmt::write!(f, ", {}", self.metrics);
989    }
990}
991
992#[derive(Debug, PartialEq)]
993#[cfg_attr(feature = "defmt", derive(defmt::Format))]
994pub enum ConnectionState {
995    DisconnectRequest(DisconnectReason),
996    Disconnecting(DisconnectReason),
997    Disconnected,
998    Connecting,
999    Connected,
1000}
1001
1002pub struct PacketGrant<'a, 'd, P> {
1003    state: &'a RefCell<State<'d, P>>,
1004    handle: ConnHandle,
1005    packets: usize,
1006}
1007
1008impl<'a, 'd, P> PacketGrant<'a, 'd, P> {
1009    fn new(state: &'a RefCell<State<'d, P>>, handle: ConnHandle, packets: usize) -> Self {
1010        Self { state, handle, packets }
1011    }
1012
1013    pub(crate) fn confirm(&mut self, sent: usize) {
1014        self.packets = self.packets.saturating_sub(sent);
1015        #[cfg(feature = "connection-metrics")]
1016        {
1017            let mut state = self.state.borrow_mut();
1018            for storage in state.connections.iter_mut() {
1019                match storage.state {
1020                    ConnectionState::Connected if self.handle == storage.handle.unwrap() => {
1021                        storage.metrics.sent(sent);
1022                        break;
1023                    }
1024                    _ => {}
1025                }
1026            }
1027        }
1028    }
1029}
1030
1031impl<P> Drop for PacketGrant<'_, '_, P> {
1032    fn drop(&mut self) {
1033        if self.packets > 0 {
1034            let mut state = self.state.borrow_mut();
1035            for storage in state.connections.iter_mut() {
1036                match storage.state {
1037                    ConnectionState::Connected if self.handle == storage.handle.unwrap() => {
1038                        storage.link_credits += self.packets;
1039                        storage.link_credit_waker.wake();
1040                        return;
1041                    }
1042                    _ => {}
1043                }
1044            }
1045            // make it an assert?
1046            warn!("[link] connection {:?} not found", self.handle);
1047        }
1048    }
1049}
1050
1051#[cfg(test)]
1052pub(crate) mod tests {
1053    use super::*;
1054    extern crate std;
1055
1056    use std::boxed::Box;
1057
1058    use embassy_futures::block_on;
1059
1060    use crate::prelude::*;
1061
1062    pub const ADDR_1: [u8; 6] = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
1063    pub const ADDR_2: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
1064
1065    pub fn setup() -> &'static ConnectionManager<'static, DefaultPacketPool> {
1066        let storage = Box::leak(Box::new([const { ConnectionStorage::new() }; 3]));
1067        let mgr = ConnectionManager::new(&mut storage[..], 23);
1068        Box::leak(Box::new(mgr))
1069    }
1070
1071    #[test]
1072    fn peripheral_connection_established() {
1073        let mgr = setup();
1074        assert!(mgr.poll_accept(LeConnRole::Peripheral, &[], None).is_pending());
1075
1076        unwrap!(mgr.connect(
1077            ConnHandle::new(0),
1078            AddrKind::RANDOM,
1079            BdAddr::new(ADDR_1),
1080            LeConnRole::Peripheral,
1081            ConnParams::new(),
1082        ));
1083
1084        let Poll::Ready(handle) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1085            panic!("expected connection to be accepted");
1086        };
1087        assert_eq!(handle.role(), LeConnRole::Peripheral);
1088        assert_eq!(handle.peer_address(), BdAddr::new(ADDR_1));
1089
1090        handle.disconnect();
1091    }
1092
1093    #[test]
1094    fn central_connection_established() {
1095        let mgr = setup();
1096
1097        assert!(mgr.poll_accept(LeConnRole::Central, &[], None).is_pending());
1098
1099        unwrap!(mgr.connect(
1100            ConnHandle::new(0),
1101            AddrKind::RANDOM,
1102            BdAddr::new(ADDR_2),
1103            LeConnRole::Central,
1104            ConnParams::new(),
1105        ));
1106
1107        let Poll::Ready(handle) = mgr.poll_accept(LeConnRole::Central, &[], None) else {
1108            panic!("expected connection to be accepted");
1109        };
1110        assert_eq!(handle.role(), LeConnRole::Central);
1111        assert_eq!(handle.peer_address(), BdAddr::new(ADDR_2));
1112    }
1113
1114    #[test]
1115    fn controller_disconnects_before_host() {
1116        let mgr = setup();
1117
1118        unwrap!(mgr.connect(
1119            ConnHandle::new(3),
1120            AddrKind::RANDOM,
1121            BdAddr::new(ADDR_1),
1122            LeConnRole::Central,
1123            ConnParams::new(),
1124        ));
1125
1126        unwrap!(mgr.connect(
1127            ConnHandle::new(2),
1128            AddrKind::RANDOM,
1129            BdAddr::new(ADDR_2),
1130            LeConnRole::Peripheral,
1131            ConnParams::new(),
1132        ));
1133
1134        let Poll::Ready(central) = mgr.poll_accept(LeConnRole::Central, &[], None) else {
1135            panic!("expected connection to be accepted");
1136        };
1137
1138        let Poll::Ready(peripheral) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1139            panic!("expected connection to be accepted");
1140        };
1141
1142        assert_eq!(ConnHandle::new(3), central.handle());
1143        assert_eq!(ConnHandle::new(2), peripheral.handle());
1144
1145        // Disconnect request from us
1146        peripheral.disconnect();
1147
1148        // Polling should return the disconnecting handle
1149        let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1150            panic!("expected connection to be accepted");
1151        };
1152
1153        // If nothing happens, polling should behave the same way
1154        let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1155            panic!("expected connection to be accepted");
1156        };
1157
1158        // Disconnection event from host arrives before we confirm
1159        unwrap!(mgr.disconnected(ConnHandle::new(2), Status::UNSPECIFIED));
1160
1161        // This should be a noop
1162        req.confirm();
1163
1164        // Polling should not return anything
1165        assert!(mgr.poll_disconnecting(None).is_pending());
1166    }
1167
1168    #[test]
1169    fn controller_disconnects_after_host() {
1170        let mgr = setup();
1171
1172        unwrap!(mgr.connect(
1173            ConnHandle::new(3),
1174            AddrKind::RANDOM,
1175            BdAddr::new(ADDR_1),
1176            LeConnRole::Central,
1177            ConnParams::new(),
1178        ));
1179
1180        unwrap!(mgr.connect(
1181            ConnHandle::new(2),
1182            AddrKind::RANDOM,
1183            BdAddr::new(ADDR_2),
1184            LeConnRole::Peripheral,
1185            ConnParams::new(),
1186        ));
1187
1188        let Poll::Ready(central) = mgr.poll_accept(LeConnRole::Central, &[], None) else {
1189            panic!("expected connection to be accepted");
1190        };
1191
1192        let Poll::Ready(peripheral) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1193            panic!("expected connection to be accepted");
1194        };
1195
1196        assert_eq!(ConnHandle::new(3), central.handle());
1197        assert_eq!(ConnHandle::new(2), peripheral.handle());
1198
1199        // Disconnect request from us
1200        peripheral.disconnect();
1201
1202        // Polling should return the disconnecting handle
1203        let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1204            panic!("expected connection to be accepted");
1205        };
1206
1207        // This should remove it from the list
1208        req.confirm();
1209
1210        // Polling should not return anything
1211        assert!(mgr.poll_disconnecting(None).is_pending());
1212
1213        // Disconnection event from host arrives before we confirm
1214        unwrap!(mgr.disconnected(ConnHandle::new(2), Status::UNSPECIFIED));
1215
1216        // Check that we get an event
1217        use crate::connection::ConnectionEvent;
1218        assert!(matches!(
1219            block_on(peripheral.next()),
1220            ConnectionEvent::Disconnected {
1221                reason: Status::UNSPECIFIED
1222            }
1223        ));
1224
1225        // Polling should not return anything
1226        assert!(mgr.poll_disconnecting(None).is_pending());
1227    }
1228
1229    #[test]
1230    fn referenced_handle_not_reused() {
1231        let mgr = setup();
1232
1233        assert!(mgr.poll_accept(LeConnRole::Peripheral, &[], None).is_pending());
1234
1235        let handle = ConnHandle::new(42);
1236        unwrap!(mgr.connect(
1237            handle,
1238            AddrKind::RANDOM,
1239            BdAddr::new(ADDR_1),
1240            LeConnRole::Peripheral,
1241            ConnParams::new()
1242        ));
1243
1244        let Poll::Ready(conn) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1245            panic!("expected connection to be accepted");
1246        };
1247        assert_eq!(conn.role(), LeConnRole::Peripheral);
1248        assert_eq!(conn.peer_address(), BdAddr::new(ADDR_1));
1249
1250        unwrap!(mgr.disconnected(handle, Status::UNSPECIFIED));
1251
1252        // New incoming connection reusing handle
1253        let handle = ConnHandle::new(42);
1254        unwrap!(mgr.connect(
1255            handle,
1256            AddrKind::RANDOM,
1257            BdAddr::new(ADDR_2),
1258            LeConnRole::Peripheral,
1259            ConnParams::new()
1260        ));
1261
1262        let Poll::Ready(conn2) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1263            panic!("expected connection to be accepted");
1264        };
1265
1266        // Ensure existing connection doesnt panic things
1267        assert_eq!(conn.handle(), ConnHandle::new(42));
1268        assert_eq!(conn.role(), LeConnRole::Peripheral);
1269        assert_eq!(conn.peer_address(), BdAddr::new(ADDR_1));
1270        assert!(!conn.is_connected());
1271
1272        assert_eq!(conn2.handle(), ConnHandle::new(42));
1273        assert_eq!(conn2.role(), LeConnRole::Peripheral);
1274        assert_eq!(conn2.peer_address(), BdAddr::new(ADDR_2));
1275        assert!(conn2.is_connected());
1276    }
1277
1278    #[test]
1279    fn disconnect_correct_handle() {
1280        let mgr = setup();
1281
1282        assert!(mgr.poll_accept(LeConnRole::Peripheral, &[], None).is_pending());
1283
1284        let handle = ConnHandle::new(42);
1285        unwrap!(mgr.connect(
1286            handle,
1287            AddrKind::RANDOM,
1288            BdAddr::new(ADDR_1),
1289            LeConnRole::Peripheral,
1290            ConnParams::new()
1291        ));
1292
1293        let Poll::Ready(conn) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1294            panic!("expected connection to be accepted");
1295        };
1296        assert_eq!(conn.role(), LeConnRole::Peripheral);
1297        assert_eq!(conn.peer_address(), BdAddr::new(ADDR_1));
1298
1299        unwrap!(mgr.disconnected(handle, Status::UNSPECIFIED));
1300
1301        // New incoming connection reusing handle
1302        let handle = ConnHandle::new(42);
1303        unwrap!(mgr.connect(
1304            handle,
1305            AddrKind::RANDOM,
1306            BdAddr::new(ADDR_2),
1307            LeConnRole::Peripheral,
1308            ConnParams::new()
1309        ));
1310
1311        let Poll::Ready(conn2) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1312            panic!("expected connection to be accepted");
1313        };
1314
1315        assert_eq!(conn2.handle(), ConnHandle::new(42));
1316        assert_eq!(conn2.role(), LeConnRole::Peripheral);
1317        assert_eq!(conn2.peer_address(), BdAddr::new(ADDR_2));
1318        assert!(conn2.is_connected());
1319
1320        unwrap!(mgr.disconnected(handle, Status::UNSPECIFIED));
1321
1322        assert!(!conn2.is_connected());
1323    }
1324
1325    #[test]
1326    fn disconnecting_iterator_invalid() {
1327        let mgr = setup();
1328
1329        assert!(mgr.poll_accept(LeConnRole::Peripheral, &[], None).is_pending());
1330
1331        unwrap!(mgr.connect(
1332            ConnHandle::new(3),
1333            AddrKind::RANDOM,
1334            BdAddr::new(ADDR_1),
1335            LeConnRole::Peripheral,
1336            ConnParams::new()
1337        ));
1338
1339        let Poll::Ready(handle) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1340            panic!("expected connection to be accepted");
1341        };
1342        assert_eq!(handle.role(), LeConnRole::Peripheral);
1343        assert_eq!(handle.peer_address(), BdAddr::new(ADDR_1));
1344
1345        assert!(mgr.poll_disconnecting(None).is_pending());
1346
1347        // Disconnect request from us
1348        drop(handle);
1349
1350        // Polling should return the disconnecting handle
1351        let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1352            panic!("expected connection to be accepted");
1353        };
1354
1355        //        unwrap!(mgr.disconnected(ConnHandle::new(3)));
1356
1357        req.confirm();
1358
1359        assert!(mgr.poll_disconnecting(None).is_pending());
1360    }
1361
1362    #[test]
1363    fn nonexisting_handle_is_disconnected() {
1364        let mgr = setup();
1365
1366        assert!(!mgr.is_handle_connected(ConnHandle::new(5)));
1367
1368        unwrap!(mgr.connect(
1369            ConnHandle::new(3),
1370            AddrKind::RANDOM,
1371            BdAddr::new(ADDR_1),
1372            LeConnRole::Peripheral,
1373            ConnParams::new()
1374        ));
1375
1376        assert!(mgr.is_handle_connected(ConnHandle::new(3)));
1377
1378        let Poll::Ready(handle) = mgr.poll_accept(LeConnRole::Peripheral, &[], None) else {
1379            panic!("expected connection to be accepted");
1380        };
1381
1382        assert!(mgr.is_handle_connected(ConnHandle::new(3)));
1383
1384        handle.disconnect();
1385
1386        assert!(!mgr.is_handle_connected(ConnHandle::new(3)));
1387    }
1388}