1 /*
2 * Copyright (c) 2018-2021 mcumgr authors
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/sys/util.h>
8 #include <zephyr/stats/stats.h>
9 #include <zephyr/logging/log.h>
10 #include <string.h>
11 #include <stdio.h>
12
13 #include <zcbor_common.h>
14 #include <zcbor_decode.h>
15 #include <zcbor_encode.h>
16
17 #include <mgmt/mcumgr/util/zcbor_bulk.h>
18
19 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
20 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
21 #include <zephyr/mgmt/mcumgr/smp/smp.h>
22 #include <zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h>
23
24 LOG_MODULE_REGISTER(mcumgr_stat_grp, CONFIG_MCUMGR_GRP_STAT_LOG_LEVEL);
25
26 static const struct mgmt_handler stat_mgmt_handlers[];
27
28 typedef int stat_mgmt_foreach_entry_fn(zcbor_state_t *zse, struct stat_mgmt_entry *entry);
29
30 static int
stats_mgmt_count_plus_one(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)31 stats_mgmt_count_plus_one(struct stats_hdr *hdr, void *arg, const char *name, uint16_t off)
32 {
33 size_t *counter = arg;
34
35 (*counter)++;
36
37 return 0;
38 }
39
40 static int
stat_mgmt_count(const char * group_name,size_t * counter)41 stat_mgmt_count(const char *group_name, size_t *counter)
42 {
43 struct stats_hdr *hdr = stats_group_find(group_name);
44
45 if (hdr == NULL) {
46 return MGMT_ERR_ENOENT;
47 }
48
49 *counter = 0;
50
51 return stats_walk(hdr, stats_mgmt_count_plus_one, &counter);
52 }
53
54 static int
55 stat_mgmt_walk_cb(struct stats_hdr *hdr, void *arg, const char *name, uint16_t off);
56
57 struct stat_mgmt_walk_arg {
58 stat_mgmt_foreach_entry_fn *cb;
59 zcbor_state_t *zse;
60 };
61
62 static int
stat_mgmt_walk_cb(struct stats_hdr * hdr,void * arg,const char * name,uint16_t off)63 stat_mgmt_walk_cb(struct stats_hdr *hdr, void *arg, const char *name, uint16_t off)
64 {
65 struct stat_mgmt_walk_arg *walk_arg;
66 struct stat_mgmt_entry entry;
67 void *stat_val;
68
69 walk_arg = arg;
70
71 stat_val = (uint8_t *)hdr + off;
72 switch (hdr->s_size) {
73 case sizeof(uint16_t):
74 entry.value = *(uint16_t *) stat_val;
75 break;
76 case sizeof(uint32_t):
77 entry.value = *(uint32_t *) stat_val;
78 break;
79 case sizeof(uint64_t):
80 entry.value = *(uint64_t *) stat_val;
81 break;
82 default:
83 return STAT_MGMT_ERR_INVALID_STAT_SIZE;
84 }
85
86 entry.name = name;
87
88 return walk_arg->cb(walk_arg->zse, &entry);
89 }
90
91 static int
stat_mgmt_foreach_entry(zcbor_state_t * zse,const char * group_name,stat_mgmt_foreach_entry_fn * cb)92 stat_mgmt_foreach_entry(zcbor_state_t *zse, const char *group_name, stat_mgmt_foreach_entry_fn *cb)
93 {
94 struct stat_mgmt_walk_arg walk_arg;
95 struct stats_hdr *hdr;
96
97 hdr = stats_group_find(group_name);
98 if (hdr == NULL) {
99 return STAT_MGMT_ERR_INVALID_GROUP;
100 }
101
102 walk_arg = (struct stat_mgmt_walk_arg) {
103 .cb = cb,
104 .zse = zse
105 };
106
107 return stats_walk(hdr, stat_mgmt_walk_cb, &walk_arg);
108 }
109
110 static int
stat_mgmt_cb_encode(zcbor_state_t * zse,struct stat_mgmt_entry * entry)111 stat_mgmt_cb_encode(zcbor_state_t *zse, struct stat_mgmt_entry *entry)
112 {
113 bool ok = zcbor_tstr_put_term(zse, entry->name, CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN) &&
114 zcbor_uint32_put(zse, entry->value);
115
116 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
117 }
118
119 /**
120 * Command handler: stat show
121 */
122 static int
stat_mgmt_show(struct smp_streamer * ctxt)123 stat_mgmt_show(struct smp_streamer *ctxt)
124 {
125 zcbor_state_t *zse = ctxt->writer->zs;
126 zcbor_state_t *zsd = ctxt->reader->zs;
127 char stat_name[CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN];
128 bool ok;
129 size_t counter = 0;
130 size_t decoded;
131 struct zcbor_string name = { 0 };
132
133 struct zcbor_map_decode_key_val stat_decode[] = {
134 ZCBOR_MAP_DECODE_KEY_DECODER("name", zcbor_tstr_decode, &name),
135 };
136
137 ok = zcbor_map_decode_bulk(zsd, stat_decode, ARRAY_SIZE(stat_decode), &decoded) == 0;
138
139 if (!ok || name.len == 0 || name.len >= ARRAY_SIZE(stat_name)) {
140 return MGMT_ERR_EINVAL;
141 }
142
143 memcpy(stat_name, name.value, name.len);
144 stat_name[name.len] = '\0';
145
146 if (stat_mgmt_count(stat_name, &counter) != 0) {
147 LOG_ERR("Invalid stat name: %s", stat_name);
148 ok = smp_add_cmd_err(zse, ZEPHYR_MGMT_GRP_BASIC,
149 STAT_MGMT_ERR_INVALID_STAT_NAME);
150 goto end;
151 }
152
153 if (IS_ENABLED(CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR)) {
154 ok = zcbor_tstr_put_lit(zse, "rc") &&
155 zcbor_int32_put(zse, MGMT_ERR_EOK);
156 }
157
158 if (ok) {
159 ok = zcbor_tstr_put_lit(zse, "name") &&
160 zcbor_tstr_encode(zse, &name) &&
161 zcbor_tstr_put_lit(zse, "fields") &&
162 zcbor_map_start_encode(zse, counter);
163 }
164
165 if (ok) {
166 int rc = stat_mgmt_foreach_entry(zse, stat_name,
167 stat_mgmt_cb_encode);
168
169 if (rc != STAT_MGMT_ERR_OK) {
170 if (rc != STAT_MGMT_ERR_INVALID_GROUP &&
171 rc != STAT_MGMT_ERR_INVALID_STAT_SIZE) {
172 rc = STAT_MGMT_ERR_WALK_ABORTED;
173 }
174
175 ok = smp_add_cmd_err(zse, ZEPHYR_MGMT_GRP_BASIC, rc);
176 }
177 }
178
179 ok = ok && zcbor_map_end_encode(zse, counter);
180
181 end:
182 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
183 }
184
185 /**
186 * Command handler: stat list
187 */
188 static int
stat_mgmt_list(struct smp_streamer * ctxt)189 stat_mgmt_list(struct smp_streamer *ctxt)
190 {
191 const struct stats_hdr *cur = NULL;
192 zcbor_state_t *zse = ctxt->writer->zs;
193 bool ok;
194 size_t counter = 0;
195
196 do {
197 cur = stats_group_get_next(cur);
198 if (cur != NULL) {
199 counter++;
200 }
201 } while (cur != NULL);
202
203 ok = zcbor_tstr_put_lit(zse, "rc") &&
204 zcbor_int32_put(zse, MGMT_ERR_EOK) &&
205 zcbor_tstr_put_lit(zse, "stat_list") &&
206 zcbor_list_start_encode(zse, counter);
207
208 if (!ok) {
209 return MGMT_ERR_EMSGSIZE;
210 }
211 /* Iterate the list of stat groups, encoding each group's name in the CBOR
212 * array.
213 */
214 cur = NULL;
215 do {
216 cur = stats_group_get_next(cur);
217 if (cur != NULL) {
218 ok = zcbor_tstr_put_term(zse, cur->s_name,
219 CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN);
220 }
221 } while (ok && cur != NULL);
222
223 if (!ok || !zcbor_list_end_encode(zse, counter)) {
224 return MGMT_ERR_EMSGSIZE;
225 }
226
227 return 0;
228 }
229
230 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
231 /*
232 * @brief Translate stat mgmt group error code into MCUmgr error code
233 *
234 * @param ret #stat_mgmt_err_code_t error code
235 *
236 * @return #mcumgr_err_t error code
237 */
stat_mgmt_translate_error_code(uint16_t err)238 static int stat_mgmt_translate_error_code(uint16_t err)
239 {
240 int rc;
241
242 switch (err) {
243 case STAT_MGMT_ERR_INVALID_GROUP:
244 case STAT_MGMT_ERR_INVALID_STAT_NAME:
245 rc = MGMT_ERR_ENOENT;
246 break;
247
248 case STAT_MGMT_ERR_INVALID_STAT_SIZE:
249 rc = MGMT_ERR_EINVAL;
250 break;
251
252 case STAT_MGMT_ERR_WALK_ABORTED:
253 default:
254 rc = MGMT_ERR_EUNKNOWN;
255 }
256
257 return rc;
258 }
259 #endif
260
261 static const struct mgmt_handler stat_mgmt_handlers[] = {
262 [STAT_MGMT_ID_SHOW] = { stat_mgmt_show, NULL },
263 [STAT_MGMT_ID_LIST] = { stat_mgmt_list, NULL },
264 };
265
266 #define STAT_MGMT_HANDLER_CNT ARRAY_SIZE(stat_mgmt_handlers)
267
268 static struct mgmt_group stat_mgmt_group = {
269 .mg_handlers = stat_mgmt_handlers,
270 .mg_handlers_count = STAT_MGMT_HANDLER_CNT,
271 .mg_group_id = MGMT_GROUP_ID_STAT,
272 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
273 .mg_translate_error = stat_mgmt_translate_error_code,
274 #endif
275 };
276
stat_mgmt_register_group(void)277 static void stat_mgmt_register_group(void)
278 {
279 mgmt_register_group(&stat_mgmt_group);
280 }
281
282 MCUMGR_HANDLER_DEFINE(stat_mgmt, stat_mgmt_register_group);
283