1 #include <string.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <errno.h>
5
6 #include "libmctp-cmds.h"
7 #include "libmctp-alloc.h"
8 #include "libmctp-log.h"
9 #include "core-internal.h"
10
11 #include "control.h"
12
fill_resp(const void * req,struct mctp_ctrl_msg_hdr * hdr)13 static void fill_resp(const void *req, struct mctp_ctrl_msg_hdr *hdr)
14 {
15 const struct mctp_ctrl_msg_hdr *req_hdr = req;
16 hdr->ic_msg_type = MCTP_CTRL_HDR_MSG_TYPE;
17 hdr->rq_dgram_inst = req_hdr->rq_dgram_inst &
18 MCTP_CTRL_HDR_INSTANCE_ID_MASK;
19 hdr->command_code = req_hdr->command_code;
20 }
21
mctp_ctrl_set_endpoint_id(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)22 static uint8_t mctp_ctrl_set_endpoint_id(struct mctp_bus *bus, uint8_t src_eid,
23 uint8_t msg_tag, const void *data,
24 size_t len)
25 {
26 if (len != sizeof(struct mctp_ctrl_cmd_set_endpoint_id_req)) {
27 return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
28 }
29 const struct mctp_ctrl_cmd_set_endpoint_id_req *req = data;
30
31 uint8_t op = req->operation & MCTP_CTRL_SET_EID_OP_MASK;
32 if (!(op == MCTP_CTRL_SET_EID_OP_SET ||
33 op == MCTP_CTRL_SET_EID_OP_FORCE)) {
34 return MCTP_CTRL_CC_ERROR_INVALID_DATA;
35 }
36
37 if (mctp_bus_set_eid(bus->binding, req->eid)) {
38 return MCTP_CTRL_CC_ERROR_INVALID_DATA;
39 }
40
41 struct mctp_ctrl_cmd_set_endpoint_id_resp *resp =
42 __mctp_msg_alloc(sizeof(*resp), bus->mctp);
43 if (!resp) {
44 mctp_prdebug("no response buffer");
45 return MCTP_CTRL_CC_ERROR;
46 }
47 memset(resp, 0x00, sizeof(*resp));
48 fill_resp(data, &resp->hdr);
49 resp->completion_code = MCTP_CTRL_CC_SUCCESS;
50 resp->status = MCTP_CTRL_SET_EID_STATUS_ACCEPTED;
51 resp->eid = req->eid;
52 resp->pool_size = 0;
53
54 int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
55 resp, sizeof(*resp));
56 if (!rc) {
57 mctp_prdebug("set_endpoint_id response send failed: %d", rc);
58 }
59 return MCTP_CTRL_CC_SUCCESS;
60 }
61
mctp_ctrl_get_endpoint_id(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)62 static uint8_t mctp_ctrl_get_endpoint_id(struct mctp_bus *bus, uint8_t src_eid,
63 uint8_t msg_tag, const void *data,
64 size_t len)
65 {
66 if (len != sizeof(struct mctp_ctrl_msg_hdr)) {
67 /* Expect empty request */
68 return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
69 }
70 (void)data;
71
72 struct mctp_ctrl_cmd_get_endpoint_id_resp *resp =
73 __mctp_msg_alloc(sizeof(*resp), bus->mctp);
74 if (!resp) {
75 mctp_prdebug("no response buffer");
76 return MCTP_CTRL_CC_ERROR;
77 }
78 memset(resp, 0x00, sizeof(*resp));
79 fill_resp(data, &resp->hdr);
80 resp->completion_code = MCTP_CTRL_CC_SUCCESS;
81 resp->endpoint_id = bus->eid;
82 resp->endpoint_type = MCTP_CTRL_ENDPOINT_TYPE_SIMPLE |
83 MCTP_CTRL_ENDPOINT_ID_TYPE_STATIC;
84 resp->medium_specific = 0x00;
85
86 int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
87 resp, sizeof(*resp));
88 if (!rc) {
89 mctp_prdebug("get_endpoint_id response send failed: %d", rc);
90 }
91 return MCTP_CTRL_CC_SUCCESS;
92 }
93
94 #define MCTP_PROTOCOL_COUNT 4
95 /* Big endian */
96 const uint8_t MCTP_PROTOCOL_VERSIONS[MCTP_PROTOCOL_COUNT * 4] = {
97 // 1.0
98 0xf1,
99 0xf0,
100 0xff,
101 0x00,
102 // 1.1
103 0xf1,
104 0xf1,
105 0xff,
106 0x00,
107 // 1.2
108 0xf1,
109 0xf2,
110 0xff,
111 0x00,
112 // 1.3.3
113 0xf1,
114 0xf3,
115 0xf3,
116 0x00,
117 };
118
mctp_ctrl_get_version(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)119 static uint8_t mctp_ctrl_get_version(struct mctp_bus *bus, uint8_t src_eid,
120 uint8_t msg_tag, const void *data,
121 size_t len)
122 {
123 if (len != sizeof(struct mctp_ctrl_cmd_get_version_req)) {
124 return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
125 }
126 const struct mctp_ctrl_cmd_get_version_req *req = data;
127
128 switch (req->msg_type) {
129 case 0x00:
130 case 0xff:
131 /* Only have versions for MCTP base or control */
132 break;
133 default:
134 return MCTP_CTRL_VERSIONS_NOT_SUPPORTED;
135 }
136
137 /* Return only the versions for MCTP */
138 size_t total_sz = sizeof(struct mctp_ctrl_cmd_get_version_resp) +
139 sizeof(MCTP_PROTOCOL_VERSIONS);
140
141 struct mctp_ctrl_cmd_get_version_resp *resp =
142 __mctp_msg_alloc(total_sz, bus->mctp);
143 if (!resp) {
144 mctp_prdebug("no response buffer");
145 return MCTP_CTRL_CC_ERROR;
146 }
147 memset(resp, 0x00, total_sz);
148 fill_resp(data, &resp->hdr);
149 resp->completion_code = MCTP_CTRL_CC_SUCCESS;
150 resp->version_count = MCTP_PROTOCOL_COUNT;
151 memcpy(resp->versions, MCTP_PROTOCOL_VERSIONS,
152 sizeof(MCTP_PROTOCOL_VERSIONS));
153
154 int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
155 resp, total_sz);
156 if (!rc) {
157 mctp_prdebug("mctp get_version response send failed: %d", rc);
158 }
159 return MCTP_CTRL_CC_SUCCESS;
160 }
161
mctp_ctrl_get_types(struct mctp_bus * bus,uint8_t src_eid,uint8_t msg_tag,const void * data,size_t len)162 static uint8_t mctp_ctrl_get_types(struct mctp_bus *bus, uint8_t src_eid,
163 uint8_t msg_tag, const void *data,
164 size_t len)
165 {
166 if (len != sizeof(struct mctp_ctrl_msg_hdr)) {
167 return MCTP_CTRL_CC_ERROR_INVALID_LENGTH;
168 }
169 (void)data;
170
171 size_t total_sz = sizeof(struct mctp_ctrl_cmd_get_types_resp) +
172 bus->mctp->control.num_msg_types;
173
174 struct mctp_ctrl_cmd_get_types_resp *resp =
175 __mctp_msg_alloc(total_sz, bus->mctp);
176 if (!resp) {
177 mctp_prdebug("no response buffer");
178 return MCTP_CTRL_CC_ERROR;
179 }
180 memset(resp, 0x00, total_sz);
181 fill_resp(data, &resp->hdr);
182 resp->completion_code = MCTP_CTRL_CC_SUCCESS;
183 resp->type_count = bus->mctp->control.num_msg_types;
184 memcpy(resp->types, bus->mctp->control.msg_types,
185 bus->mctp->control.num_msg_types);
186
187 int rc = mctp_message_tx_alloced(bus->mctp, src_eid, false, msg_tag,
188 resp, total_sz);
189 if (!rc) {
190 mctp_prdebug("mctp get_types response send failed: %d", rc);
191 }
192 return MCTP_CTRL_CC_SUCCESS;
193 }
194
reply_error(struct mctp * mctp,uint8_t src_eid,uint8_t msg_tag,const struct mctp_ctrl_msg_hdr * ctrl_hdr,uint8_t ccode)195 static void reply_error(struct mctp *mctp, uint8_t src_eid, uint8_t msg_tag,
196 const struct mctp_ctrl_msg_hdr *ctrl_hdr, uint8_t ccode)
197 {
198 struct mctp_ctrl_cmd_empty_resp *resp =
199 __mctp_msg_alloc(sizeof(*resp), mctp);
200 if (!resp) {
201 mctp_prdebug("no response buffer");
202 return;
203 }
204 memset(resp, 0x00, sizeof(*resp));
205 fill_resp(ctrl_hdr, &resp->hdr);
206 resp->completion_code = ccode;
207
208 int rc = mctp_message_tx_alloced(mctp, src_eid, false, msg_tag, resp,
209 sizeof(*resp));
210 if (!rc) {
211 mctp_prdebug("error response send failed: %d", rc);
212 }
213 }
214
215 /* Control message request handler. This will respond to the mandatory MCTP control
216 * commands */
mctp_control_handler(struct mctp_bus * bus,mctp_eid_t src_eid,bool tag_owner,uint8_t msg_tag,const void * data,size_t len)217 bool mctp_control_handler(struct mctp_bus *bus, mctp_eid_t src_eid,
218 bool tag_owner, uint8_t msg_tag, const void *data,
219 size_t len)
220 {
221 if (!tag_owner) {
222 // Not a request
223 return false;
224 }
225
226 if (len < 1) {
227 // No type byte
228 return false;
229 }
230
231 const struct mctp_ctrl_msg_hdr *ctrl_hdr = data;
232 if (ctrl_hdr->ic_msg_type != MCTP_CTRL_HDR_MSG_TYPE) {
233 // Not Control type
234 return false;
235 }
236
237 if (len < sizeof(struct mctp_ctrl_msg_hdr)) {
238 // Drop short messages, but treat as handled
239 return true;
240 }
241
242 if ((ctrl_hdr->rq_dgram_inst &
243 (MCTP_CTRL_HDR_FLAG_REQUEST | MCTP_CTRL_HDR_FLAG_DGRAM)) !=
244 MCTP_CTRL_HDR_FLAG_REQUEST) {
245 // Drop message, isn't a request.
246 // Treat as handled since TO bit was set.
247 return true;
248 }
249
250 // A valid MCTP Control request has been received, process it
251
252 uint8_t cc = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
253 switch (ctrl_hdr->command_code) {
254 case MCTP_CTRL_CMD_SET_ENDPOINT_ID:
255 cc = mctp_ctrl_set_endpoint_id(bus, src_eid, msg_tag, data,
256 len);
257 break;
258 case MCTP_CTRL_CMD_GET_ENDPOINT_ID:
259 cc = mctp_ctrl_get_endpoint_id(bus, src_eid, msg_tag, data,
260 len);
261 break;
262 case MCTP_CTRL_CMD_GET_VERSION_SUPPORT:
263 cc = mctp_ctrl_get_version(bus, src_eid, msg_tag, data, len);
264 break;
265 case MCTP_CTRL_CMD_GET_MESSAGE_TYPE_SUPPORT:
266 cc = mctp_ctrl_get_types(bus, src_eid, msg_tag, data, len);
267 break;
268 default:
269 cc = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD;
270 break;
271 }
272
273 if (cc) {
274 reply_error(bus->mctp, src_eid, msg_tag, ctrl_hdr, cc);
275 }
276
277 // No further handling required.
278 return true;
279 }
280
mctp_control_add_type(struct mctp * mctp,uint8_t msg_type)281 int mctp_control_add_type(struct mctp *mctp, uint8_t msg_type)
282 {
283 /* Check for existing */
284 for (size_t i = 0; i < mctp->control.num_msg_types; i++) {
285 if (mctp->control.msg_types[i] == msg_type) {
286 return 0;
287 }
288 }
289
290 if (mctp->control.num_msg_types == MCTP_CONTROL_MAX_TYPES) {
291 return -ENOSPC;
292 }
293
294 mctp->control.msg_types[mctp->control.num_msg_types] = msg_type;
295 mctp->control.num_msg_types++;
296 return 0;
297 }
298
mctp_control_remove_type(struct mctp * mctp,uint8_t msg_type)299 void mctp_control_remove_type(struct mctp *mctp, uint8_t msg_type)
300 {
301 for (size_t i = 0; i < mctp->control.num_msg_types; i++) {
302 if (mctp->control.msg_types[i] == msg_type) {
303 memmove(&mctp->control.msg_types[i],
304 &mctp->control.msg_types[i + 1],
305 mctp->control.num_msg_types - (i + 1));
306 mctp->control.num_msg_types--;
307 }
308 }
309 }
310