1 /*
2  * Copyright Runtime.io 2018. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Utility functions used by the UART and shell mcumgr transports.
10  *
11  * Mcumgr packets sent over serial are fragmented into frames of 128 bytes or
12  * fewer.
13  *
14  * The initial frame in a packet has the following format:
15  *     offset 0:    0x06 0x09
16  *     === Begin base64 encoding ===
17  *     offset 2:    {16-bit packet-length}
18  *     offset ?:    {body}
19  *     offset ?:    {crc16} (if final frame)
20  *     === End base64 encoding ===
21  *     offset ?:    0x0a (newline)
22  *
23  * All subsequent frames have the following format:
24  *     offset 0:    0x04 0x14
25  *     === Begin base64 encoding ===
26  *     offset 2:    {body}
27  *     offset ?:    {crc16} (if final frame)
28  *     === End base64 encoding ===
29  *     offset ?:    0x0a (newline)
30  *
31  * All integers are represented in big-endian.  The packet fields are described
32  * below:
33  *
34  * | Field          | Description                                             |
35  * | -------------- | ------------------------------------------------------- |
36  * | 0x06 0x09      | Byte pair indicating the start of a packet.             |
37  * | 0x04 0x14      | Byte pair indicating the start of a continuation frame. |
38  * | Packet length  | The combined total length of the *unencoded* body plus  |
39  * |                | the final CRC (2 bytes). Length is in Big-Endian format.|
40  * | Body           | The actual SMP data (i.e., 8-byte header and CBOR       |
41  * |                | key-value map).                                         |
42  * | CRC16          | A CRC16 of the *unencoded* body of the entire packet.   |
43  * |                | This field is only present in the final frame of a      |
44  * |                | packet.                                                 |
45  * | Newline        | A 0x0a byte; terminates a frame.                        |
46  *
47  * The packet is fully received when {packet-length} bytes of body has been
48  * received.
49  *
50  * ## CRC details
51  *
52  * The CRC16 should be calculated with the following parameters:
53  *
54  * | Field         | Value         |
55  * | ------------- | ------------- |
56  * | Polynomial    | 0x1021        |
57  * | Initial Value | 0             |
58  */
59 
60 #ifndef ZEPHYR_INCLUDE_MGMT_SERIAL_H_
61 #define ZEPHYR_INCLUDE_MGMT_SERIAL_H_
62 
63 #include <zephyr/types.h>
64 
65 #ifdef __cplusplus
66 extern "C" {
67 #endif
68 
69 #define MCUMGR_SERIAL_HDR_PKT       0x0609
70 #define MCUMGR_SERIAL_HDR_FRAG      0x0414
71 #define MCUMGR_SERIAL_MAX_FRAME     128
72 
73 #define MCUMGR_SERIAL_HDR_PKT_1     (MCUMGR_SERIAL_HDR_PKT >> 8)
74 #define MCUMGR_SERIAL_HDR_PKT_2     (MCUMGR_SERIAL_HDR_PKT & 0xff)
75 #define MCUMGR_SERIAL_HDR_FRAG_1    (MCUMGR_SERIAL_HDR_FRAG >> 8)
76 #define MCUMGR_SERIAL_HDR_FRAG_2    (MCUMGR_SERIAL_HDR_FRAG & 0xff)
77 
78 /**
79  * @brief Maintains state for an incoming mcumgr request packet.
80  */
81 struct mcumgr_serial_rx_ctxt {
82 	/* Contains the partially- or fully-received mcumgr request.  Data
83 	 * stored in this buffer has already been base64-decoded.
84 	 */
85 	struct net_buf *nb;
86 
87 	/* Length of full packet, as read from header. */
88 	uint16_t pkt_len;
89 };
90 
91 /** @typedef mcumgr_serial_tx_cb
92  * @brief Transmits a chunk of raw response data.
93  *
94  * @param data                  The data to transmit.
95  * @param len                   The number of bytes to transmit.
96  * @param arg                   An optional argument.
97  *
98  * @return                      0 on success; negative error code on failure.
99  */
100 typedef int (*mcumgr_serial_tx_cb)(const void *data, int len, void *arg);
101 
102 /**
103  * @brief Processes an mcumgr request fragment received over a serial
104  *        transport.
105  *
106  * Processes an mcumgr request fragment received over a serial transport.  If
107  * the fragment is the end of a valid mcumgr request, this function returns a
108  * net_buf containing the decoded request.  It is the caller's responsibility
109  * to free the net_buf after it has been processed.
110  *
111  * @param rx_ctxt               The receive context associated with the serial
112  *                                  transport being used.
113  * @param frag                  The incoming fragment to process.
114  * @param frag_len              The length of the fragment, in bytes.
115  *
116  * @return                      A net_buf containing the decoded request if a
117  *                                  complete and valid request has been
118  *                                  received.
119  *                              NULL if the packet is incomplete or invalid.
120  */
121 struct net_buf *mcumgr_serial_process_frag(
122 	struct mcumgr_serial_rx_ctxt *rx_ctxt,
123 	const uint8_t *frag, int frag_len);
124 
125 /**
126  * @brief Encodes and transmits an mcumgr packet over serial.
127  *
128  * @param data                  The mcumgr packet data to send.
129  * @param len                   The length of the unencoded mcumgr packet.
130  * @param cb                    A callback used to transmit raw bytes.
131  * @param arg                   An optional argument to pass to the callback.
132  *
133  * @return                      0 on success; negative error code on failure.
134  */
135 int mcumgr_serial_tx_pkt(const uint8_t *data, int len, mcumgr_serial_tx_cb cb,
136 			 void *arg);
137 
138 #ifdef __cplusplus
139 }
140 #endif
141 
142 #endif
143