1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/byteorder.h>
9 #include <zephyr/net_buf.h>
10 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
11 #include <zephyr/mgmt/mcumgr/smp/smp.h>
12 #include <zephyr/mgmt/mcumgr/transport/smp.h>
13
14 #include <mgmt/mcumgr/transport/smp_internal.h>
15
16 #define MCUMGR_TRANSPORT_NETBUF_SIZE CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE
17
smp_reassembly_init(struct smp_transport * smpt)18 void smp_reassembly_init(struct smp_transport *smpt)
19 {
20 smpt->__reassembly.current = NULL;
21 smpt->__reassembly.expected = 0;
22 }
23
smp_reassembly_expected(const struct smp_transport * smpt)24 int smp_reassembly_expected(const struct smp_transport *smpt)
25 {
26 if (smpt->__reassembly.current == NULL) {
27 return -EINVAL;
28 }
29
30 return smpt->__reassembly.expected;
31 }
32
smp_reassembly_collect(struct smp_transport * smpt,const void * buf,uint16_t len)33 int smp_reassembly_collect(struct smp_transport *smpt, const void *buf, uint16_t len)
34 {
35 if (smpt->__reassembly.current == NULL) {
36 /*
37 * Collecting the first fragment: need to allocate buffer for it and prepare
38 * the reassembly context.
39 */
40 if (len >= sizeof(struct smp_hdr)) {
41 uint16_t expected = sys_be16_to_cpu(((struct smp_hdr *)buf)->nh_len);
42
43 /*
44 * The length field in the header does not count the header size,
45 * but the reassembly does so the size needs to be added to the number of
46 * expected bytes.
47 */
48 expected += sizeof(struct smp_hdr);
49
50 /* Joining net_bufs not supported yet */
51 if (len > MCUMGR_TRANSPORT_NETBUF_SIZE ||
52 expected > MCUMGR_TRANSPORT_NETBUF_SIZE) {
53 return -ENOSR;
54 }
55
56 if (len > expected) {
57 return -EOVERFLOW;
58 }
59
60 smpt->__reassembly.current = smp_packet_alloc();
61 if (smpt->__reassembly.current != NULL) {
62 smpt->__reassembly.expected = expected;
63 } else {
64 return -ENOMEM;
65 }
66 } else {
67 /* Not enough data to even collect header */
68 return -ENODATA;
69 }
70 }
71
72 /* len is expected to be > 0 */
73 if (smpt->__reassembly.expected >= len) {
74 net_buf_add_mem(smpt->__reassembly.current, buf, len);
75 smpt->__reassembly.expected -= len;
76 } else {
77 /*
78 * A fragment is longer than the expected size and will not fit into the buffer.
79 */
80 return -EOVERFLOW;
81 }
82
83 return smpt->__reassembly.expected;
84 }
85
smp_reassembly_complete(struct smp_transport * smpt,bool force)86 int smp_reassembly_complete(struct smp_transport *smpt, bool force)
87 {
88 if (smpt->__reassembly.current == NULL) {
89 return -EINVAL;
90 }
91
92 if (smpt->__reassembly.expected == 0 || force) {
93 int expected = smpt->__reassembly.expected;
94
95 smp_rx_req(smpt, smpt->__reassembly.current);
96 smpt->__reassembly.expected = 0;
97 smpt->__reassembly.current = NULL;
98 return expected;
99 }
100 return -ENODATA;
101 }
102
smp_reassembly_drop(struct smp_transport * smpt)103 int smp_reassembly_drop(struct smp_transport *smpt)
104 {
105 if (smpt->__reassembly.current == NULL) {
106 return -EINVAL;
107 }
108
109 smp_packet_free(smpt->__reassembly.current);
110 smpt->__reassembly.expected = 0;
111 smpt->__reassembly.current = NULL;
112
113 return 0;
114 }
115
smp_reassembly_get_ud(const struct smp_transport * smpt)116 void *smp_reassembly_get_ud(const struct smp_transport *smpt)
117 {
118 if (smpt->__reassembly.current != NULL) {
119 return net_buf_user_data(smpt->__reassembly.current);
120 }
121
122 return NULL;
123 }
124