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