xref: /openbmc/libmctp/control.c (revision 4058b2cb)
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