xref: /openbmc/libpldm/src/control.c (revision bde874e9c057b537da85f5fe96a2c436639fc4a2)
1*bde874e9SMatt Johnston #include <stdint.h>
2*bde874e9SMatt Johnston #include <stdbool.h>
3*bde874e9SMatt Johnston #include <string.h>
4*bde874e9SMatt Johnston 
5*bde874e9SMatt Johnston #include <libpldm/pldm.h>
6*bde874e9SMatt Johnston #include <libpldm/utils.h>
7*bde874e9SMatt Johnston #include <libpldm/platform.h>
8*bde874e9SMatt Johnston #include <libpldm/control.h>
9*bde874e9SMatt Johnston #include <compiler.h>
10*bde874e9SMatt Johnston #include <msgbuf.h>
11*bde874e9SMatt Johnston 
12*bde874e9SMatt Johnston #include "control-internal.h"
13*bde874e9SMatt Johnston 
14*bde874e9SMatt Johnston #define PLDM_BASE_VERSIONS_COUNT 2
15*bde874e9SMatt Johnston static const uint32_t PLDM_BASE_VERSIONS[PLDM_BASE_VERSIONS_COUNT] = {
16*bde874e9SMatt Johnston 	/* PLDM 1.1.0 is current implemented. */
17*bde874e9SMatt Johnston 	0xf1f1f000,
18*bde874e9SMatt Johnston 	/* CRC. Calculated with python:
19*bde874e9SMatt Johnston 	hex(crccheck.crc.Crc32.calc(struct.pack('<I', 0xf1f1f000)))
20*bde874e9SMatt Johnston 	*/
21*bde874e9SMatt Johnston 	0x539dbeba,
22*bde874e9SMatt Johnston };
23*bde874e9SMatt Johnston const bitfield8_t PLDM_CONTROL_COMMANDS[32] = {
24*bde874e9SMatt Johnston 	// 0x00..0x07
25*bde874e9SMatt Johnston 	{ .byte = (1 << PLDM_GET_TID | 1 << PLDM_GET_PLDM_VERSION |
26*bde874e9SMatt Johnston 		   1 << PLDM_GET_PLDM_TYPES | 1 << PLDM_GET_PLDM_COMMANDS) }
27*bde874e9SMatt Johnston };
28*bde874e9SMatt Johnston 
pldm_control_reply_error(uint8_t ccode,const struct pldm_header_info * req_hdr,struct pldm_msg * resp,size_t * resp_payload_len)29*bde874e9SMatt Johnston static int pldm_control_reply_error(uint8_t ccode,
30*bde874e9SMatt Johnston 				    const struct pldm_header_info *req_hdr,
31*bde874e9SMatt Johnston 				    struct pldm_msg *resp,
32*bde874e9SMatt Johnston 				    size_t *resp_payload_len)
33*bde874e9SMatt Johnston {
34*bde874e9SMatt Johnston 	int rc;
35*bde874e9SMatt Johnston 
36*bde874e9SMatt Johnston 	/* 1 byte completion code */
37*bde874e9SMatt Johnston 	if (*resp_payload_len < 1) {
38*bde874e9SMatt Johnston 		return -EOVERFLOW;
39*bde874e9SMatt Johnston 	}
40*bde874e9SMatt Johnston 	*resp_payload_len = 1;
41*bde874e9SMatt Johnston 
42*bde874e9SMatt Johnston 	rc = encode_cc_only_resp(req_hdr->instance, PLDM_FWUP, req_hdr->command,
43*bde874e9SMatt Johnston 				 ccode, resp);
44*bde874e9SMatt Johnston 	if (rc != PLDM_SUCCESS) {
45*bde874e9SMatt Johnston 		return -EINVAL;
46*bde874e9SMatt Johnston 	}
47*bde874e9SMatt Johnston 	return 0;
48*bde874e9SMatt Johnston }
49*bde874e9SMatt Johnston 
pldm_control_get_tid(const struct pldm_header_info * hdr,const struct pldm_msg * req LIBPLDM_CC_UNUSED,size_t req_payload_len,struct pldm_msg * resp,size_t * resp_payload_len)50*bde874e9SMatt Johnston static int pldm_control_get_tid(const struct pldm_header_info *hdr,
51*bde874e9SMatt Johnston 				const struct pldm_msg *req LIBPLDM_CC_UNUSED,
52*bde874e9SMatt Johnston 				size_t req_payload_len, struct pldm_msg *resp,
53*bde874e9SMatt Johnston 				size_t *resp_payload_len)
54*bde874e9SMatt Johnston {
55*bde874e9SMatt Johnston 	if (req_payload_len != PLDM_GET_TID_REQ_BYTES) {
56*bde874e9SMatt Johnston 		return pldm_control_reply_error(PLDM_ERROR_INVALID_LENGTH, hdr,
57*bde874e9SMatt Johnston 						resp, resp_payload_len);
58*bde874e9SMatt Johnston 	}
59*bde874e9SMatt Johnston 
60*bde874e9SMatt Johnston 	if (*resp_payload_len <= PLDM_GET_TID_RESP_BYTES) {
61*bde874e9SMatt Johnston 		return -EOVERFLOW;
62*bde874e9SMatt Johnston 	}
63*bde874e9SMatt Johnston 	*resp_payload_len = PLDM_GET_TID_RESP_BYTES;
64*bde874e9SMatt Johnston 
65*bde874e9SMatt Johnston 	uint8_t cc = encode_get_tid_resp(hdr->instance, PLDM_SUCCESS,
66*bde874e9SMatt Johnston 					 PLDM_TID_UNASSIGNED, resp);
67*bde874e9SMatt Johnston 	if (cc) {
68*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
69*bde874e9SMatt Johnston 						resp_payload_len);
70*bde874e9SMatt Johnston 	}
71*bde874e9SMatt Johnston 	return 0;
72*bde874e9SMatt Johnston }
73*bde874e9SMatt Johnston 
pldm_control_get_version(struct pldm_control * control,const struct pldm_header_info * hdr,const struct pldm_msg * req,size_t req_payload_len,struct pldm_msg * resp,size_t * resp_payload_len)74*bde874e9SMatt Johnston static int pldm_control_get_version(struct pldm_control *control,
75*bde874e9SMatt Johnston 				    const struct pldm_header_info *hdr,
76*bde874e9SMatt Johnston 				    const struct pldm_msg *req,
77*bde874e9SMatt Johnston 				    size_t req_payload_len,
78*bde874e9SMatt Johnston 				    struct pldm_msg *resp,
79*bde874e9SMatt Johnston 				    size_t *resp_payload_len)
80*bde874e9SMatt Johnston {
81*bde874e9SMatt Johnston 	uint8_t cc;
82*bde874e9SMatt Johnston 
83*bde874e9SMatt Johnston 	uint32_t handle;
84*bde874e9SMatt Johnston 	uint8_t opflag;
85*bde874e9SMatt Johnston 	uint8_t type;
86*bde874e9SMatt Johnston 	cc = decode_get_version_req(req, req_payload_len, &handle, &opflag,
87*bde874e9SMatt Johnston 				    &type);
88*bde874e9SMatt Johnston 	if (cc) {
89*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
90*bde874e9SMatt Johnston 						resp_payload_len);
91*bde874e9SMatt Johnston 	}
92*bde874e9SMatt Johnston 
93*bde874e9SMatt Johnston 	/* Response is always sent as a single transfer */
94*bde874e9SMatt Johnston 	if (opflag != PLDM_GET_FIRSTPART) {
95*bde874e9SMatt Johnston 		return pldm_control_reply_error(
96*bde874e9SMatt Johnston 			PLDM_CONTROL_INVALID_TRANSFER_OPERATION_FLAG, hdr, resp,
97*bde874e9SMatt Johnston 			resp_payload_len);
98*bde874e9SMatt Johnston 	}
99*bde874e9SMatt Johnston 
100*bde874e9SMatt Johnston 	const struct pldm_type_versions *v = NULL;
101*bde874e9SMatt Johnston 	for (int i = 0; i < PLDM_CONTROL_MAX_VERSION_TYPES; i++) {
102*bde874e9SMatt Johnston 		if (control->types[i].pldm_type == type &&
103*bde874e9SMatt Johnston 		    control->types[i].versions) {
104*bde874e9SMatt Johnston 			v = &control->types[i];
105*bde874e9SMatt Johnston 			break;
106*bde874e9SMatt Johnston 		}
107*bde874e9SMatt Johnston 	}
108*bde874e9SMatt Johnston 
109*bde874e9SMatt Johnston 	if (!v) {
110*bde874e9SMatt Johnston 		return pldm_control_reply_error(
111*bde874e9SMatt Johnston 			PLDM_CONTROL_INVALID_PLDM_TYPE_IN_REQUEST_DATA, hdr,
112*bde874e9SMatt Johnston 			resp, resp_payload_len);
113*bde874e9SMatt Johnston 	}
114*bde874e9SMatt Johnston 
115*bde874e9SMatt Johnston 	/* encode_get_version_resp doesn't have length checking */
116*bde874e9SMatt Johnston 	uint32_t required_resp_payload =
117*bde874e9SMatt Johnston 		1 + 4 + 1 + v->versions_count * sizeof(ver32_t);
118*bde874e9SMatt Johnston 	if (*resp_payload_len < required_resp_payload) {
119*bde874e9SMatt Johnston 		return -EOVERFLOW;
120*bde874e9SMatt Johnston 	}
121*bde874e9SMatt Johnston 	*resp_payload_len = required_resp_payload;
122*bde874e9SMatt Johnston 
123*bde874e9SMatt Johnston 	/* crc32 is included in the versions buffer */
124*bde874e9SMatt Johnston 	cc = encode_get_version_resp(hdr->instance, PLDM_SUCCESS, 0,
125*bde874e9SMatt Johnston 				     PLDM_START_AND_END, v->versions,
126*bde874e9SMatt Johnston 				     v->versions_count * sizeof(ver32_t), resp);
127*bde874e9SMatt Johnston 	if (cc) {
128*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
129*bde874e9SMatt Johnston 						resp_payload_len);
130*bde874e9SMatt Johnston 	}
131*bde874e9SMatt Johnston 	return 0;
132*bde874e9SMatt Johnston }
133*bde874e9SMatt Johnston 
pldm_control_get_types(struct pldm_control * control,const struct pldm_header_info * hdr,const struct pldm_msg * req LIBPLDM_CC_UNUSED,size_t req_payload_len,struct pldm_msg * resp,size_t * resp_payload_len)134*bde874e9SMatt Johnston static int pldm_control_get_types(struct pldm_control *control,
135*bde874e9SMatt Johnston 				  const struct pldm_header_info *hdr,
136*bde874e9SMatt Johnston 				  const struct pldm_msg *req LIBPLDM_CC_UNUSED,
137*bde874e9SMatt Johnston 				  size_t req_payload_len, struct pldm_msg *resp,
138*bde874e9SMatt Johnston 				  size_t *resp_payload_len)
139*bde874e9SMatt Johnston {
140*bde874e9SMatt Johnston 	uint8_t cc;
141*bde874e9SMatt Johnston 
142*bde874e9SMatt Johnston 	if (req_payload_len != PLDM_GET_TYPES_REQ_BYTES) {
143*bde874e9SMatt Johnston 		return pldm_control_reply_error(PLDM_ERROR_INVALID_LENGTH, hdr,
144*bde874e9SMatt Johnston 						resp, resp_payload_len);
145*bde874e9SMatt Johnston 	}
146*bde874e9SMatt Johnston 
147*bde874e9SMatt Johnston 	bitfield8_t types[8];
148*bde874e9SMatt Johnston 	memset(types, 0, sizeof(types));
149*bde874e9SMatt Johnston 	for (int i = 0; i < PLDM_CONTROL_MAX_VERSION_TYPES; i++) {
150*bde874e9SMatt Johnston 		uint8_t ty = control->types[i].pldm_type;
151*bde874e9SMatt Johnston 		if (ty < 64 && control->types[i].versions) {
152*bde874e9SMatt Johnston 			uint8_t bit = 1 << (ty % 8);
153*bde874e9SMatt Johnston 			types[ty / 8].byte |= bit;
154*bde874e9SMatt Johnston 		}
155*bde874e9SMatt Johnston 	}
156*bde874e9SMatt Johnston 
157*bde874e9SMatt Johnston 	/* encode_get_types_resp doesn't have length checking */
158*bde874e9SMatt Johnston 	uint32_t required_resp_payload = 1 + 8;
159*bde874e9SMatt Johnston 	if (*resp_payload_len < required_resp_payload) {
160*bde874e9SMatt Johnston 		return -EOVERFLOW;
161*bde874e9SMatt Johnston 	}
162*bde874e9SMatt Johnston 	*resp_payload_len = required_resp_payload;
163*bde874e9SMatt Johnston 
164*bde874e9SMatt Johnston 	cc = encode_get_types_resp(hdr->instance, PLDM_SUCCESS, types, resp);
165*bde874e9SMatt Johnston 	if (cc) {
166*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
167*bde874e9SMatt Johnston 						resp_payload_len);
168*bde874e9SMatt Johnston 	}
169*bde874e9SMatt Johnston 	return 0;
170*bde874e9SMatt Johnston }
171*bde874e9SMatt Johnston 
pldm_control_get_commands(struct pldm_control * control,const struct pldm_header_info * hdr,const struct pldm_msg * req,size_t req_payload_len,struct pldm_msg * resp,size_t * resp_payload_len)172*bde874e9SMatt Johnston static int pldm_control_get_commands(struct pldm_control *control,
173*bde874e9SMatt Johnston 				     const struct pldm_header_info *hdr,
174*bde874e9SMatt Johnston 				     const struct pldm_msg *req,
175*bde874e9SMatt Johnston 				     size_t req_payload_len,
176*bde874e9SMatt Johnston 				     struct pldm_msg *resp,
177*bde874e9SMatt Johnston 				     size_t *resp_payload_len)
178*bde874e9SMatt Johnston {
179*bde874e9SMatt Johnston 	uint8_t cc;
180*bde874e9SMatt Johnston 
181*bde874e9SMatt Johnston 	uint8_t ty;
182*bde874e9SMatt Johnston 	// version in request is ignored, since SelectPLDMVersion isn't supported currently
183*bde874e9SMatt Johnston 	ver32_t version;
184*bde874e9SMatt Johnston 	cc = decode_get_commands_req(req, req_payload_len, &ty, &version);
185*bde874e9SMatt Johnston 	if (cc) {
186*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
187*bde874e9SMatt Johnston 						resp_payload_len);
188*bde874e9SMatt Johnston 	}
189*bde874e9SMatt Johnston 
190*bde874e9SMatt Johnston 	const struct pldm_type_versions *v = NULL;
191*bde874e9SMatt Johnston 	for (int i = 0; i < PLDM_CONTROL_MAX_VERSION_TYPES; i++) {
192*bde874e9SMatt Johnston 		if (control->types[i].pldm_type == ty &&
193*bde874e9SMatt Johnston 		    control->types[i].versions && control->types[i].commands) {
194*bde874e9SMatt Johnston 			v = &control->types[i];
195*bde874e9SMatt Johnston 			break;
196*bde874e9SMatt Johnston 		}
197*bde874e9SMatt Johnston 	}
198*bde874e9SMatt Johnston 
199*bde874e9SMatt Johnston 	if (!v) {
200*bde874e9SMatt Johnston 		return pldm_control_reply_error(
201*bde874e9SMatt Johnston 			PLDM_CONTROL_INVALID_PLDM_TYPE_IN_REQUEST_DATA, hdr,
202*bde874e9SMatt Johnston 			resp, resp_payload_len);
203*bde874e9SMatt Johnston 	}
204*bde874e9SMatt Johnston 
205*bde874e9SMatt Johnston 	/* encode_get_commands_resp doesn't have length checking */
206*bde874e9SMatt Johnston 	uint32_t required_resp_payload = 1 + 32;
207*bde874e9SMatt Johnston 	if (*resp_payload_len < required_resp_payload) {
208*bde874e9SMatt Johnston 		return -EOVERFLOW;
209*bde874e9SMatt Johnston 	}
210*bde874e9SMatt Johnston 	*resp_payload_len = required_resp_payload;
211*bde874e9SMatt Johnston 
212*bde874e9SMatt Johnston 	cc = encode_get_commands_resp(hdr->instance, PLDM_SUCCESS, v->commands,
213*bde874e9SMatt Johnston 				      resp);
214*bde874e9SMatt Johnston 	if (cc) {
215*bde874e9SMatt Johnston 		return pldm_control_reply_error(cc, hdr, resp,
216*bde874e9SMatt Johnston 						resp_payload_len);
217*bde874e9SMatt Johnston 	}
218*bde874e9SMatt Johnston 	return 0;
219*bde874e9SMatt Johnston }
220*bde874e9SMatt Johnston 
221*bde874e9SMatt Johnston /* A response should only be used when this returns 0, and *resp_len > 0 */
222*bde874e9SMatt Johnston LIBPLDM_ABI_TESTING
pldm_control_handle_msg(struct pldm_control * control,const void * req_msg,size_t req_len,void * resp_msg,size_t * resp_len)223*bde874e9SMatt Johnston int pldm_control_handle_msg(struct pldm_control *control, const void *req_msg,
224*bde874e9SMatt Johnston 			    size_t req_len, void *resp_msg, size_t *resp_len)
225*bde874e9SMatt Johnston {
226*bde874e9SMatt Johnston 	int rc;
227*bde874e9SMatt Johnston 
228*bde874e9SMatt Johnston 	/* Space for header plus completion code */
229*bde874e9SMatt Johnston 	if (*resp_len < sizeof(struct pldm_msg_hdr) + 1) {
230*bde874e9SMatt Johnston 		return -EOVERFLOW;
231*bde874e9SMatt Johnston 	}
232*bde874e9SMatt Johnston 	size_t resp_payload_len = *resp_len - sizeof(struct pldm_msg_hdr);
233*bde874e9SMatt Johnston 	struct pldm_msg *resp = resp_msg;
234*bde874e9SMatt Johnston 
235*bde874e9SMatt Johnston 	if (req_len < sizeof(struct pldm_msg_hdr)) {
236*bde874e9SMatt Johnston 		return -EOVERFLOW;
237*bde874e9SMatt Johnston 	}
238*bde874e9SMatt Johnston 	size_t req_payload_len = req_len - sizeof(struct pldm_msg_hdr);
239*bde874e9SMatt Johnston 	const struct pldm_msg *req = req_msg;
240*bde874e9SMatt Johnston 
241*bde874e9SMatt Johnston 	struct pldm_header_info hdr;
242*bde874e9SMatt Johnston 	rc = unpack_pldm_header(&req->hdr, &hdr);
243*bde874e9SMatt Johnston 	if (rc != PLDM_SUCCESS) {
244*bde874e9SMatt Johnston 		return -EINVAL;
245*bde874e9SMatt Johnston 	}
246*bde874e9SMatt Johnston 
247*bde874e9SMatt Johnston 	if (hdr.pldm_type != PLDM_BASE) {
248*bde874e9SMatt Johnston 		/* Caller should not have passed non-control */
249*bde874e9SMatt Johnston 		return -ENOMSG;
250*bde874e9SMatt Johnston 	}
251*bde874e9SMatt Johnston 
252*bde874e9SMatt Johnston 	if (hdr.msg_type != PLDM_REQUEST) {
253*bde874e9SMatt Johnston 		return -EINVAL;
254*bde874e9SMatt Johnston 	}
255*bde874e9SMatt Johnston 
256*bde874e9SMatt Johnston 	/* Dispatch command */
257*bde874e9SMatt Johnston 	switch (hdr.command) {
258*bde874e9SMatt Johnston 	case PLDM_GET_TID:
259*bde874e9SMatt Johnston 		rc = pldm_control_get_tid(&hdr, req, req_payload_len, resp,
260*bde874e9SMatt Johnston 					  &resp_payload_len);
261*bde874e9SMatt Johnston 		break;
262*bde874e9SMatt Johnston 	case PLDM_GET_PLDM_VERSION:
263*bde874e9SMatt Johnston 		rc = pldm_control_get_version(control, &hdr, req,
264*bde874e9SMatt Johnston 					      req_payload_len, resp,
265*bde874e9SMatt Johnston 					      &resp_payload_len);
266*bde874e9SMatt Johnston 		break;
267*bde874e9SMatt Johnston 	case PLDM_GET_PLDM_TYPES:
268*bde874e9SMatt Johnston 		rc = pldm_control_get_types(control, &hdr, req, req_payload_len,
269*bde874e9SMatt Johnston 					    resp, &resp_payload_len);
270*bde874e9SMatt Johnston 		break;
271*bde874e9SMatt Johnston 	case PLDM_GET_PLDM_COMMANDS:
272*bde874e9SMatt Johnston 		rc = pldm_control_get_commands(control, &hdr, req,
273*bde874e9SMatt Johnston 					       req_payload_len, resp,
274*bde874e9SMatt Johnston 					       &resp_payload_len);
275*bde874e9SMatt Johnston 		break;
276*bde874e9SMatt Johnston 	default:
277*bde874e9SMatt Johnston 		rc = pldm_control_reply_error(PLDM_ERROR_UNSUPPORTED_PLDM_CMD,
278*bde874e9SMatt Johnston 					      &hdr, resp, &resp_payload_len);
279*bde874e9SMatt Johnston 	}
280*bde874e9SMatt Johnston 
281*bde874e9SMatt Johnston 	if (rc == 0) {
282*bde874e9SMatt Johnston 		*resp_len = resp_payload_len + sizeof(struct pldm_msg_hdr);
283*bde874e9SMatt Johnston 	}
284*bde874e9SMatt Johnston 
285*bde874e9SMatt Johnston 	return rc;
286*bde874e9SMatt Johnston }
287*bde874e9SMatt Johnston 
288*bde874e9SMatt Johnston LIBPLDM_ABI_TESTING
pldm_control_setup(struct pldm_control * control,size_t pldm_control_size)289*bde874e9SMatt Johnston int pldm_control_setup(struct pldm_control *control, size_t pldm_control_size)
290*bde874e9SMatt Johnston {
291*bde874e9SMatt Johnston 	int rc;
292*bde874e9SMatt Johnston 
293*bde874e9SMatt Johnston 	if (pldm_control_size < sizeof(struct pldm_control)) {
294*bde874e9SMatt Johnston 		return -EINVAL;
295*bde874e9SMatt Johnston 	}
296*bde874e9SMatt Johnston 
297*bde874e9SMatt Johnston 	memset(control, 0, sizeof(struct pldm_control));
298*bde874e9SMatt Johnston 
299*bde874e9SMatt Johnston 	rc = pldm_control_add_type(control, PLDM_BASE, &PLDM_BASE_VERSIONS,
300*bde874e9SMatt Johnston 				   PLDM_BASE_VERSIONS_COUNT,
301*bde874e9SMatt Johnston 				   PLDM_CONTROL_COMMANDS);
302*bde874e9SMatt Johnston 	if (rc) {
303*bde874e9SMatt Johnston 		return rc;
304*bde874e9SMatt Johnston 	}
305*bde874e9SMatt Johnston 
306*bde874e9SMatt Johnston 	return 0;
307*bde874e9SMatt Johnston }
308*bde874e9SMatt Johnston 
309*bde874e9SMatt Johnston LIBPLDM_ABI_TESTING
pldm_control_add_type(struct pldm_control * control,uint8_t pldm_type,const void * versions,size_t versions_count,const bitfield8_t * commands)310*bde874e9SMatt Johnston int pldm_control_add_type(struct pldm_control *control, uint8_t pldm_type,
311*bde874e9SMatt Johnston 			  const void *versions, size_t versions_count,
312*bde874e9SMatt Johnston 			  const bitfield8_t *commands)
313*bde874e9SMatt Johnston {
314*bde874e9SMatt Johnston 	if (versions_count < 2) {
315*bde874e9SMatt Johnston 		/* At least one version must be provided, along with a CRC32 */
316*bde874e9SMatt Johnston 		return -EINVAL;
317*bde874e9SMatt Johnston 	}
318*bde874e9SMatt Johnston 
319*bde874e9SMatt Johnston 	struct pldm_type_versions *v = NULL;
320*bde874e9SMatt Johnston 	for (int i = 0; i < PLDM_CONTROL_MAX_VERSION_TYPES; i++) {
321*bde874e9SMatt Johnston 		if (control->types[i].versions == NULL ||
322*bde874e9SMatt Johnston 		    (control->types[i].versions != NULL &&
323*bde874e9SMatt Johnston 		     control->types[i].pldm_type == pldm_type)) {
324*bde874e9SMatt Johnston 			v = &control->types[i];
325*bde874e9SMatt Johnston 			break;
326*bde874e9SMatt Johnston 		}
327*bde874e9SMatt Johnston 	}
328*bde874e9SMatt Johnston 
329*bde874e9SMatt Johnston 	if (!v) {
330*bde874e9SMatt Johnston 		return -ENOMEM;
331*bde874e9SMatt Johnston 		// No spare slots
332*bde874e9SMatt Johnston 	}
333*bde874e9SMatt Johnston 
334*bde874e9SMatt Johnston 	v->pldm_type = pldm_type;
335*bde874e9SMatt Johnston 	v->versions = versions;
336*bde874e9SMatt Johnston 	v->versions_count = versions_count;
337*bde874e9SMatt Johnston 	v->commands = commands;
338*bde874e9SMatt Johnston 
339*bde874e9SMatt Johnston 	return 0;
340*bde874e9SMatt Johnston }
341