trouble_host/
attribute_server.rs

1use core::cell::RefCell;
2use core::marker::PhantomData;
3
4use embassy_sync::blocking_mutex::raw::RawMutex;
5use embassy_sync::blocking_mutex::Mutex;
6
7use crate::att::{self, AttClient, AttCmd, AttErrorCode, AttReq};
8use crate::attribute::{Attribute, AttributeData, AttributeTable, CCCD};
9use crate::cursor::WriteCursor;
10use crate::prelude::Connection;
11use crate::types::uuid::Uuid;
12use crate::{codec, Error, Identity, PacketPool};
13
14#[derive(Default)]
15struct Client {
16    identity: Identity,
17    is_connected: bool,
18}
19
20impl Client {
21    fn set_identity(&mut self, identity: Identity) {
22        self.identity = identity;
23    }
24}
25
26/// A table of CCCD values.
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28#[derive(Clone, Debug)]
29pub struct CccdTable<const ENTRIES: usize> {
30    inner: [(u16, CCCD); ENTRIES],
31}
32
33impl<const ENTRIES: usize> Default for CccdTable<ENTRIES> {
34    fn default() -> Self {
35        Self {
36            inner: [(0, CCCD(0)); ENTRIES],
37        }
38    }
39}
40
41impl<const ENTRIES: usize> CccdTable<ENTRIES> {
42    /// Create a new CCCD table from an array of (handle, cccd) pairs.
43    pub fn new(cccd_values: [(u16, CCCD); ENTRIES]) -> Self {
44        Self { inner: cccd_values }
45    }
46
47    /// Get the inner array of (handle, cccd) pairs.
48    pub fn inner(&self) -> &[(u16, CCCD); ENTRIES] {
49        &self.inner
50    }
51
52    fn add_handle(&mut self, cccd_handle: u16) {
53        for (handle, _) in self.inner.iter_mut() {
54            if *handle == 0 {
55                *handle = cccd_handle;
56                break;
57            }
58        }
59    }
60
61    fn disable_all(&mut self) {
62        for (_, value) in self.inner.iter_mut() {
63            value.disable();
64        }
65    }
66
67    fn get_raw(&self, cccd_handle: u16) -> Option<[u8; 2]> {
68        for (handle, value) in self.inner.iter() {
69            if *handle == cccd_handle {
70                return Some(value.raw().to_le_bytes());
71            }
72        }
73        None
74    }
75
76    fn set_notify(&mut self, cccd_handle: u16, is_enabled: bool) {
77        for (handle, value) in self.inner.iter_mut() {
78            if *handle == cccd_handle {
79                trace!("[cccd] set_notify({}) = {}", cccd_handle, is_enabled);
80                value.set_notify(is_enabled);
81                break;
82            }
83        }
84    }
85
86    fn should_notify(&self, cccd_handle: u16) -> bool {
87        for (handle, value) in self.inner.iter() {
88            if *handle == cccd_handle {
89                return value.should_notify();
90            }
91        }
92        false
93    }
94}
95
96/// A table of CCCD values for each connected client.
97struct CccdTables<M: RawMutex, const CCCD_MAX: usize, const CONN_MAX: usize> {
98    state: Mutex<M, RefCell<[(Client, CccdTable<CCCD_MAX>); CONN_MAX]>>,
99}
100
101impl<M: RawMutex, const CCCD_MAX: usize, const CONN_MAX: usize> CccdTables<M, CCCD_MAX, CONN_MAX> {
102    fn new<const ATT_MAX: usize>(att_table: &AttributeTable<'_, M, ATT_MAX>) -> Self {
103        let mut values: [(Client, CccdTable<CCCD_MAX>); CONN_MAX] =
104            core::array::from_fn(|_| (Client::default(), CccdTable::default()));
105        let mut base_cccd_table = CccdTable::default();
106        att_table.iterate(|mut at| {
107            while let Some(att) = at.next() {
108                if let AttributeData::Cccd { .. } = att.data {
109                    base_cccd_table.add_handle(att.handle);
110                }
111            }
112        });
113        // add the base CCCD table for each potential connected client
114        for (_, table) in values.iter_mut() {
115            *table = base_cccd_table.clone();
116        }
117        Self {
118            state: Mutex::new(RefCell::new(values)),
119        }
120    }
121
122    fn connect(&self, peer_identity: &Identity) -> Result<(), Error> {
123        self.state.lock(|n| {
124            trace!("[server] searching for peer {:?}", peer_identity);
125            let mut n = n.borrow_mut();
126            let empty_slot = Identity::default();
127            for (client, table) in n.iter_mut() {
128                if client.identity.match_identity(peer_identity) {
129                    // trace!("[server] found! table = {:?}", *table);
130                    client.is_connected = true;
131                    return Ok(());
132                } else if client.identity == empty_slot {
133                    //  trace!("[server] empty slot: connecting");
134                    client.is_connected = true;
135                    client.set_identity(*peer_identity);
136                    return Ok(());
137                }
138            }
139            trace!("[server] all slots full...");
140            // if we got here all slots are full; replace the first disconnected client
141            for (client, table) in n.iter_mut() {
142                if !client.is_connected {
143                    trace!("[server] booting disconnected peer {:?}", client.identity);
144                    client.is_connected = true;
145                    client.set_identity(*peer_identity);
146                    // erase the previous client's config
147                    table.disable_all();
148                    return Ok(());
149                }
150            }
151            // Should be unreachable if the max connections (CONN_MAX) matches that defined
152            // in HostResources...
153            warn!("[server] unable to obtain CCCD slot");
154            Err(Error::ConnectionLimitReached)
155        })
156    }
157
158    fn disconnect(&self, peer_identity: &Identity) {
159        self.state.lock(|n| {
160            let mut n = n.borrow_mut();
161            for (client, _) in n.iter_mut() {
162                if client.identity.match_identity(peer_identity) {
163                    client.is_connected = false;
164                    break;
165                }
166            }
167        })
168    }
169
170    fn get_value(&self, peer_identity: &Identity, cccd_handle: u16) -> Option<[u8; 2]> {
171        self.state.lock(|n| {
172            let n = n.borrow();
173            for (client, table) in n.iter() {
174                if client.identity.match_identity(peer_identity) {
175                    return table.get_raw(cccd_handle);
176                }
177            }
178            None
179        })
180    }
181
182    fn set_notify(&self, peer_identity: &Identity, cccd_handle: u16, is_enabled: bool) {
183        self.state.lock(|n| {
184            let mut n = n.borrow_mut();
185            for (client, table) in n.iter_mut() {
186                if client.identity.match_identity(peer_identity) {
187                    table.set_notify(cccd_handle, is_enabled);
188                    break;
189                }
190            }
191        })
192    }
193
194    fn should_notify(&self, peer_identity: &Identity, cccd_handle: u16) -> bool {
195        self.state.lock(|n| {
196            let n = n.borrow();
197            for (client, table) in n.iter() {
198                if client.identity.match_identity(peer_identity) {
199                    return table.should_notify(cccd_handle);
200                }
201            }
202            false
203        })
204    }
205
206    fn get_cccd_table(&self, peer_identity: &Identity) -> Option<CccdTable<CCCD_MAX>> {
207        self.state.lock(|n| {
208            let n = n.borrow();
209            for (client, table) in n.iter() {
210                if client.identity.match_identity(peer_identity) {
211                    return Some(table.clone());
212                }
213            }
214            None
215        })
216    }
217
218    fn set_cccd_table(&self, peer_identity: &Identity, table: CccdTable<CCCD_MAX>) {
219        self.state.lock(|n| {
220            let mut n = n.borrow_mut();
221            for (client, t) in n.iter_mut() {
222                if client.identity.match_identity(peer_identity) {
223                    trace!("Setting cccd table {:?} for {:?}", table, peer_identity);
224                    *t = table;
225                    break;
226                }
227            }
228        })
229    }
230
231    fn update_identity(&self, identity: Identity) -> Result<(), Error> {
232        self.state.lock(|n| {
233            let mut n = n.borrow_mut();
234            for (client, _) in n.iter_mut() {
235                if identity.match_identity(&client.identity) {
236                    client.set_identity(identity);
237                    return Ok(());
238                }
239            }
240            Err(Error::NotFound)
241        })
242    }
243}
244
245/// A GATT server capable of processing the GATT protocol using the provided table of attributes.
246pub struct AttributeServer<
247    'values,
248    M: RawMutex,
249    P: PacketPool,
250    const ATT_MAX: usize,
251    const CCCD_MAX: usize,
252    const CONN_MAX: usize,
253> {
254    att_table: AttributeTable<'values, M, ATT_MAX>,
255    cccd_tables: CccdTables<M, CCCD_MAX, CONN_MAX>,
256    _p: PhantomData<P>,
257}
258
259pub(crate) mod sealed {
260    use super::*;
261
262    pub trait DynamicAttributeServer<P: PacketPool> {
263        fn connect(&self, connection: &Connection<'_, P>) -> Result<(), Error>;
264        fn disconnect(&self, connection: &Connection<'_, P>);
265        fn process(
266            &self,
267            connection: &Connection<'_, P>,
268            packet: &AttClient,
269            rx: &mut [u8],
270        ) -> Result<Option<usize>, Error>;
271        fn should_notify(&self, connection: &Connection<'_, P>, cccd_handle: u16) -> bool;
272        fn set(&self, characteristic: u16, input: &[u8]) -> Result<(), Error>;
273        fn update_identity(&self, identity: Identity) -> Result<(), Error>;
274    }
275}
276
277/// Type erased attribute server
278pub trait DynamicAttributeServer<P: PacketPool>: sealed::DynamicAttributeServer<P> {}
279
280impl<M: RawMutex, P: PacketPool, const ATT_MAX: usize, const CCCD_MAX: usize, const CONN_MAX: usize>
281    DynamicAttributeServer<P> for AttributeServer<'_, M, P, ATT_MAX, CCCD_MAX, CONN_MAX>
282{
283}
284impl<M: RawMutex, P: PacketPool, const ATT_MAX: usize, const CCCD_MAX: usize, const CONN_MAX: usize>
285    sealed::DynamicAttributeServer<P> for AttributeServer<'_, M, P, ATT_MAX, CCCD_MAX, CONN_MAX>
286{
287    fn connect(&self, connection: &Connection<'_, P>) -> Result<(), Error> {
288        AttributeServer::connect(self, connection)
289    }
290
291    fn disconnect(&self, connection: &Connection<'_, P>) {
292        self.cccd_tables.disconnect(&connection.peer_identity());
293    }
294
295    fn process(
296        &self,
297        connection: &Connection<'_, P>,
298        packet: &AttClient,
299        rx: &mut [u8],
300    ) -> Result<Option<usize>, Error> {
301        let res = AttributeServer::process(self, connection, packet, rx)?;
302        Ok(res)
303    }
304
305    fn should_notify(&self, connection: &Connection<'_, P>, cccd_handle: u16) -> bool {
306        AttributeServer::should_notify(self, connection, cccd_handle)
307    }
308
309    fn set(&self, characteristic: u16, input: &[u8]) -> Result<(), Error> {
310        self.att_table.set_raw(characteristic, input)
311    }
312
313    fn update_identity(&self, identity: Identity) -> Result<(), Error> {
314        self.cccd_tables.update_identity(identity)
315    }
316}
317
318impl<'values, M: RawMutex, P: PacketPool, const ATT_MAX: usize, const CCCD_MAX: usize, const CONN_MAX: usize>
319    AttributeServer<'values, M, P, ATT_MAX, CCCD_MAX, CONN_MAX>
320{
321    /// Create a new instance of the AttributeServer
322    pub fn new(
323        att_table: AttributeTable<'values, M, ATT_MAX>,
324    ) -> AttributeServer<'values, M, P, ATT_MAX, CCCD_MAX, CONN_MAX> {
325        let cccd_tables = CccdTables::new(&att_table);
326        AttributeServer {
327            att_table,
328            cccd_tables,
329            _p: PhantomData,
330        }
331    }
332
333    pub(crate) fn connect(&self, connection: &Connection<'_, P>) -> Result<(), Error> {
334        self.cccd_tables.connect(&connection.peer_identity())
335    }
336
337    pub(crate) fn should_notify(&self, connection: &Connection<'_, P>, cccd_handle: u16) -> bool {
338        self.cccd_tables.should_notify(&connection.peer_identity(), cccd_handle)
339    }
340
341    fn read_attribute_data(
342        &self,
343        connection: &Connection<'_, P>,
344        offset: usize,
345        att: &mut Attribute<'values>,
346        data: &mut [u8],
347    ) -> Result<usize, AttErrorCode> {
348        if let AttributeData::Cccd { .. } = att.data {
349            // CCCD values for each connected client are held in the CCCD tables:
350            // the value is written back into att.data so att.read() has the final
351            // say when parsing at the requested offset.
352            if let Some(value) = self.cccd_tables.get_value(&connection.peer_identity(), att.handle) {
353                let _ = att.write(0, value.as_slice());
354            }
355        }
356        att.read(offset, data)
357    }
358
359    fn write_attribute_data(
360        &self,
361        connection: &Connection<'_, P>,
362        offset: usize,
363        att: &mut Attribute<'values>,
364        data: &[u8],
365    ) -> Result<(), AttErrorCode> {
366        let err = att.write(offset, data);
367        if err.is_ok() {
368            if let AttributeData::Cccd {
369                notifications,
370                indications,
371            } = att.data
372            {
373                self.cccd_tables
374                    .set_notify(&connection.peer_identity(), att.handle, notifications);
375            }
376        }
377        err
378    }
379
380    fn handle_read_by_type_req(
381        &self,
382        connection: &Connection<'_, P>,
383        buf: &mut [u8],
384        start: u16,
385        end: u16,
386        attribute_type: &Uuid,
387    ) -> Result<usize, codec::Error> {
388        let mut handle = start;
389        let mut data = WriteCursor::new(buf);
390
391        let (mut header, mut body) = data.split(2)?;
392        let err = self.att_table.iterate(|mut it| {
393            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
394            while let Some(att) = it.next() {
395                // trace!("[read_by_type] Check attribute {:?} {}", att.uuid, att.handle);
396                if &att.uuid == attribute_type && att.handle >= start && att.handle <= end {
397                    body.write(att.handle)?;
398                    handle = att.handle;
399
400                    err = self.read_attribute_data(connection, 0, att, body.write_buf());
401                    if let Ok(len) = err {
402                        body.commit(len)?;
403                    }
404
405                    // debug!("[read_by_type] found! {:?} {}", att.uuid, att.handle);
406                    break;
407                }
408            }
409            err
410        });
411
412        match err {
413            Ok(len) => {
414                header.write(att::ATT_READ_BY_TYPE_RSP)?;
415                header.write(2 + len as u8)?;
416                Ok(header.len() + body.len())
417            }
418            Err(e) => Ok(Self::error_response(data, att::ATT_READ_BY_TYPE_REQ, handle, e)?),
419        }
420    }
421
422    fn handle_read_by_group_type_req(
423        &self,
424        connection: &Connection<'_, P>,
425        buf: &mut [u8],
426        start: u16,
427        end: u16,
428        group_type: &Uuid,
429    ) -> Result<usize, codec::Error> {
430        // TODO respond with all finds - not just one
431        let mut handle = start;
432        let mut data = WriteCursor::new(buf);
433
434        let (mut header, mut body) = data.split(2)?;
435        let err = self.att_table.iterate(|mut it| {
436            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
437            while let Some(att) = it.next() {
438                // trace!("[read_by_group] Check attribute {:x} {}", att.uuid, att.handle);
439                if &att.uuid == group_type && att.handle >= start && att.handle <= end {
440                    // debug!("[read_by_group] found! {:x} {}", att.uuid, att.handle);
441                    handle = att.handle;
442
443                    body.write(att.handle)?;
444                    body.write(att.last_handle_in_group)?;
445                    err = self.read_attribute_data(connection, 0, att, body.write_buf());
446                    if let Ok(len) = err {
447                        body.commit(len)?;
448                    }
449                    break;
450                }
451            }
452            err
453        });
454
455        match err {
456            Ok(len) => {
457                header.write(att::ATT_READ_BY_GROUP_TYPE_RSP)?;
458                header.write(4 + len as u8)?;
459                Ok(header.len() + body.len())
460            }
461            Err(e) => Ok(Self::error_response(data, att::ATT_READ_BY_GROUP_TYPE_REQ, handle, e)?),
462        }
463    }
464
465    fn handle_read_req(
466        &self,
467        connection: &Connection<'_, P>,
468        buf: &mut [u8],
469        handle: u16,
470    ) -> Result<usize, codec::Error> {
471        let mut data = WriteCursor::new(buf);
472
473        data.write(att::ATT_READ_RSP)?;
474
475        let err = self.att_table.iterate(|mut it| {
476            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
477            while let Some(att) = it.next() {
478                if att.handle == handle {
479                    err = self.read_attribute_data(connection, 0, att, data.write_buf());
480                    if let Ok(len) = err {
481                        data.commit(len)?;
482                    }
483                    break;
484                }
485            }
486            err
487        });
488
489        match err {
490            Ok(_) => Ok(data.len()),
491            Err(e) => Ok(Self::error_response(data, att::ATT_READ_REQ, handle, e)?),
492        }
493    }
494
495    fn handle_write_cmd(
496        &self,
497        connection: &Connection<'_, P>,
498        buf: &mut [u8],
499        handle: u16,
500        data: &[u8],
501    ) -> Result<usize, codec::Error> {
502        self.att_table.iterate(|mut it| {
503            while let Some(att) = it.next() {
504                if att.handle == handle {
505                    // Write commands can't respond with an error.
506                    let _ = self.write_attribute_data(connection, 0, att, data);
507                    break;
508                }
509            }
510        });
511        Ok(0)
512    }
513
514    fn handle_write_req(
515        &self,
516        connection: &Connection<'_, P>,
517        buf: &mut [u8],
518        handle: u16,
519        data: &[u8],
520    ) -> Result<usize, codec::Error> {
521        let err = self.att_table.iterate(|mut it| {
522            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
523            while let Some(att) = it.next() {
524                if att.handle == handle {
525                    err = self.write_attribute_data(connection, 0, att, data);
526                    break;
527                }
528            }
529            err
530        });
531
532        let mut w = WriteCursor::new(buf);
533        match err {
534            Ok(()) => {
535                w.write(att::ATT_WRITE_RSP)?;
536                Ok(w.len())
537            }
538            Err(e) => Ok(Self::error_response(w, att::ATT_WRITE_REQ, handle, e)?),
539        }
540    }
541
542    fn handle_find_type_value(
543        &self,
544        buf: &mut [u8],
545        start: u16,
546        end: u16,
547        attr_type: u16,
548        attr_value: &[u8],
549    ) -> Result<usize, codec::Error> {
550        let mut w = WriteCursor::new(buf);
551        let attr_type = Uuid::new_short(attr_type);
552
553        w.write(att::ATT_FIND_BY_TYPE_VALUE_RSP)?;
554        self.att_table.iterate(|mut it| {
555            while let Some(att) = it.next() {
556                if att.handle >= start && att.handle <= end && att.uuid == attr_type {
557                    if let AttributeData::Service { uuid } = &att.data {
558                        if uuid.as_raw() == attr_value {
559                            if w.available() < 4 + uuid.as_raw().len() {
560                                break;
561                            }
562                            w.write(att.handle)?;
563                            w.write(att.last_handle_in_group)?;
564                        }
565                    }
566                }
567            }
568            Ok::<(), codec::Error>(())
569        })?;
570        if w.len() > 1 {
571            Ok(w.len())
572        } else {
573            Ok(Self::error_response(
574                w,
575                att::ATT_FIND_BY_TYPE_VALUE_REQ,
576                start,
577                AttErrorCode::ATTRIBUTE_NOT_FOUND,
578            )?)
579        }
580    }
581
582    fn handle_find_information(&self, buf: &mut [u8], start: u16, end: u16) -> Result<usize, codec::Error> {
583        let mut w = WriteCursor::new(buf);
584
585        let (mut header, mut body) = w.split(2)?;
586
587        header.write(att::ATT_FIND_INFORMATION_RSP)?;
588        let mut t = 0;
589
590        self.att_table.iterate(|mut it| {
591            while let Some(att) = it.next() {
592                if att.handle >= start && att.handle <= end {
593                    if t == 0 {
594                        t = att.uuid.get_type();
595                    } else if t != att.uuid.get_type() {
596                        break;
597                    }
598                    body.write(att.handle)?;
599                    body.append(att.uuid.as_raw())?;
600                }
601            }
602            Ok::<(), codec::Error>(())
603        })?;
604        header.write(t)?;
605
606        if body.len() > 2 {
607            Ok(header.len() + body.len())
608        } else {
609            Ok(Self::error_response(
610                w,
611                att::ATT_FIND_INFORMATION_REQ,
612                start,
613                AttErrorCode::ATTRIBUTE_NOT_FOUND,
614            )?)
615        }
616    }
617
618    fn error_response(
619        mut w: WriteCursor<'_>,
620        opcode: u8,
621        handle: u16,
622        code: AttErrorCode,
623    ) -> Result<usize, codec::Error> {
624        w.reset();
625        w.write(att::ATT_ERROR_RSP)?;
626        w.write(opcode)?;
627        w.write(handle)?;
628        w.write(code)?;
629        Ok(w.len())
630    }
631
632    fn handle_prepare_write(
633        &self,
634        connection: &Connection<'_, P>,
635        buf: &mut [u8],
636        handle: u16,
637        offset: u16,
638        value: &[u8],
639    ) -> Result<usize, codec::Error> {
640        let mut w = WriteCursor::new(buf);
641        w.write(att::ATT_PREPARE_WRITE_RSP)?;
642        w.write(handle)?;
643        w.write(offset)?;
644
645        let err = self.att_table.iterate(|mut it| {
646            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
647            while let Some(att) = it.next() {
648                if att.handle == handle {
649                    err = self.write_attribute_data(connection, offset as usize, att, value);
650                    w.append(value)?;
651                    break;
652                }
653            }
654            err
655        });
656
657        match err {
658            Ok(()) => Ok(w.len()),
659            Err(e) => Ok(Self::error_response(w, att::ATT_PREPARE_WRITE_REQ, handle, e)?),
660        }
661    }
662
663    fn handle_execute_write(&self, buf: &mut [u8], _flags: u8) -> Result<usize, codec::Error> {
664        let mut w = WriteCursor::new(buf);
665        w.write(att::ATT_EXECUTE_WRITE_RSP)?;
666        Ok(w.len())
667    }
668
669    fn handle_read_blob(
670        &self,
671        connection: &Connection<'_, P>,
672        buf: &mut [u8],
673        handle: u16,
674        offset: u16,
675    ) -> Result<usize, codec::Error> {
676        let mut w = WriteCursor::new(buf);
677        w.write(att::ATT_READ_BLOB_RSP)?;
678
679        let err = self.att_table.iterate(|mut it| {
680            let mut err = Err(AttErrorCode::ATTRIBUTE_NOT_FOUND);
681            while let Some(att) = it.next() {
682                if att.handle == handle {
683                    err = self.read_attribute_data(connection, offset as usize, att, w.write_buf());
684                    if let Ok(n) = err {
685                        w.commit(n)?;
686                    }
687                    break;
688                }
689            }
690            err
691        });
692
693        match err {
694            Ok(_) => Ok(w.len()),
695            Err(e) => Ok(Self::error_response(w, att::ATT_READ_BLOB_REQ, handle, e)?),
696        }
697    }
698
699    fn handle_read_multiple(&self, buf: &mut [u8], handles: &[u8]) -> Result<usize, codec::Error> {
700        let w = WriteCursor::new(buf);
701        Self::error_response(
702            w,
703            att::ATT_READ_MULTIPLE_REQ,
704            u16::from_le_bytes([handles[0], handles[1]]),
705            AttErrorCode::ATTRIBUTE_NOT_FOUND,
706        )
707    }
708
709    /// Process an event and produce a response if necessary
710    pub fn process(
711        &self,
712        connection: &Connection<'_, P>,
713        packet: &AttClient,
714        rx: &mut [u8],
715    ) -> Result<Option<usize>, codec::Error> {
716        let len = match packet {
717            AttClient::Request(AttReq::ReadByType {
718                start,
719                end,
720                attribute_type,
721            }) => self.handle_read_by_type_req(connection, rx, *start, *end, attribute_type)?,
722
723            AttClient::Request(AttReq::ReadByGroupType { start, end, group_type }) => {
724                self.handle_read_by_group_type_req(connection, rx, *start, *end, group_type)?
725            }
726            AttClient::Request(AttReq::FindInformation {
727                start_handle,
728                end_handle,
729            }) => self.handle_find_information(rx, *start_handle, *end_handle)?,
730
731            AttClient::Request(AttReq::Read { handle }) => self.handle_read_req(connection, rx, *handle)?,
732
733            AttClient::Command(AttCmd::Write { handle, data }) => {
734                self.handle_write_cmd(connection, rx, *handle, data)?;
735                0
736            }
737
738            AttClient::Request(AttReq::Write { handle, data }) => {
739                self.handle_write_req(connection, rx, *handle, data)?
740            }
741
742            AttClient::Request(AttReq::ExchangeMtu { mtu }) => 0, // Done outside,
743
744            AttClient::Request(AttReq::FindByTypeValue {
745                start_handle,
746                end_handle,
747                att_type,
748                att_value,
749            }) => self.handle_find_type_value(rx, *start_handle, *end_handle, *att_type, att_value)?,
750
751            AttClient::Request(AttReq::PrepareWrite { handle, offset, value }) => {
752                self.handle_prepare_write(connection, rx, *handle, *offset, value)?
753            }
754
755            AttClient::Request(AttReq::ExecuteWrite { flags }) => self.handle_execute_write(rx, *flags)?,
756
757            AttClient::Request(AttReq::ReadBlob { handle, offset }) => {
758                self.handle_read_blob(connection, rx, *handle, *offset)?
759            }
760
761            AttClient::Request(AttReq::ReadMultiple { handles }) => self.handle_read_multiple(rx, handles)?,
762
763            AttClient::Confirmation(_) => 0,
764        };
765        if len > 0 {
766            Ok(Some(len))
767        } else {
768            Ok(None)
769        }
770    }
771
772    /// Get a reference to the attribute table
773    pub fn table(&self) -> &AttributeTable<'values, M, ATT_MAX> {
774        &self.att_table
775    }
776
777    /// Get the CCCD table for a connection
778    pub fn get_cccd_table(&self, connection: &Connection<'_, P>) -> Option<CccdTable<CCCD_MAX>> {
779        self.cccd_tables.get_cccd_table(&connection.peer_identity())
780    }
781
782    /// Set the CCCD table for a connection
783    pub fn set_cccd_table(&self, connection: &Connection<'_, P>, table: CccdTable<CCCD_MAX>) {
784        self.cccd_tables.set_cccd_table(&connection.peer_identity(), table);
785    }
786}