1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
//! Implementation of the Attribute Protocol (ATT).
//!
//! ATT always runs over L2CAP channel `0x0004`, which is connected by default as soon as the
//! Link-Layer connection is established.
//!
//! ATT is used by GATT, the *Generic Attribute Profile*, which introduces the concept of *Services*
//! and *Characteristics* which can all be accessed and discovered over the Attribute Protocol.
//!
//! # Attributes
//!
//! The ATT server hosts a list of *Attributes*, which consist of the following:
//!
//! * A 16-bit *Attribute Handle* ([`Handle`]) uniquely identifying the attribute.
//! * A 16- or 128-bit UUID identifying the attribute type. This provides information about how to
//! interpret the attribute's value (eg. as a little-endian 32-bit integer).
//! * The attribute's *value*, consisting of a dynamically-sized byte array of up to 512 Bytes.
//! * A set of *permissions*, restricting the operations that can be performed on the attribute.
//!
//! ## Attribute Grouping
//!
//! The higher-level protocol layer using ATT (ie. GATT) may define a set of attribute types as
//! *Grouping Attributes*. These attribute types are allowed for use in *Read By Group Type*
//! requests, and can also influence the behavior of other requests (such as *Find By Type Value*).
//!
//! All *Grouping Attributes* can be seen as the start of a group of attributes. Groups are formed
//! by indicating the *Group End Handle* to the client, which is the handle of the last attribute in
//! the group. The *Group End Handle* isn't known by the ATT server and must be provided by the
//! higher-level protocol (GATT).
mod handle;
mod pdus;
mod server;
mod uuid;
use self::{handle::*, pdus::*};
use crate::{l2cap::Sender, Error};
pub use self::handle::{Handle, HandleRange};
pub use self::server::{AttributeServer, AttributeServerTx};
pub use self::uuid::AttUuid;
/// An ATT server attribute
pub struct Attribute<T>
where
T: ?Sized,
{
/// The type of the attribute as a UUID16, EG "Primary Service" or "Anaerobic Heart Rate Lower Limit"
pub att_type: AttUuid,
/// Unique server-side identifer for attribute
pub handle: Handle,
/// Attribute values can be any fixed length or variable length octet array, which if too large
/// can be sent across multiple PDUs
pub value: T,
}
impl<T: AsRef<[u8]>> Attribute<T> {
/// Creates a new attribute.
pub fn new(att_type: AttUuid, handle: Handle, value: T) -> Self {
assert_ne!(handle, Handle::NULL);
Attribute {
att_type,
handle,
value,
}
}
/// Retrieves the attribute's value as a slice.
pub fn value(&self) -> &[u8] {
self.value.as_ref()
}
/// Overrides the previously set attribute's value.
pub fn set_value(&mut self, value: T) {
self.value = value;
}
}
pub enum AttributeAccessPermissions {
Readable,
Writeable,
ReadableAndWriteable,
}
impl AttributeAccessPermissions {
fn is_readable(&self) -> bool {
match self {
AttributeAccessPermissions::Readable
| AttributeAccessPermissions::ReadableAndWriteable => true,
AttributeAccessPermissions::Writeable => false,
}
}
fn is_writeable(&self) -> bool {
match self {
AttributeAccessPermissions::Writeable
| AttributeAccessPermissions::ReadableAndWriteable => true,
AttributeAccessPermissions::Readable => false,
}
}
}
impl Default for AttributeAccessPermissions {
fn default() -> Self {
AttributeAccessPermissions::Readable
}
}
/// Trait for attribute sets that can be hosted by an `AttributeServer`.
pub trait AttributeProvider {
/// Calls a closure `f` with every attribute whose handle is inside `range`, ascending.
///
/// If `f` returns an error, this function will stop calling `f` and propagate the error
/// upwards. If `f` returns `Ok(())`, iteration will continue.
///
/// This function would ideally return an iterator instead of invoking a callback, but it's not
/// currently possible to express the iterator type generically (it would need lifetime-generic
/// associated types), and all workarounds seem to be severely limiting.
fn for_attrs_in_range(
&mut self,
range: HandleRange,
f: impl FnMut(&Self, &Attribute<dyn AsRef<[u8]>>) -> Result<(), Error>,
) -> Result<(), Error>;
/// Returns whether `uuid` is a valid grouping attribute type that can be used in *Read By
/// Group Type* requests.
fn is_grouping_attr(&self, uuid: AttUuid) -> bool;
/// Queries the last attribute that is part of the attribute group denoted by the grouping
/// attribute at `handle`.
///
/// If `handle` does not refer to a grouping attribute, returns `None`.
///
/// Groups themselves are collections of attributes. An attribute is in
/// exactly zero or one groups.
///
/// For primary services and secondary services, the BLE specification gives
/// exact definitions of what's in the group. The group begins with the
/// "primary service" or "secondary service" attribute, is followed by
/// the various attributes contained within that service, and ends with the
/// last attribute contained within that service.
///
/// TODO: document what the BLE spec has to say about grouping for characteristics.
fn group_end(&self, handle: Handle) -> Option<&Attribute<dyn AsRef<[u8]>>>;
/// Retrieves the permissions for the given attribute.
///
/// These are used purely for access control within rubble, and won't be
/// communicated with clients. They should be coordinated beforehand as part
/// of a larger protocol.
///
/// Defaults to read-only. If this is overwritten and some attributes are made writeable,
/// `write_attribute` must be implemented as well.
fn attr_access_permissions(&self, _handle: Handle) -> AttributeAccessPermissions {
AttributeAccessPermissions::Readable
}
/// Attempts to write data to the given attribute.
///
/// This will only be called on handles for which
/// `attribute_access_permissions` returns
/// [`AttributeAccessPermissions::Writeable`]
/// or [`AttributeAccessPermissions::ReadableAndWriteable`].
///
/// By default, panics on all writes. This must be overwritten if
/// `attribute_access_permissions` is.
fn write_attr(&mut self, _handle: Handle, _data: &[u8]) -> Result<(), Error> {
unimplemented!("by default, no attributes should have write access permissions, and this should never be called");
}
/// If this read is from dynamic data fill the buffer and return the length of the data.
/// If not return None.
///
/// Currently the buffer is 256 bytes.
///
/// By default returns `None`.
fn read_attr_dynamic(&mut self, _handle: Handle, _buffer: &mut [u8]) -> Option<usize> {
None
}
/// In order to write data longer than what would fit one write request the procedure is explained in
/// BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part F section 3.4.6.
fn prepare_write_attr(
&mut self,
_handle: Handle,
_offset: u16,
_data: &[u8],
) -> Result<(), Error> {
unimplemented!("you need to implement prepare_write_attr to make queued writes work")
}
/// In order to write data longer than what would fit one write request the procedure is explained in
/// BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part F section 3.4.6.
fn execute_write_attr(&mut self, _flags: u8) -> Result<(), Error> {
unimplemented!("you need to implement execute_write_attr to make queued writes work")
}
/// See BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 3, Part F section 3.4.3.1 on what to implement here.
fn find_information(
&mut self,
_range: HandleRange,
_responder: &mut Sender<'_>,
) -> Result<(), Error> {
unimplemented!("you need to implement find_information to make things like Client Characteristic Configuration work")
}
}
/// An empty attribute set.
///
/// FIXME: Is this even legal according to the spec?
pub struct NoAttributes;
impl AttributeProvider for NoAttributes {
fn for_attrs_in_range(
&mut self,
_range: HandleRange,
_f: impl FnMut(&Self, &Attribute<dyn AsRef<[u8]>>) -> Result<(), Error>,
) -> Result<(), Error> {
Ok(())
}
fn is_grouping_attr(&self, _uuid: AttUuid) -> bool {
false
}
fn group_end(&self, _handle: Handle) -> Option<&Attribute<dyn AsRef<[u8]>>> {
None
}
}