Chapter 12 — Attribute Protocol (ATT)
Part 1 of 4 · Introduction · Attribute Structure · UUID · Permissions · PDU Format · Sequential Transactions
12.1 — Introduction
What ATT Does and Where It Sits
The Attribute Protocol gives one BLE device a way to discover what data another device exposes, then read or write that data. It runs directly above L2CAP and uses CID 0x0004 — a fixed channel that needs no setup handshake before use.
ATT feeds directly into the Generic Attribute Profile (GATT), which organises ATT attributes into the services and characteristics that applications actually work with. Think of ATT as the raw data transport and GATT as the filing system on top of it.
Client-server model: The server holds attributes and exposes them. The client discovers, reads, and writes them. A device can be both client and server simultaneously — a heart rate monitor, for example, is a server for heart rate data but might also be a client when reading time from a paired phone. Only one server can be active on a device at any time.
12.2 — What Is an Attribute?
Any Piece of Data a Device Wants to Share
An attribute is an addressable piece of data. It can represent anything: a temperature reading, a device name, battery level, a control command, or the timestamp of last measurement. The ATT protocol is designed to push or pull any such data to or from a remote device, and to alert remote devices when that data changes.
- Temperature value from a thermometer
- Temperature unit (Celsius / Fahrenheit)
- Device name string
- Manufacturer name and model number
- Heart rate measurement
- Battery level percentage
- Discover what attributes exist on a server
- Read the value of any attribute
- Write a value to a writable attribute
- Subscribe to notifications when a value changes
- Receive reliable indications with confirmation
Attribute Structure — Four Fields
Every attribute on a server is described by exactly four fields. These four fields together form the complete identity of that piece of data.
12.2.1 — Attribute Type (UUID)
The type field tells a client what this attribute means. Without the type, a handle is just a number pointing to an unknown blob of bytes. The type gives it semantic meaning — “this is a temperature”, “this is a heart rate”, “this is a service boundary”.
All types are identified by a UUID — a Universally Unique Identifier. Two forms are used:
Assigned by the Bluetooth SIG. Published in the Bluetooth Assigned Numbers specification. Used for all standard BLE characteristics and services. Much more compact — only 2 bytes instead of 16.
Example: 0x180D = Heart Rate Service
Example: 0x2A29 = Manufacturer Name String
Used for custom vendor-specific services and characteristics. Any developer can generate a 128-bit UUID and use it without registration. Derived from 16-bit SIG UUIDs by substituting into the base formula.
Base UUID: 0000xxxx-0000-1000-8000-00805F9B34FB
Replace xxxx with the 16-bit UUID hex value
12.2.2 — Attribute Handle
Every attribute on a server has a unique numeric handle — a 16-bit value the client uses in every read, write, and discovery operation. Think of it as an address in memory: once you know the handle for “heart rate measurement”, you can read it directly without rediscovering it every connection.
If an attribute is deleted, its handle number is retired — the server must not reuse that handle number for any future attribute, even if it adds a new attribute at the same logical position. This guarantees that cached handles on clients remain unique and valid.
12.2.3 — Attribute Permissions
Permissions control who can access an attribute and what they must prove first. They are set by the GATT profile or the application — ATT just enforces them by returning error codes when the requirements are not met.
| Error Code | Meaning |
|---|---|
| Read Not Permitted | Attribute type does not support reading |
| Write Not Permitted | Attribute type does not support writing |
| Insufficient Authentication | Authenticated pairing required — re-pair with MITM |
| Insufficient Authorization | Application-level authorization needed |
| Insufficient Encryption Key Size | Current encryption key is too short |
| Insufficient Encryption | Link must be encrypted first |
12.2.4 — Attribute Value
The value is the actual payload — the byte array that contains the data. Lengths are either fixed (1, 2, or 4 octets for simple types) or variable (strings, variable-length records). ATT sends only one attribute value per PDU. If the value is too large for a single PDU, it gets split across multiple read operations using Read Blob requests.
12.2.5 — Control Point Attributes
Some attributes exist to receive commands, not to expose data. These are write-only — they cannot be read. A good example is the Alert Level characteristic in the Immediate Alert Service: a remote device writes “No Alert”, “Mid Alert”, or “High Alert” to it, which triggers an action like flashing an LED or sounding a buzzer. Reading back the alert level makes no sense — the attribute only processes incoming writes.
12.2.6 — Grouping of Attribute Handles
ATT allows attributes to be grouped together with a specific attribute placed at the beginning of the group. GATT defines three group types: Primary Service, Secondary Service, and Characteristic. Grouping enables range-based operations — a client can ask “give me all attributes in the handle range of this Primary Service group” and get the entire service definition in one transaction.
12.2.7 — Atomic Operations
When multiple clients are connected to one server, each client’s operation is treated atomically — it completes without interference from other clients. If Client A is doing a multi-step Prepare Write sequence, Client B starting a different write on the same server does not corrupt A’s queued data. Each client has its own separate write queue on the server.
12.3 — The Six PDU Method Types
Every ATT Packet Falls Into One of Six Categories
The ATT protocol uses six types of PDU, distinguished by who sends them and whether a response is expected:
12.3.1 — PDU Format
Every ATT packet starts with a 1-byte Opcode field followed by variable-length parameters, and optionally an authentication signature at the end.
1 octet
6 bits
1b
1b
Variable length — method-specific data
Optional
12 octets
The Authentication Signature is for the scenario where the link is not encrypted but data integrity is still required. The CSRK (Connection Signature Resolving Key distributed in SM Phase 3) generates this 12-byte signature. The server verifies it before processing the write. This is different from link encryption — it is message-level integrity only.
12.3.2 — Sequential Transactions and the 30-Second Timeout
ATT is a sequential protocol. The client sends one Request and must wait for the Response before sending the next Request. The server sends one Indication and must wait for the Confirmation before sending the next Indication. This keeps things simple and provides implicit flow control.
30-second timeout: If a Request is sent and no Response arrives within 30 seconds, the transaction has timed out. The client notifies the higher layer (GATT, application) of the failure. Both sides must disconnect and reconnect to clear the failed state before trying again.
Interesting sequence possibilities: Because Notifications have no flow control, a sequence like Request → Notification → Response is perfectly valid. The server can send a Notification in the middle of a pending Request/Response pair without violating the protocol.
/* Discovering all services with gatttool (BlueZ) */
gatttool -b AA:BB:CC:DD:EE:FF -I
/* Inside the interactive session: */
[AA:BB:CC:DD:EE:FF][LE]> connect
[AA:BB:CC:DD:EE:FF][LE]> primary
/* This sends a sequence of Read By Group Type Requests */
/* on CID 0x0004 — waits for each Response before sending */
/* the next Request (sequential transactions enforced) */
/* Output: */
/* attr handle: 0x0001, end grp handle: 0x0007 uuid: 1800 */
/* attr handle: 0x0016, end grp handle: 0x0019 uuid: 1801 */
/* attr handle: 0x0080, end grp handle: 0x0082 uuid: 1803 */
/* Using bluetoothctl (newer BlueZ): */
bluetoothctl
[bluetooth]# connect AA:BB:CC:DD:EE:FF
[AA:BB:CC:DD:EE:FF]# list-attributes
/* Lists all GATT services and characteristics via ATT */
Next — ATT Read Methods
Part 2 covers all the Request/Response read operations: Exchange MTU, Find Information, Find By Type Value, Read By Type, Read, Read Blob, Read Multiple, and Read By Group Type.
