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, _ => 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 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 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 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#[cfg(feature = "connection-metrics")]
863#[derive(Debug)]
864pub struct Metrics {
865 pub num_sent: usize,
867 pub num_received: usize,
869 pub last_sent: embassy_time::Instant,
871 pub last_received: embassy_time::Instant,
873 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 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 peripheral.disconnect();
1147
1148 let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1150 panic!("expected connection to be accepted");
1151 };
1152
1153 let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1155 panic!("expected connection to be accepted");
1156 };
1157
1158 unwrap!(mgr.disconnected(ConnHandle::new(2), Status::UNSPECIFIED));
1160
1161 req.confirm();
1163
1164 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 peripheral.disconnect();
1201
1202 let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1204 panic!("expected connection to be accepted");
1205 };
1206
1207 req.confirm();
1209
1210 assert!(mgr.poll_disconnecting(None).is_pending());
1212
1213 unwrap!(mgr.disconnected(ConnHandle::new(2), Status::UNSPECIFIED));
1215
1216 use crate::connection::ConnectionEvent;
1218 assert!(matches!(
1219 block_on(peripheral.next()),
1220 ConnectionEvent::Disconnected {
1221 reason: Status::UNSPECIFIED
1222 }
1223 ));
1224
1225 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 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 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 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 drop(handle);
1349
1350 let Poll::Ready(req) = mgr.poll_disconnecting(None) else {
1352 panic!("expected connection to be accepted");
1353 };
1354
1355 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}