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