1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <zcbor_common.h>
12 #include <zcbor_decode.h>
13 #include <zcbor_encode.h>
14
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/net_buf.h>
19 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
20 #include <zephyr/mgmt/mcumgr/smp/smp.h>
21 #include <zephyr/mgmt/mcumgr/smp/smp_client.h>
22 #include <zephyr/mgmt/mcumgr/transport/smp.h>
23 #include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h>
24 #include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h>
25
26 #include <mgmt/mcumgr/util/zcbor_bulk.h>
27 #include <mgmt/mcumgr/transport/smp_internal.h>
28
29 #include <zephyr/logging/log.h>
30 LOG_MODULE_REGISTER(mcumgr_grp_os_client, CONFIG_MCUMGR_GRP_OS_CLIENT_LOG_LEVEL);
31
32 static struct os_mgmt_client *active_client;
33 static K_SEM_DEFINE(mcummgr_os_client_grp_sem, 0, 1);
34 static K_MUTEX_DEFINE(mcummgr_os_client_grp_mutex);
35
os_mgmt_client_init(struct os_mgmt_client * client,struct smp_client_object * smp_client)36 void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client)
37 {
38 client->smp_client = smp_client;
39 }
40
41 #ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_RESET
42
reset_res_fn(struct net_buf * nb,void * user_data)43 static int reset_res_fn(struct net_buf *nb, void *user_data)
44 {
45 if (!nb) {
46 active_client->status = MGMT_ERR_ETIMEOUT;
47 } else {
48 active_client->status = MGMT_ERR_EOK;
49 }
50 k_sem_give(user_data);
51 return 0;
52 }
53
os_mgmt_client_reset(struct os_mgmt_client * client)54 int os_mgmt_client_reset(struct os_mgmt_client *client)
55 {
56 struct net_buf *nb;
57 int rc;
58
59 k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER);
60 active_client = client;
61 /* allocate buffer */
62 nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS,
63 OS_MGMT_ID_RESET, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
64 if (!nb) {
65 active_client->status = MGMT_ERR_ENOMEM;
66 goto end;
67 }
68 k_sem_reset(&mcummgr_os_client_grp_sem);
69 rc = smp_client_send_cmd(active_client->smp_client, nb, reset_res_fn,
70 &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
71 if (rc) {
72 active_client->status = rc;
73 smp_packet_free(nb);
74 goto end;
75 }
76 /* Wait for process end update event */
77 k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER);
78 end:
79 rc = active_client->status;
80 active_client = NULL;
81 k_mutex_unlock(&mcummgr_os_client_grp_mutex);
82 return rc;
83 }
84
85 #endif /* CONFIG_MCUMGR_GRP_OS_CLIENT_RESET */
86
87 #ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO
88
echo_res_fn(struct net_buf * nb,void * user_data)89 static int echo_res_fn(struct net_buf *nb, void *user_data)
90 {
91 struct zcbor_string val = {0};
92 zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
93 size_t decoded;
94 bool ok;
95 int rc;
96 struct zcbor_map_decode_key_val echo_response[] = {
97 ZCBOR_MAP_DECODE_KEY_DECODER("r", zcbor_tstr_decode, &val)
98 };
99
100 if (!nb) {
101 LOG_ERR("Echo command timeout");
102 active_client->status = MGMT_ERR_ETIMEOUT;
103 goto end;
104 }
105
106 /* Init ZCOR decoder state */
107 zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0);
108
109 ok = zcbor_map_decode_bulk(zsd, echo_response, ARRAY_SIZE(echo_response), &decoded) == 0;
110
111 if (!ok) {
112 active_client->status = MGMT_ERR_ECORRUPT;
113 goto end;
114 }
115 active_client->status = MGMT_ERR_EOK;
116 end:
117 rc = active_client->status;
118 k_sem_give(user_data);
119 return rc;
120 }
121
os_mgmt_client_echo(struct os_mgmt_client * client,const char * echo_string,size_t max_len)122 int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string, size_t max_len)
123 {
124 struct net_buf *nb;
125 int rc;
126 bool ok;
127 zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS];
128
129 k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER);
130 active_client = client;
131 nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, OS_MGMT_ID_ECHO,
132 MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
133 if (!nb) {
134 rc = active_client->status = MGMT_ERR_ENOMEM;
135 goto end;
136 }
137
138 zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0);
139
140 ok = zcbor_map_start_encode(zse, 2) &&
141 zcbor_tstr_put_lit(zse, "d") &&
142 zcbor_tstr_put_term(zse, echo_string, max_len) &&
143 zcbor_map_end_encode(zse, 2);
144
145 if (!ok) {
146 smp_packet_free(nb);
147 rc = active_client->status = MGMT_ERR_ENOMEM;
148 goto end;
149 }
150
151 nb->len = zse->payload - nb->data;
152
153 LOG_DBG("Echo Command packet len %d", nb->len);
154 k_sem_reset(&mcummgr_os_client_grp_sem);
155 rc = smp_client_send_cmd(active_client->smp_client, nb, echo_res_fn,
156 &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
157 if (rc) {
158 smp_packet_free(nb);
159 } else {
160 k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER);
161 /* Take response status */
162 rc = active_client->status;
163 }
164 end:
165 active_client = NULL;
166 k_mutex_unlock(&mcummgr_os_client_grp_mutex);
167 return rc;
168 }
169 #endif
170