xref: /openbmc/libpldm/src/oem/meta/file_io.c (revision 7a8d932bc3cd30a0869b2e5cfd38c1b87019cffb)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include <libpldm/oem/meta/file_io.h>
3 #include <endian.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 
8 #include "api.h"
9 #include "msgbuf.h"
10 #include "dsp/base.h"
11 
12 LIBPLDM_ABI_STABLE
pldm_oem_meta_file_io_write_req_data(struct pldm_oem_meta_file_io_write_req * req)13 void *pldm_oem_meta_file_io_write_req_data(
14 	struct pldm_oem_meta_file_io_write_req *req)
15 {
16 	return req->data;
17 }
18 
19 LIBPLDM_ABI_STABLE
decode_oem_meta_file_io_write_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_oem_meta_file_io_write_req * req,size_t req_length)20 int decode_oem_meta_file_io_write_req(
21 	const struct pldm_msg *msg, size_t payload_length,
22 	struct pldm_oem_meta_file_io_write_req *req, size_t req_length)
23 {
24 	PLDM_MSGBUF_RO_DEFINE_P(buf);
25 	int rc;
26 
27 	if (msg == NULL || req == NULL) {
28 		return -EINVAL;
29 	}
30 
31 	if (req_length < sizeof(*req)) {
32 		return -EINVAL;
33 	}
34 
35 	rc = pldm_msgbuf_init_errno(buf,
36 				    PLDM_OEM_META_FILE_IO_WRITE_REQ_MIN_LENGTH,
37 				    msg->payload, payload_length);
38 	if (rc) {
39 		return rc;
40 	}
41 
42 	pldm_msgbuf_extract(buf, req->handle);
43 	rc = pldm_msgbuf_extract(buf, req->length);
44 	if (rc) {
45 		return pldm_msgbuf_discard(buf, rc);
46 	}
47 
48 	rc = pldm_msgbuf_extract_array(buf, req->length, req->data,
49 				       req_length - sizeof(*req));
50 	if (rc) {
51 		return pldm_msgbuf_discard(buf, rc);
52 	}
53 
54 	return pldm_msgbuf_complete_consumed(buf);
55 }
56 
57 LIBPLDM_ABI_DEPRECATED_UNSAFE
decode_oem_meta_file_io_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * file_handle,uint32_t * length,uint8_t * data)58 int decode_oem_meta_file_io_req(const struct pldm_msg *msg,
59 				size_t payload_length, uint8_t *file_handle,
60 				uint32_t *length, uint8_t *data)
61 {
62 	struct pldm_oem_meta_file_io_write_req *request_msg;
63 	size_t request_msg_len;
64 	int rc;
65 
66 	if (msg == NULL || file_handle == NULL || length == NULL ||
67 	    data == NULL) {
68 		return pldm_xlate_errno(-EINVAL);
69 	}
70 
71 	if (SIZE_MAX - sizeof(*request_msg) < payload_length) {
72 		return pldm_xlate_errno(-EOVERFLOW);
73 	}
74 
75 	request_msg_len = sizeof(*request_msg) + payload_length;
76 	request_msg = malloc(request_msg_len);
77 
78 	rc = decode_oem_meta_file_io_write_req(msg, payload_length, request_msg,
79 					       request_msg_len);
80 	if (rc < 0) {
81 		free(request_msg);
82 		return pldm_xlate_errno(rc);
83 	}
84 
85 	*file_handle = request_msg->handle;
86 	*length = request_msg->length;
87 
88 	/* NOTE: Unsafe, memory safety is not possible due to API constraints. */
89 	memcpy(data, request_msg->data, request_msg->length);
90 
91 	free(request_msg);
92 
93 	return 0;
94 }
95 
96 LIBPLDM_ABI_STABLE
decode_oem_meta_file_io_read_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_oem_meta_file_io_read_req * req)97 int decode_oem_meta_file_io_read_req(const struct pldm_msg *msg,
98 				     size_t payload_length,
99 				     struct pldm_oem_meta_file_io_read_req *req)
100 {
101 	PLDM_MSGBUF_RO_DEFINE_P(buf);
102 
103 	if (msg == NULL || req == NULL) {
104 		return -EINVAL;
105 	}
106 
107 	if (req->version > sizeof(struct pldm_oem_meta_file_io_read_req)) {
108 		return -E2BIG;
109 	}
110 
111 	int rc = pldm_msgbuf_init_errno(
112 		buf, PLDM_OEM_META_FILE_IO_READ_REQ_MIN_LENGTH, msg->payload,
113 		payload_length);
114 	if (rc) {
115 		return rc;
116 	}
117 
118 	pldm_msgbuf_extract(buf, req->handle);
119 	rc = pldm_msgbuf_extract(buf, req->option);
120 	if (rc) {
121 		return pldm_msgbuf_discard(buf, rc);
122 	}
123 
124 	rc = pldm_msgbuf_extract(buf, req->length);
125 	if (rc) {
126 		return pldm_msgbuf_discard(buf, rc);
127 	}
128 
129 	switch (req->option) {
130 	case PLDM_OEM_META_FILE_IO_READ_ATTR:
131 		if (req->length != 0) {
132 			return pldm_msgbuf_discard(buf, -EPROTO);
133 		}
134 		break;
135 	case PLDM_OEM_META_FILE_IO_READ_DATA:
136 		pldm_msgbuf_extract(buf, req->info.data.transferFlag);
137 		pldm_msgbuf_extract(buf, req->info.data.offset);
138 		break;
139 	default:
140 		return pldm_msgbuf_discard(buf, -EPROTO);
141 	}
142 
143 	return pldm_msgbuf_complete_consumed(buf);
144 }
145 
146 LIBPLDM_ABI_STABLE
pldm_oem_meta_file_io_read_resp_data(struct pldm_oem_meta_file_io_read_resp * resp)147 void *pldm_oem_meta_file_io_read_resp_data(
148 	struct pldm_oem_meta_file_io_read_resp *resp)
149 {
150 	return resp->data;
151 }
152 
153 LIBPLDM_ABI_STABLE
encode_oem_meta_file_io_read_resp(uint8_t instance_id,struct pldm_oem_meta_file_io_read_resp * resp,size_t resp_len,struct pldm_msg * responseMsg,size_t payload_length)154 int encode_oem_meta_file_io_read_resp(
155 	uint8_t instance_id, struct pldm_oem_meta_file_io_read_resp *resp,
156 	size_t resp_len, struct pldm_msg *responseMsg, size_t payload_length)
157 {
158 	int rc;
159 	PLDM_MSGBUF_RW_DEFINE_P(buf);
160 	struct pldm_header_info header = { 0 };
161 
162 	if (resp == NULL || responseMsg == NULL) {
163 		return -EINVAL;
164 	}
165 
166 	if (resp_len < sizeof(*resp)) {
167 		return -EINVAL;
168 	}
169 
170 	if (resp->version > sizeof(*resp)) {
171 		return -E2BIG;
172 	}
173 
174 	header.instance = instance_id;
175 	header.msg_type = PLDM_RESPONSE;
176 	header.pldm_type = PLDM_OEM;
177 	header.command = PLDM_OEM_META_FILE_IO_CMD_READ_FILE;
178 	rc = pack_pldm_header_errno(&header, &(responseMsg->hdr));
179 	if (rc) {
180 		return rc;
181 	}
182 
183 	rc = pldm_msgbuf_init_errno(buf,
184 				    PLDM_OEM_META_FILE_IO_READ_RESP_MIN_SIZE,
185 				    responseMsg->payload, payload_length);
186 	if (rc) {
187 		return rc;
188 	}
189 
190 	pldm_msgbuf_insert(buf, resp->completion_code);
191 	pldm_msgbuf_insert(buf, resp->handle);
192 	pldm_msgbuf_insert(buf, resp->option);
193 	pldm_msgbuf_insert(buf, resp->length);
194 
195 	switch (resp->option) {
196 	case PLDM_OEM_META_FILE_IO_READ_ATTR:
197 		pldm_msgbuf_insert(buf, resp->info.attr.size);
198 		pldm_msgbuf_insert(buf, resp->info.attr.crc32);
199 		break;
200 	case PLDM_OEM_META_FILE_IO_READ_DATA:
201 		pldm_msgbuf_insert(buf, resp->info.data.transferFlag);
202 		pldm_msgbuf_insert(buf, resp->info.data.offset);
203 		rc = pldm_msgbuf_insert_array_uint8(buf, resp->length,
204 						    resp->data,
205 						    resp_len - sizeof(*resp));
206 		if (rc) {
207 			return pldm_msgbuf_discard(buf, rc);
208 		}
209 		break;
210 	default:
211 		return pldm_msgbuf_discard(buf, -EPROTO);
212 	}
213 
214 	return pldm_msgbuf_complete(buf);
215 }
216