1# SMP (Simple Management Protocol) Protocol Notes 2 3The `mcumgr` SMP server and `mcumgr-cli` SMP client tool ([source](https://github.com/apache/mynewt-mcumgr-cli)) 4use a custom protocol to send commands and responses between the server and client using a 5variety of transports (currently TTY serial or BLE). 6 7The protocol isn't fully documented but the following information has been inferred 8from the source code available on Github and using the `-l DEBUG` flag when 9executing commands. 10 11## Source Code 12 13**SMP** is based on the earlier **NMP**, which is part of [Apache Mynewt](https://mynewt.apache.org/). 14 15The golang source for the original **newtmgr** is [available here](https://github.com/apache/mynewt-newtmgr), 16and can be used to provide some insight into how data is exchanged between the 17utility and the device under test. 18 19This repository (`mynewt-mcumgr`) implements an SMP server in **C**, 20and a new command-line SMP client called **mcumgr** was created at 21[apache/mynewt-mcumgr-cli](https://github.com/apache/mynewt-mcumgr-cli). 22 23## SMP Frame Format 24 25### Endianness 26 27Frames are normally serialized as **Big Endian** when dealing with values > 8 bits. This is 28mandatory in NMP, but the SMP implementation does add support for **Little Endian** as an 29option at the struct level, as shown below. 30 31### Frame Header 32 33Frames in SMP have the following header format: 34 35``` 36struct mgmt_hdr { 37#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 38 uint8_t nh_op:3; /* MGMT_OP_[...] */ 39 uint8_t _res1:5; 40#endif 41#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 42 uint8_t _res1:5; 43 uint8_t nh_op:3; /* MGMT_OP_[...] */ 44#endif 45 uint8_t nh_flags; /* Reserved for future flags */ 46 uint16_t nh_len; /* Length of the payload */ 47 uint16_t nh_group; /* MGMT_GROUP_ID_[...] */ 48 uint8_t nh_seq; /* Sequence number */ 49 uint8_t nh_id; /* Message ID within group */ 50}; 51``` 52 53The NMP/newtmgr [go source](https://github.com/apache/mynewt-newtmgr/blob/master/nmxact/nmp/nmp.go) is as follows, 54without the option to select endianness: 55 56``` 57type NmpHdr struct { 58 Op uint8 /* 3 bits of opcode */ 59 Flags uint8 60 Len uint16 61 Group uint16 62 Seq uint8 63 Id uint8 64} 65``` 66 67`nh_op` (or `Op` in newtmgr) can be one of the following values: 68 69``` 70/** Opcodes; encoded in first byte of header. */ 71#define MGMT_OP_READ 0 72#define MGMT_OP_READ_RSP 1 73#define MGMT_OP_WRITE 2 74#define MGMT_OP_WRITE_RSP 3 75``` 76 77- **`op`**: The operation code 78- **`Flags`**: TBD 79- **`Len`**: The payload len when `Data` is present 80- **`Group`**: Commands are organized into groups. Groups are defined 81 [here](https://github.com/apache/mynewt-mcumgr/blob/master/mgmt/include/mgmt/mgmt.h). 82- **`Seq`**: TBD 83- **`Id`**: The command ID to send. Commands in the default `Group` are defined 84 [here](https://github.com/apache/mynewt-mcumgr/blob/master/mgmt/include/mgmt/mgmt.h). 85 86SMP header (Little Endian) 87 88``` 89 0 1 2 3 90 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 91+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 92| OP | Res. | Flags | Length | 93+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 94| Group ID | Sequence | Command ID | 95+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 96``` 97 98#### `Data` Payload 99 100If `nh_len` (`Len` in nmp) is non-zero, the `nh_len` byte payload (referred to as **`Data`** in this document) immediately follows the frame header. 101 102### Example Packets 103 104The following example commands show how the different fields work: 105 106#### Simple Read Request: `taskstats` 107 108The following example corresponds to the `taskstats` command ([source](https://github.com/apache/mynewt-mcumgr/blob/master/cmd/os_mgmt/include/os_mgmt/os_mgmt.h)), and 109can be seen by running `mcumgr -l DEBUG -c serial taskstats`: 110 111``` 112Op: 0 # NMGR_OP_READ 113Flags: 0 114Len: 0 # No payload present 115Group: 0 # 0x00 = NMGR_GROUP_ID_DEFAULT 116Seq: 0 117Id: 2 # 0x02 in group 0x00 = OS_MGMT_ID_TASKSTAT 118Data: [] # No payload (len = 0 above) 119``` 120 121When serialized this will be sent as `0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02`. 122 123If this was sent using the serial port, you would get the following request and response: 124 125``` 126$ mcumgr -l DEBUG -c serial taskstats 1272016/11/11 12:45:44 [DEBUG] Writing newtmgr request &{Op:0 Flags:0 Len:0 Group:0 Seq:0 Id:2 Data:[]} 1282016/11/11 12:45:44 [DEBUG] Serializing request &{Op:0 Flags:0 Len:0 Group:0 Seq:0 Id:2 Data:[]} into buffer [0 0 0 0 0 0 0 2] 1292016/11/11 12:45:44 [DEBUG] Tx packet dump: 13000000000 00 00 00 00 00 00 00 02 |........| 131 1322016/11/11 12:45:44 [DEBUG] Writing [6 9] to data channel 1332016/11/11 12:45:44 [DEBUG] Writing [65 65 111 65 65 65 65 65 65 65 65 65 65 105 66 67] to data channel 1342016/11/11 12:45:44 [DEBUG] Writing [10] to data channel 1352016/11/11 12:45:44 [DEBUG] Reading [6 9 65 65 111 65 65 65 65 65 65 65 65 65 65 105 66 67] from data channel 1362016/11/11 12:45:44 [DEBUG] Rx packet dump: 13700000000 00 00 00 00 00 00 00 02 |........| 138 1392016/11/11 12:45:44 [DEBUG] Deserialized response &{Op:0 Flags:0 Len:0 Group:0 Seq:0 Id:2 Data:[]} 1402016/11/11 12:45:44 [DEBUG] Reading [13] from data channel 1412016/11/11 12:45:44 [DEBUG] Reading [6 9 65 90 119 66 65 81 71 83 65 65 65 65 65 114 57 105 99 109 77 65 90 88 82 104 99 50 116 122 118 50 82 112 90 71 120 108 118 50 82 119 99 109 108 118 71 80 57 106 100 71 108 107 65 71 86 122 100 71 70 48 90 81 70 109 99 51 82 114 100 88 78 108 71 66 108 109 99 51 82 114 99 50 108 54 71 69 66 109 89 51 78 51 89 50 53 48 71 103 65 85 102 109 112 110 99 110 86 117 100 71 108 116 90 82 111 65 69 53 120 80 98 71 120 104 99 51 82 102] from data channel 1422016/11/11 12:45:44 [DEBUG] Reading [4 20 89 50 104 108 89 50 116 112 98 103 66 115 98 109 86 52 100 70 57 106 97 71 86 106 97 50 108 117 65 80 57 109 89 109 120 108 88 50 120 115 118 50 82 119 99 109 108 118 65 71 78 48 97 87 81 66 90 88 78 48 89 88 82 108 65 109 90 122 100 71 116 49 99 50 85 89 79 109 90 122 100 71 116 122 97 88 111 89 85 71 90 106 99 51 100 106 98 110 81 90 54 112 120 110 99 110 86 117 100 71 108 116 90 82 107 74 82 87 120 115 89 88 78 48 88 50 78 111] from data channel 1432016/11/11 12:45:44 [DEBUG] Reading [4 20 90 87 78 114 97 87 52 65 98 71 53 108 101 72 82 102 89 50 104 108 89 50 116 112 98 103 68 47 98 109 74 115 90 88 86 104 99 110 82 102 89 110 74 112 90 71 100 108 118 50 82 119 99 109 108 118 66 87 78 48 97 87 81 67 90 88 78 48 89 88 82 108 65 87 90 122 100 71 116 49 99 50 85 89 72 50 90 122 100 71 116 122 97 88 111 90 65 81 66 109 89 51 78 51 89 50 53 48 71 103 65 84 113 89 78 110 99 110 86 117 100 71 108 116 90 81 66 115] from data channel 1442016/11/11 12:45:44 [DEBUG] Reading [4 20 98 71 70 122 100 70 57 106 97 71 86 106 97 50 108 117 65 71 120 117 90 88 104 48 88 50 78 111 90 87 78 114 97 87 52 65 47 50 100 105 98 71 86 119 99 110 66 111 118 50 82 119 99 109 108 118 65 87 78 48 97 87 81 68 90 88 78 48 89 88 82 108 65 87 90 122 100 71 116 49 99 50 85 89 48 50 90 122 100 71 116 122 97 88 111 90 65 86 66 109 89 51 78 51 89 50 53 48 71 81 113 68 90 51 74 49 98 110 82 112 98 87 85 69 98 71 120 104] from data channel 1452016/11/11 12:45:44 [DEBUG] Reading [4 20 99 51 82 102 89 50 104 108 89 50 116 112 98 103 66 115 98 109 86 52 100 70 57 106 97 71 86 106 97 50 108 117 65 80 47 47 47 56 85 88] from data channel 1462016/11/11 12:45:44 [DEBUG] Rx packet dump: 14700000000 01 01 01 92 00 00 00 02 bf 62 72 63 00 65 74 61 |.........brc.eta| 14800000010 73 6b 73 bf 64 69 64 6c 65 bf 64 70 72 69 6f 18 |sks.didle.dprio.| 14900000020 ff 63 74 69 64 00 65 73 74 61 74 65 01 66 73 74 |.ctid.estate.fst| 15000000030 6b 75 73 65 18 19 66 73 74 6b 73 69 7a 18 40 66 |kuse..fstksiz.@f| 15100000040 63 73 77 63 6e 74 1a 00 14 7e 6a 67 72 75 6e 74 |cswcnt...~jgrunt| 15200000050 69 6d 65 1a 00 13 9c 4f 6c 6c 61 73 74 5f 63 68 |ime....Ollast_ch| 15300000060 65 63 6b 69 6e 00 6c 6e 65 78 74 5f 63 68 65 63 |eckin.lnext_chec| 15400000070 6b 69 6e 00 ff 66 62 6c 65 5f 6c 6c bf 64 70 72 |kin..fble_ll.dpr| 15500000080 69 6f 00 63 74 69 64 01 65 73 74 61 74 65 02 66 |io.ctid.estate.f| 15600000090 73 74 6b 75 73 65 18 3a 66 73 74 6b 73 69 7a 18 |stkuse.:fstksiz.| 157000000a0 50 66 63 73 77 63 6e 74 19 ea 9c 67 72 75 6e 74 |Pfcswcnt...grunt| 158000000b0 69 6d 65 19 09 45 6c 6c 61 73 74 5f 63 68 65 63 |ime..Ellast_chec| 159000000c0 6b 69 6e 00 6c 6e 65 78 74 5f 63 68 65 63 6b 69 |kin.lnext_checki| 160000000d0 6e 00 ff 6e 62 6c 65 75 61 72 74 5f 62 72 69 64 |n..nbleuart_brid| 161000000e0 67 65 bf 64 70 72 69 6f 05 63 74 69 64 02 65 73 |ge.dprio.ctid.es| 162000000f0 74 61 74 65 01 66 73 74 6b 75 73 65 18 1f 66 73 |tate.fstkuse..fs| 16300000100 74 6b 73 69 7a 19 01 00 66 63 73 77 63 6e 74 1a |tksiz...fcswcnt.| 16400000110 00 13 a9 83 67 72 75 6e 74 69 6d 65 00 6c 6c 61 |....gruntime.lla| 16500000120 73 74 5f 63 68 65 63 6b 69 6e 00 6c 6e 65 78 74 |st_checkin.lnext| 16600000130 5f 63 68 65 63 6b 69 6e 00 ff 67 62 6c 65 70 72 |_checkin..gblepr| 16700000140 70 68 bf 64 70 72 69 6f 01 63 74 69 64 03 65 73 |ph.dprio.ctid.es| 16800000150 74 61 74 65 01 66 73 74 6b 75 73 65 18 d3 66 73 |tate.fstkuse..fs| 16900000160 74 6b 73 69 7a 19 01 50 66 63 73 77 63 6e 74 19 |tksiz..Pfcswcnt.| 17000000170 0a 83 67 72 75 6e 74 69 6d 65 04 6c 6c 61 73 74 |..gruntime.llast| 17100000180 5f 63 68 65 63 6b 69 6e 00 6c 6e 65 78 74 5f 63 |_checkin.lnext_c| 17200000190 68 65 63 6b 69 6e 00 ff ff ff |heckin....| 173 1742016/11/11 12:45:44 [DEBUG] Deserialized response &{Op:1 Flags:1 Len:402 Group:0 Seq:0 Id:2 Data:[191 98 114 99 0 101 116 97 115 107 115 191 100 105 100 108 101 191 100 112 114 105 111 24 255 99 116 105 100 0 101 115 116 97 116 101 1 102 115 116 107 117 115 101 24 25 102 115 116 107 115 105 122 24 64 102 99 115 119 99 110 116 26 0 20 126 106 103 114 117 110 116 105 109 101 26 0 19 156 79 108 108 97 115 116 95 99 104 101 99 107 105 110 0 108 110 101 120 116 95 99 104 101 99 107 105 110 0 255 102 98 108 101 95 108 108 191 100 112 114 105 111 0 99 116 105 100 1 101 115 116 97 116 101 2 102 115 116 107 117 115 101 24 58 102 115 116 107 115 105 122 24 80 102 99 115 119 99 110 116 25 234 156 103 114 117 110 116 105 109 101 25 9 69 108 108 97 115 116 95 99 104 101 99 107 105 110 0 108 110 101 120 116 95 99 104 101 99 107 105 110 0 255 110 98 108 101 117 97 114 116 95 98 114 105 100 103 101 191 100 112 114 105 111 5 99 116 105 100 2 101 115 116 97 116 101 1 102 115 116 107 117 115 101 24 31 102 115 116 107 115 105 122 25 1 0 102 99 115 119 99 110 116 26 0 19 169 131 103 114 117 110 116 105 109 101 0 108 108 97 115 116 95 99 104 101 99 107 105 110 0 108 110 101 120 116 95 99 104 101 99 107 105 110 0 255 103 98 108 101 112 114 112 104 191 100 112 114 105 111 1 99 116 105 100 3 101 115 116 97 116 101 1 102 115 116 107 117 115 101 24 211 102 115 116 107 115 105 122 25 1 80 102 99 115 119 99 110 116 25 10 131 103 114 117 110 116 105 109 101 4 108 108 97 115 116 95 99 104 101 99 107 105 110 0 108 110 101 120 116 95 99 104 101 99 107 105 110 0 255 255 255]} 175Return Code = 0 176 task pri tid runtime csw stksz stkuse last_checkin next_checkin 177 bleuart_bridge 5 2 0 1288579 256 31 0 0 178 bleprph 1 3 4 2691 336 211 0 0 179 idle 255 0 1285199 1343082 64 25 0 0 180 ble_ll 0 1 2373 60060 80 58 0 0 181``` 182 183#### Group Read Request: `image list` 184 185The following command lists images on the device and uses commands from `Group` 1860x01 (`MGMT_GROUP_ID_IMAGE`), and was generated with `$ mcumgr -l DEBUG -c serial image list`: 187 188> See [img_mgmt](https://github.com/apache/mynewt-mcumgr/tree/master/cmd/img_mgmt) 189for a full list of commands in the IMAGE `Group`. 190 191``` 192$ mcumgr -l DEBUG -c serial image list 1932016/11/11 12:25:51 [DEBUG] Writing newtmgr request &{Op:0 Flags:0 Len:0 Group:1 Seq:0 Id:0 Data:[]} 1942016/11/11 12:25:51 [DEBUG] Serializing request &{Op:0 Flags:0 Len:0 Group:1 Seq:0 Id:0 Data:[]} into buffer [0 0 0 0 0 1 0 0] 1952016/11/11 12:25:51 [DEBUG] Tx packet dump: 19600000000 00 00 00 00 00 01 00 00 |........| 197 1982016/11/11 12:25:51 [DEBUG] Writing [6 9] to data channel 1992016/11/11 12:25:51 [DEBUG] Writing [65 65 111 65 65 65 65 65 65 65 69 65 65 68 99 119] to data channel 2002016/11/11 12:25:51 [DEBUG] Writing [10] to data channel 2012016/11/11 12:25:51 [DEBUG] Reading [6 9 65 65 111 65 65 65 65 65 65 65 69 65 65 68 99 119] from data channel 2022016/11/11 12:25:51 [DEBUG] Rx packet dump: 20300000000 00 00 00 00 00 01 00 00 |........| 204 2052016/11/11 12:25:51 [DEBUG] Deserialized response &{Op:0 Flags:0 Len:0 Group:1 Seq:0 Id:0 Data:[]} 2062016/11/11 12:25:51 [DEBUG] Reading [13] from data channel 2072016/11/11 12:25:51 [DEBUG] Reading [6 9 65 73 85 66 65 81 66 55 65 65 69 65 65 76 57 109 97 87 49 104 90 50 86 122 110 55 57 107 99 50 120 118 100 65 66 110 100 109 86 121 99 50 108 118 98 109 85 119 76 106 77 117 77 71 82 111 89 88 78 111 87 67 68 83 84 76 77 70 69 49 81 88 75 55 85 81 110 53 121 48 114 110 104 104 50 87 49 113 47 102 120 71 50 48 103 115 54 121 48 48 113 75 101 79 48 71 104 105 98 50 57 48 89 87 74 115 90 102 86 110 99 71 86 117 90 71 108 117] from data channel 2082016/11/11 12:25:51 [DEBUG] Reading [4 20 90 47 82 112 89 50 57 117 90 109 108 121 98 87 86 107 57 87 90 104 89 51 82 112 100 109 88 49 47 47 57 114 99 51 66 115 97 88 82 84 100 71 70 48 100 88 77 65 47 49 78 116] from data channel 2092016/11/11 12:25:51 [DEBUG] Rx packet dump: 21000000000 01 01 00 7b 00 01 00 00 bf 66 69 6d 61 67 65 73 |...{.....fimages| 21100000010 9f bf 64 73 6c 6f 74 00 67 76 65 72 73 69 6f 6e |..dslot.gversion| 21200000020 65 30 2e 33 2e 30 64 68 61 73 68 58 20 d2 4c b3 |e0.3.0dhashX .L.| 21300000030 05 13 54 17 2b b5 10 9f 9c b4 ae 78 61 d9 6d 6a |..T.+......xa.mj| 21400000040 fd fc 46 db 48 2c eb 2d 34 a8 a7 8e d0 68 62 6f |..F.H,.-4....hbo| 21500000050 6f 74 61 62 6c 65 f5 67 70 65 6e 64 69 6e 67 f4 |otable.gpending.| 21600000060 69 63 6f 6e 66 69 72 6d 65 64 f5 66 61 63 74 69 |iconfirmed.facti| 21700000070 76 65 f5 ff ff 6b 73 70 6c 69 74 53 74 61 74 75 |ve...ksplitStatu| 21800000080 73 00 ff |s..| 219 2202016/11/11 12:25:51 [DEBUG] Deserialized response &{Op:1 Flags:1 Len:123 Group:1 Seq:0 Id:0 Data:[191 102 105 109 97 103 101 115 159 191 100 115 108 111 116 0 103 118 101 114 115 105 111 110 101 48 46 51 46 48 100 104 97 115 104 88 32 210 76 179 5 19 84 23 43 181 16 159 156 180 174 120 97 217 109 106 253 252 70 219 72 44 235 45 52 168 167 142 208 104 98 111 111 116 97 98 108 101 245 103 112 101 110 100 105 110 103 244 105 99 111 110 102 105 114 109 101 100 245 102 97 99 116 105 118 101 245 255 255 107 115 112 108 105 116 83 116 97 116 117 115 0 255]} 221Images: 222 slot=0 223 version: 0.3.0 224 bootable: true 225 flags: active confirmed 226 hash: d24cb3051354172bb5109f9cb4ae7861d96d6afdfc46db482ceb2d34a8a78ed0 227Split status: N/A 228``` 229 230When serialised this will be sent as `0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00`. 231 232## Transports 233 234### Mcumgr/Newtmgr SMP Client Over Serial 235 236`mcumgr` or `newtmgr` can be used over TTY serial with the following parameters 237to connect to a SMP server running on the target device: 238 239- Baud Rate: 115200 240- HW Flow Control: None 241 242### Mcumgr/Newtmgr SMP Client Over BLE 243 244`mcumgr` or `newtmgr` can be used over BLE with the following GATT service and 245characteristic UUIDs to connect to a SMP server running on the target device: 246 247- **Service UUID**: `8D53DC1D-1DB7-4CD3-868B-8A527460AA84` 248- **Characteristic UUID**: `DA2E7828-FBCE-4E01-AE9E-261174997C48` 249 250The "SMP" GATT service consists of one **write no-rsp characteristic** 251for SMP requests: a single-byte characteristic that 252can only accepts write-without-response commands. The contents of 253each write command contains an SMP request. 254 255SMP responses are sent back in the form of unsolicited notifications 256from the same characteristic. 257