SMP Transport Specification
The documents specifies information needed for implementing server and client side SMP transports.
BLE (Bluetooth Low Energy)
MCUmgr Clients need to use following BLE Characteristics, when implementing SMP client:
Service UUID: 8D53DC1D-1DB7-4CD3-868B-8A527460AA84
Characteristic UUID: DA2E7828-FBCE-4E01-AE9E-261174997C48
All SMP communication utilizes a single GATT characteristic. An SMP request is sent via a GATT Write Without Response command. An SMP response is sent in the form of a GATT Notification
If an SMP request or response is too large to fit in a single GATT command, the sender fragments it across several packets. No additional framing is introduced when a request or response is fragmented; the payload is simply split among several packets. Since GATT guarantees ordered delivery of packets, the SMP header in the first fragment contains sufficient information for reassembly.
UART/serial and console
SMP protocol specification by MCUmgr subsystem of Zephyr uses basic framing of data to allow multiplexing of UART channel. Multiplexing requires prefixing each frame with two byte marker and terminating it with newline. Currently MCUmgr imposes a 127 byte limit on frame size, although there are no real protocol constraints that require that limit. The limit includes the prefix and the newline character, so the allowed payload size is actually 124 bytes.
Although no such transport exists in Zephyr, it is possible to implement MCUmgr client/server over UART transport that does not have framing at all, or uses hardware serial port control, or other means of framing.
Frame fragmenting
SMP protocol over serial is fragmented into MTU size frames; each frame consists of two byte start marker, body and terminating newline character.
There are four types of types of frames: initial, partial, partial-final and initial-final; each frame type differs by start marker and/or body contents.
Frame formats
Initial frame requires to be followed by optional sequence of partial frames and finally by partial-final frame. Body is always Base64 encoded, so the body size, here described as MTU - 3, is able to actually carry N = (MTU - 3) / 4 * 3 bytes of raw data.
Body of initial frame is preceded by two byte total packet length, encoded in Big Endian, and equals size of a raw body plus two bytes, size of CRC16; this means that actual body size allowed into an initial frame is N - 2.
If a body size is smaller than N - 4, than it is possible to carry entire body with preceding length and following it CRC in a single frame, here called initial-final; for the description of initial-final frame look below.
Initial frame format:
Content |
Size |
Description |
---|---|---|
0x06 0x09 |
2 bytes |
Frame start marker |
<base64-i> |
no more than MTU - 3 bytes |
Base64 encoded body |
0x0a |
1 byte |
Frame termination |
<base64-i>
is Base64 encoded body of format:
Content |
Size |
Description |
---|---|---|
total length |
2 bytes |
Big endian 16-bit value representing total length of body + 2 bytes for CRC16; note that size of total length field is not added to total length value. |
body |
no more than MTU - 5 |
Raw body data fragment |
Initial-final frame format is similar to initial frame format,
but differs by <base64-i>
definition.
<base64-i>
of initial-final frame, is Base64 encoded data taking
form:
Content |
Size |
Description |
---|---|---|
total length |
2 bytes |
Big endian 16-bit value representing total length of body + 2 bytes for CRC16; note that size of total length field is not added to total length value. |
body |
no more than MTU - 7 |
Raw body data fragment |
crc16 |
2 bytes |
CRC16 of entire packet body, preceding length not included. |
Partial frame is continuation after previous initial or other partial frame. Partial frame takes form:
Content |
Size |
Description |
---|---|---|
0x04 0x14 |
2 bytes |
Frame start marker |
<base64-i> |
no more than MTU - 3 bytes |
Base64 encoded body |
0x0a |
1 byte |
Frame termination |
The <base64-i>
of partial frame is Base64 encoding of data,
taking form:
Content |
Size |
Description |
---|---|---|
body |
no more than MTU - 3 |
Raw body data fragment |
The <base64-i>
of partial-final frame is Base64 encoding of data,
taking form:
Content |
Size |
Description |
---|---|---|
body |
no more than MTU - 3 |
Raw body data fragment |
crc16 |
2 bytes |
CRC16 of entire packet body, preceding length not included. |
CRC Details
The CRC16 included in final type frames is calculated over only raw data and does not include packet length. CRC16 polynomial is 0x1021 and initial value is 0.
API Reference
- group mcumgr_transport_smp
MCUmgr transport SMP API.
Typedefs
-
typedef int (*smp_transport_out_fn)(struct net_buf *nb)
SMP transmit callback for transport.
The supplied net_buf is always consumed, regardless of return code.
- Param nb:
The net_buf to transmit.
- Return:
0 on success, mcumgr_err_t code on failure.
-
typedef uint16_t (*smp_transport_get_mtu_fn)(const struct net_buf *nb)
SMP MTU query callback for transport.
The supplied net_buf should contain a request received from the peer whose MTU is being queried. This function takes a net_buf parameter because some transports store connection-specific information in the net_buf user header (e.g., the BLE transport stores the peer address).
- Param nb:
Contains a request from the relevant peer.
- Return:
The transport’s MTU; 0 if transmission is currently not possible.
-
typedef int (*smp_transport_ud_copy_fn)(struct net_buf *dst, const struct net_buf *src)
SMP copy user_data callback.
The supplied src net_buf should contain a user_data that cannot be copied using regular memcpy function (e.g., the BLE transport net_buf user_data stores the connection reference that has to be incremented when is going to be used by another buffer).
- Param dst:
Source buffer user_data pointer.
- Param src:
Destination buffer user_data pointer.
- Return:
0 on success, mcumgr_err_t code on failure.
-
typedef void (*smp_transport_ud_free_fn)(void *ud)
SMP free user_data callback.
This function frees net_buf user data, because some transports store connection-specific information in the net_buf user data (e.g., the BLE transport stores the connection reference that has to be decreased).
- Param ud:
Contains a user_data pointer to be freed.
-
typedef bool (*smp_transport_query_valid_check_fn)(struct net_buf *nb, void *arg)
Function for checking if queued data is still valid.
This function is used to check if queued SMP data is still valid e.g. on a remote device disconnecting, this is triggered when smp_rx_remove_invalid() is called.
- Param nb:
net buf containing queued request.
- Param arg:
Argument provided when calling smp_rx_remove_invalid() function.
- Return:
false if data is no longer valid/should be freed, true otherwise.
Enums
-
enum smp_transport_type
SMP transport type for client registration.
Values:
-
enumerator SMP_SERIAL_TRANSPORT = 0
SMP serial.
-
enumerator SMP_BLUETOOTH_TRANSPORT
SMP bluetooth.
-
enumerator SMP_SHELL_TRANSPORT
SMP shell.
-
enumerator SMP_UDP_IPV4_TRANSPORT
SMP UDP IPv4.
-
enumerator SMP_UDP_IPV6_TRANSPORT
SMP UDP IPv6.
-
enumerator SMP_USER_DEFINED_TRANSPORT
SMP user defined type.
-
enumerator SMP_SERIAL_TRANSPORT = 0
Functions
-
int smp_transport_init(struct smp_transport *smpt)
Initializes a Zephyr SMP transport object.
- Parameters:
smpt – The transport to construct.
- Returns:
0 If successful
- Returns:
Negative errno code if failure.
-
void smp_rx_remove_invalid(struct smp_transport *zst, void *arg)
Used to remove queued requests for an SMP transport that are no longer valid.
A smp_transport_query_valid_check_fn() function must be registered for this to function. If the smp_transport_query_valid_check_fn() function returns false during a callback, the queried command will classed as invalid and dropped.
- Parameters:
zst – The transport to use.
arg – Argument provided to callback smp_transport_query_valid_check_fn() function.
-
void smp_rx_clear(struct smp_transport *zst)
Used to clear pending queued requests for an SMP transport.
- Parameters:
zst – The transport to use.
-
void smp_client_transport_register(struct smp_client_transport_entry *entry)
Register a Zephyr SMP transport object for client.
- Parameters:
entry – The transport to construct.
-
struct smp_transport *smp_client_transport_get(int smpt_type)
Discover a registered SMP transport client object.
- Parameters:
smpt_type – Type of transport
- Returns:
Pointer to registered object. Unknown type return NULL.
-
struct smp_transport_api_t
- #include <smp.h>
Function pointers of SMP transport functions, if a handler is NULL then it is not supported/implemented.
Public Members
-
smp_transport_out_fn output
Transport’s send function.
-
smp_transport_get_mtu_fn get_mtu
Transport’s get-MTU function.
-
smp_transport_ud_copy_fn ud_copy
Transport buffer user_data copy function.
-
smp_transport_ud_free_fn ud_free
Transport buffer user_data free function.
-
smp_transport_query_valid_check_fn query_valid_check
Transport’s check function for if a query is valid.
-
smp_transport_out_fn output
-
struct smp_transport
- #include <smp.h>
SMP transport object for sending SMP responses.
-
struct smp_client_transport_entry
- #include <smp.h>
SMP Client transport structure.
Public Members
-
struct smp_transport *smpt
Transport structure pointer.
-
int smpt_type
Transport type.
-
struct smp_transport *smpt
-
typedef int (*smp_transport_out_fn)(struct net_buf *nb)