xref: /openbmc/libpldm/src/dsp/bios_table.c (revision 8c37ab36)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "array.h"
3 
4 #include <libpldm/base.h>
5 #include <libpldm/bios.h>
6 #include <libpldm/bios_table.h>
7 #include <libpldm/utils.h>
8 
9 #include <assert.h>
10 #include <endian.h>
11 #include <limits.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #define POINTER_CHECK(pointer)                                                 \
18 	do {                                                                   \
19 		if ((pointer) == NULL)                                         \
20 			return PLDM_ERROR_INVALID_DATA;                        \
21 	} while (0)
22 
23 #define ATTR_TYPE_EXPECT(type, expected)                                       \
24 	do {                                                                   \
25 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
26 			return PLDM_ERROR_INVALID_DATA;                        \
27 	} while (0)
28 
29 #define BUFFER_SIZE_EXPECT(current_size, expected_size)                        \
30 	do {                                                                   \
31 		if ((current_size) < (expected_size))                          \
32 			return PLDM_ERROR_INVALID_LENGTH;                      \
33 	} while (0)
34 
35 #define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
36 
37 static void set_errmsg(const char **errmsg, const char *msg)
38 {
39 	if (errmsg != NULL) {
40 		*errmsg = msg;
41 	}
42 }
43 
44 static int get_bios_string_handle(uint16_t *val)
45 {
46 	static uint16_t handle = 0;
47 	assert(handle != UINT16_MAX);
48 	if (handle == UINT16_MAX) {
49 		return PLDM_ERROR_INVALID_DATA;
50 	}
51 
52 	*val = handle++;
53 	return PLDM_SUCCESS;
54 }
55 
56 LIBPLDM_ABI_STABLE
57 size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
58 {
59 	return sizeof(struct pldm_bios_string_table_entry) -
60 	       MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
61 }
62 
63 LIBPLDM_ABI_STABLE
64 int pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
65 					const char *str, uint16_t str_length)
66 {
67 	if (str_length == 0) {
68 		return PLDM_ERROR_INVALID_DATA;
69 	}
70 	POINTER_CHECK(entry);
71 	POINTER_CHECK(str);
72 	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
73 	BUFFER_SIZE_EXPECT(entry_length, length);
74 	struct pldm_bios_string_table_entry *string_entry = entry;
75 	uint16_t handle;
76 	int rc = get_bios_string_handle(&handle);
77 	if (rc != PLDM_SUCCESS) {
78 		return rc;
79 	}
80 	string_entry->string_handle = htole16(handle);
81 	string_entry->string_length = htole16(str_length);
82 	memcpy(string_entry->name, str, str_length);
83 	return PLDM_SUCCESS;
84 }
85 
86 LIBPLDM_ABI_STABLE
87 uint16_t pldm_bios_table_string_entry_decode_handle(
88 	const struct pldm_bios_string_table_entry *entry)
89 {
90 	return le16toh(entry->string_handle);
91 }
92 
93 LIBPLDM_ABI_STABLE
94 uint16_t pldm_bios_table_string_entry_decode_string_length(
95 	const struct pldm_bios_string_table_entry *entry)
96 {
97 	return le16toh(entry->string_length);
98 }
99 
100 LIBPLDM_ABI_STABLE
101 int pldm_bios_table_string_entry_decode_string(
102 	const struct pldm_bios_string_table_entry *entry, char *buffer,
103 	size_t size)
104 {
105 	POINTER_CHECK(entry);
106 	POINTER_CHECK(buffer);
107 	if (size == 0) {
108 		return PLDM_ERROR_INVALID_LENGTH;
109 	}
110 	size_t length =
111 		pldm_bios_table_string_entry_decode_string_length(entry);
112 	length = length < (size - 1) ? length : (size - 1);
113 	memcpy(buffer, entry->name, length);
114 	buffer[length] = 0;
115 	return PLDM_SUCCESS;
116 }
117 
118 static ssize_t string_table_entry_length(const void *table_entry)
119 {
120 	const struct pldm_bios_string_table_entry *entry = table_entry;
121 	size_t len = sizeof(*entry) - sizeof(entry->name) +
122 		     pldm_bios_table_string_entry_decode_string_length(entry);
123 	if (len > SSIZE_MAX) {
124 		return -1;
125 	}
126 	return (ssize_t)len;
127 }
128 
129 static int get_bios_attr_handle(uint16_t *val)
130 {
131 	static uint16_t handle = 0;
132 	assert(handle != UINT16_MAX);
133 	if (handle == UINT16_MAX) {
134 		return PLDM_ERROR_INVALID_DATA;
135 	}
136 
137 	*val = handle++;
138 	return PLDM_SUCCESS;
139 }
140 
141 static int attr_table_entry_encode_header(void *entry, size_t length,
142 					  uint8_t attr_type,
143 					  uint16_t string_handle)
144 {
145 	struct pldm_bios_attr_table_entry *attr_entry = entry;
146 
147 	assert(sizeof(*attr_entry) <= length);
148 	if (sizeof(*attr_entry) > length) {
149 		return PLDM_ERROR_INVALID_LENGTH;
150 	}
151 
152 	uint16_t handle;
153 	int rc = get_bios_attr_handle(&handle);
154 	if (rc != PLDM_SUCCESS) {
155 		return rc;
156 	}
157 
158 	attr_entry->attr_handle = htole16(handle);
159 	attr_entry->attr_type = attr_type;
160 	attr_entry->string_handle = htole16(string_handle);
161 
162 	return PLDM_SUCCESS;
163 }
164 
165 LIBPLDM_ABI_STABLE
166 uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
167 	const struct pldm_bios_attr_table_entry *entry)
168 {
169 	return le16toh(entry->attr_handle);
170 }
171 
172 LIBPLDM_ABI_STABLE
173 uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
174 	const struct pldm_bios_attr_table_entry *entry)
175 {
176 	return entry->attr_type;
177 }
178 
179 LIBPLDM_ABI_STABLE
180 uint16_t pldm_bios_table_attr_entry_decode_string_handle(
181 	const struct pldm_bios_attr_table_entry *entry)
182 {
183 	return le16toh(entry->string_handle);
184 }
185 
186 LIBPLDM_ABI_STABLE
187 size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
188 						     uint8_t def_num)
189 {
190 	return sizeof(struct pldm_bios_attr_table_entry) -
191 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
192 	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
193 	       def_num;
194 }
195 
196 LIBPLDM_ABI_STABLE
197 int pldm_bios_table_attr_entry_enum_encode_check(
198 	void *entry, size_t entry_length,
199 	const struct pldm_bios_table_attr_entry_enum_info *info)
200 {
201 	POINTER_CHECK(entry);
202 	POINTER_CHECK(info);
203 	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
204 		info->pv_num, info->def_num);
205 	BUFFER_SIZE_EXPECT(entry_length, length);
206 	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
207 					      PLDM_BIOS_ENUMERATION;
208 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
209 						info->name_handle);
210 	if (rc != PLDM_SUCCESS) {
211 		return rc;
212 	}
213 	struct pldm_bios_attr_table_entry *attr_entry = entry;
214 	attr_entry->metadata[0] = info->pv_num;
215 	uint16_t *pv_hdls =
216 		(uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
217 	size_t i;
218 	for (i = 0; i < info->pv_num; i++) {
219 		pv_hdls[i] = htole16(info->pv_handle[i]);
220 	}
221 	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
222 		info->def_num;
223 	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
224 		       info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
225 	       info->def_index, info->def_num);
226 	return PLDM_SUCCESS;
227 }
228 
229 #define ATTR_TYPE_EXPECT(type, expected)                                       \
230 	do {                                                                   \
231 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
232 			return PLDM_ERROR_INVALID_DATA;                        \
233 	} while (0)
234 
235 LIBPLDM_ABI_STABLE
236 int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
237 	const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
238 {
239 	POINTER_CHECK(entry);
240 	POINTER_CHECK(pv_num);
241 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
242 	*pv_num = entry->metadata[0];
243 	return PLDM_SUCCESS;
244 }
245 
246 static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
247 	const struct pldm_bios_attr_table_entry *entry)
248 {
249 	uint8_t pv_num = entry->metadata[0];
250 	return entry->metadata[sizeof(uint8_t) /* pv_num */ +
251 			       sizeof(uint16_t) * pv_num];
252 }
253 
254 LIBPLDM_ABI_STABLE
255 int pldm_bios_table_attr_entry_enum_decode_def_num_check(
256 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
257 {
258 	POINTER_CHECK(entry);
259 	POINTER_CHECK(def_num);
260 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
261 	*def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
262 	return PLDM_SUCCESS;
263 }
264 
265 LIBPLDM_ABI_STABLE
266 int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
267 	const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
268 	uint8_t pv_num)
269 {
270 	POINTER_CHECK(entry);
271 	POINTER_CHECK(pv_hdls);
272 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
273 	uint8_t num = entry->metadata[0];
274 	num = num < pv_num ? num : pv_num;
275 	size_t i;
276 	for (i = 0; i < num; i++) {
277 		uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
278 					     i * sizeof(uint16_t));
279 		pv_hdls[i] = le16toh(*hdl);
280 	}
281 	return PLDM_SUCCESS;
282 }
283 
284 LIBPLDM_ABI_STABLE
285 uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
286 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
287 	uint8_t def_num)
288 {
289 	uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
290 	num = num < def_num ? num : def_num;
291 	uint8_t pv_num = entry->metadata[0];
292 	const uint8_t *p = entry->metadata +
293 			   sizeof(uint8_t) /* number of possible values*/
294 			   + pv_num * sizeof(uint16_t) /* possible values */
295 			   + sizeof(uint8_t); /* number of default values */
296 	memcpy(def_indices, p, num);
297 	return num;
298 }
299 
300 /** @brief Get length of an enum attribute entry
301  */
302 static ssize_t attr_table_entry_length_enum(const void *arg)
303 {
304 	const struct pldm_bios_attr_table_entry *entry = arg;
305 	uint8_t pv_num = entry->metadata[0];
306 	uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
307 	size_t len =
308 		pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
309 	if (len > SSIZE_MAX) {
310 		return -1;
311 	}
312 	return (ssize_t)len;
313 }
314 
315 struct attr_table_string_entry_fields {
316 	uint8_t string_type;
317 	uint16_t min_length;
318 	uint16_t max_length;
319 	uint16_t def_length;
320 	uint8_t def_string[1];
321 } __attribute__((packed));
322 
323 LIBPLDM_ABI_STABLE
324 size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
325 {
326 	return sizeof(struct pldm_bios_attr_table_entry) -
327 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
328 	       sizeof(struct attr_table_string_entry_fields) -
329 	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
330 	       def_str_len;
331 }
332 
333 #define PLDM_STRING_TYPE_MAX	5
334 #define PLDM_STRING_TYPE_VENDOR 0xff
335 
336 LIBPLDM_ABI_STABLE
337 int pldm_bios_table_attr_entry_string_info_check(
338 	const struct pldm_bios_table_attr_entry_string_info *info,
339 	const char **errmsg)
340 {
341 	if (info->min_length > info->max_length) {
342 		set_errmsg(errmsg, "MinimumStingLength should not be greater "
343 				   "than MaximumStringLength");
344 		return PLDM_ERROR_INVALID_DATA;
345 	}
346 	if (info->min_length == info->max_length &&
347 	    info->def_length != info->min_length) {
348 		set_errmsg(errmsg, "Wrong DefaultStringLength");
349 		return PLDM_ERROR_INVALID_DATA;
350 	}
351 	if (info->def_length > info->max_length ||
352 	    info->def_length < info->min_length) {
353 		set_errmsg(errmsg, "Wrong DefaultStringLength");
354 		return PLDM_ERROR_INVALID_DATA;
355 	}
356 	if (info->string_type > PLDM_STRING_TYPE_MAX &&
357 	    info->string_type != PLDM_STRING_TYPE_VENDOR) {
358 		set_errmsg(errmsg, "Wrong StringType");
359 		return PLDM_ERROR_INVALID_DATA;
360 	}
361 	if (info->def_string && info->def_length != strlen(info->def_string)) {
362 		set_errmsg(errmsg, "Length of DefaultString should be equal to "
363 				   "DefaultStringLength");
364 		return PLDM_ERROR_INVALID_DATA;
365 	}
366 
367 	return PLDM_SUCCESS;
368 }
369 
370 LIBPLDM_ABI_STABLE
371 int pldm_bios_table_attr_entry_string_encode_check(
372 	void *entry, size_t entry_length,
373 	const struct pldm_bios_table_attr_entry_string_info *info)
374 {
375 	POINTER_CHECK(entry);
376 	POINTER_CHECK(info);
377 	size_t length = pldm_bios_table_attr_entry_string_encode_length(
378 		info->def_length);
379 	BUFFER_SIZE_EXPECT(entry_length, length);
380 	if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
381 	    PLDM_SUCCESS) {
382 		return PLDM_ERROR_INVALID_DATA;
383 	}
384 	uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
385 					      PLDM_BIOS_STRING;
386 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
387 						info->name_handle);
388 	if (rc != PLDM_SUCCESS) {
389 		return rc;
390 	}
391 	struct pldm_bios_attr_table_entry *attr_entry = entry;
392 	struct attr_table_string_entry_fields *attr_fields =
393 		(struct attr_table_string_entry_fields *)attr_entry->metadata;
394 	attr_fields->string_type = info->string_type;
395 	attr_fields->min_length = htole16(info->min_length);
396 	attr_fields->max_length = htole16(info->max_length);
397 	attr_fields->def_length = htole16(info->def_length);
398 	if (info->def_length != 0 && info->def_string != NULL) {
399 		memcpy(attr_fields->def_string, info->def_string,
400 		       info->def_length);
401 	}
402 	return PLDM_SUCCESS;
403 }
404 
405 static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
406 	const struct pldm_bios_attr_table_entry *entry)
407 {
408 	struct attr_table_string_entry_fields *fields =
409 		(struct attr_table_string_entry_fields *)entry->metadata;
410 	return le16toh(fields->def_length);
411 }
412 
413 LIBPLDM_ABI_STABLE
414 int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
415 	const struct pldm_bios_attr_table_entry *entry,
416 	uint16_t *def_string_length)
417 {
418 	POINTER_CHECK(entry);
419 	POINTER_CHECK(def_string_length);
420 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
421 	*def_string_length =
422 		pldm_bios_table_attr_entry_string_decode_def_string_length(
423 			entry);
424 	return PLDM_SUCCESS;
425 }
426 
427 LIBPLDM_ABI_STABLE
428 uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
429 	const struct pldm_bios_attr_table_entry *entry)
430 {
431 	struct attr_table_string_entry_fields *fields =
432 		(struct attr_table_string_entry_fields *)entry->metadata;
433 	return fields->string_type;
434 }
435 
436 LIBPLDM_ABI_STABLE
437 uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
438 	const struct pldm_bios_attr_table_entry *entry)
439 {
440 	struct attr_table_string_entry_fields *fields =
441 		(struct attr_table_string_entry_fields *)entry->metadata;
442 	return le16toh(fields->max_length);
443 }
444 
445 LIBPLDM_ABI_STABLE
446 uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
447 	const struct pldm_bios_attr_table_entry *entry)
448 {
449 	struct attr_table_string_entry_fields *fields =
450 		(struct attr_table_string_entry_fields *)entry->metadata;
451 	return le16toh(fields->min_length);
452 }
453 
454 LIBPLDM_ABI_STABLE
455 uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
456 	const struct pldm_bios_attr_table_entry *entry, char *buffer,
457 	size_t size)
458 {
459 	uint16_t length =
460 		pldm_bios_table_attr_entry_string_decode_def_string_length(
461 			entry);
462 	length = length < (size - 1) ? length : (size - 1);
463 	struct attr_table_string_entry_fields *fields =
464 		(struct attr_table_string_entry_fields *)entry->metadata;
465 	memcpy(buffer, fields->def_string, length);
466 	buffer[length] = 0;
467 	return length;
468 }
469 
470 /** @brief Get length of a string attribute entry
471  */
472 static ssize_t attr_table_entry_length_string(const void *entry)
473 {
474 	uint16_t def_str_len =
475 		pldm_bios_table_attr_entry_string_decode_def_string_length(
476 			entry);
477 	size_t len =
478 		pldm_bios_table_attr_entry_string_encode_length(def_str_len);
479 	if (len > SSIZE_MAX) {
480 		return -1;
481 	}
482 	return (ssize_t)len;
483 }
484 
485 struct attr_table_integer_entry_fields {
486 	uint64_t lower_bound;
487 	uint64_t upper_bound;
488 	uint32_t scalar_increment;
489 	uint64_t default_value;
490 } __attribute__((packed));
491 
492 LIBPLDM_ABI_STABLE
493 size_t pldm_bios_table_attr_entry_integer_encode_length(void)
494 {
495 	return sizeof(struct pldm_bios_attr_table_entry) - 1 +
496 	       sizeof(struct attr_table_integer_entry_fields);
497 }
498 
499 LIBPLDM_ABI_STABLE
500 int pldm_bios_table_attr_entry_integer_info_check(
501 	const struct pldm_bios_table_attr_entry_integer_info *info,
502 	const char **errmsg)
503 {
504 	if (info->lower_bound == info->upper_bound) {
505 		if (info->default_value != info->lower_bound) {
506 			set_errmsg(errmsg, "Wrong DefaultValue");
507 			return PLDM_ERROR_INVALID_DATA;
508 		}
509 		if (info->scalar_increment != 0) {
510 			set_errmsg(errmsg, "Wrong ScalarIncrement");
511 			return PLDM_ERROR_INVALID_DATA;
512 		}
513 		return PLDM_SUCCESS;
514 	}
515 	if (info->lower_bound > info->upper_bound) {
516 		set_errmsg(errmsg,
517 			   "LowerBound should not be greater than UpperBound");
518 		return PLDM_ERROR_INVALID_DATA;
519 	}
520 	if (info->default_value > info->upper_bound ||
521 	    info->default_value < info->lower_bound) {
522 		set_errmsg(errmsg, "Wrong DefaultValue");
523 		return PLDM_ERROR_INVALID_DATA;
524 	}
525 	if (info->scalar_increment == 0) {
526 		set_errmsg(errmsg, "ScalarIncrement should not be zero when "
527 				   "lower_bound != upper_bound");
528 		return PLDM_ERROR_INVALID_DATA;
529 	}
530 	if ((info->default_value - info->lower_bound) %
531 		    info->scalar_increment !=
532 	    0) {
533 		set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
534 		return PLDM_ERROR_INVALID_DATA;
535 	}
536 	return PLDM_SUCCESS;
537 }
538 
539 LIBPLDM_ABI_STABLE
540 int pldm_bios_table_attr_entry_integer_encode_check(
541 	void *entry, size_t entry_length,
542 	const struct pldm_bios_table_attr_entry_integer_info *info)
543 {
544 	POINTER_CHECK(entry);
545 	POINTER_CHECK(info);
546 	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
547 	BUFFER_SIZE_EXPECT(entry_length, length);
548 	if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
549 	    PLDM_SUCCESS) {
550 		return PLDM_ERROR_INVALID_DATA;
551 	}
552 	uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
553 					      PLDM_BIOS_INTEGER;
554 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
555 						info->name_handle);
556 	if (rc != PLDM_SUCCESS) {
557 		return rc;
558 	}
559 	struct pldm_bios_attr_table_entry *attr_entry = entry;
560 	struct attr_table_integer_entry_fields *attr_fields =
561 		(struct attr_table_integer_entry_fields *)attr_entry->metadata;
562 	attr_fields->lower_bound = htole64(info->lower_bound);
563 	attr_fields->upper_bound = htole64(info->upper_bound);
564 	attr_fields->scalar_increment = htole32(info->scalar_increment);
565 	attr_fields->default_value = htole64(info->default_value);
566 	return PLDM_SUCCESS;
567 }
568 
569 LIBPLDM_ABI_STABLE
570 void pldm_bios_table_attr_entry_integer_decode(
571 	const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
572 	uint64_t *upper, uint32_t *scalar, uint64_t *def)
573 {
574 	struct attr_table_integer_entry_fields *fields =
575 		(struct attr_table_integer_entry_fields *)entry->metadata;
576 	*lower = le64toh(fields->lower_bound);
577 	*upper = le64toh(fields->upper_bound);
578 	*scalar = le32toh(fields->scalar_increment);
579 	*def = le64toh(fields->default_value);
580 }
581 
582 static ssize_t attr_table_entry_length_integer(const void *entry)
583 {
584 	(void)entry;
585 	size_t len = pldm_bios_table_attr_entry_integer_encode_length();
586 	if (len > SSIZE_MAX) {
587 		return -1;
588 	}
589 	return (ssize_t)len;
590 }
591 
592 struct table_entry_length {
593 	uint8_t attr_type;
594 	ssize_t (*entry_length_handler)(const void *);
595 };
596 
597 static const struct table_entry_length *
598 find_table_entry_length_by_type(uint8_t attr_type,
599 				const struct table_entry_length *handlers,
600 				size_t count)
601 {
602 	size_t i;
603 	for (i = 0; i < count; i++) {
604 		if (attr_type == handlers[i].attr_type) {
605 			return &handlers[i];
606 		}
607 	}
608 	return NULL;
609 }
610 
611 static const struct table_entry_length attr_table_entries[] = {
612 	{ .attr_type = PLDM_BIOS_ENUMERATION,
613 	  .entry_length_handler = attr_table_entry_length_enum },
614 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
615 	  .entry_length_handler = attr_table_entry_length_enum },
616 	{ .attr_type = PLDM_BIOS_STRING,
617 	  .entry_length_handler = attr_table_entry_length_string },
618 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
619 	  .entry_length_handler = attr_table_entry_length_string },
620 	{ .attr_type = PLDM_BIOS_INTEGER,
621 	  .entry_length_handler = attr_table_entry_length_integer },
622 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
623 	  .entry_length_handler = attr_table_entry_length_integer },
624 };
625 
626 static ssize_t attr_table_entry_length(const void *table_entry)
627 {
628 	const struct pldm_bios_attr_table_entry *entry = table_entry;
629 	const struct table_entry_length *attr_table_entry =
630 		find_table_entry_length_by_type(entry->attr_type,
631 						attr_table_entries,
632 						ARRAY_SIZE(attr_table_entries));
633 	assert(attr_table_entry != NULL);
634 	if (!attr_table_entry) {
635 		return -1;
636 	}
637 	assert(attr_table_entry->entry_length_handler != NULL);
638 	if (!attr_table_entry->entry_length_handler) {
639 		return -1;
640 	}
641 
642 	return attr_table_entry->entry_length_handler(entry);
643 }
644 
645 LIBPLDM_ABI_STABLE
646 uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
647 	const struct pldm_bios_attr_val_table_entry *entry)
648 {
649 	return le16toh(entry->attr_handle);
650 }
651 
652 LIBPLDM_ABI_STABLE
653 uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
654 	const struct pldm_bios_attr_val_table_entry *entry)
655 {
656 	return entry->attr_type;
657 }
658 
659 LIBPLDM_ABI_STABLE
660 size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
661 {
662 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
663 	       sizeof(count) + count;
664 }
665 
666 LIBPLDM_ABI_STABLE
667 uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
668 	const struct pldm_bios_attr_val_table_entry *entry)
669 {
670 	return entry->value[0];
671 }
672 
673 LIBPLDM_ABI_STABLE
674 uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
675 	const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
676 	uint8_t number)
677 {
678 	uint8_t curr_num =
679 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
680 	curr_num = number < curr_num ? number : curr_num;
681 	memcpy(handles, &entry->value[1], curr_num);
682 
683 	return curr_num;
684 }
685 
686 LIBPLDM_ABI_STABLE
687 int pldm_bios_table_attr_value_entry_encode_enum_check(
688 	void *entry, size_t entry_length, uint16_t attr_handle,
689 	uint8_t attr_type, uint8_t count, const uint8_t *handles)
690 {
691 	POINTER_CHECK(entry);
692 	POINTER_CHECK(handles);
693 	if (count != 0 && handles == NULL) {
694 		return PLDM_ERROR_INVALID_DATA;
695 	}
696 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
697 	size_t length =
698 		pldm_bios_table_attr_value_entry_encode_enum_length(count);
699 	BUFFER_SIZE_EXPECT(entry_length, length);
700 	struct pldm_bios_attr_val_table_entry *table_entry = entry;
701 	table_entry->attr_handle = htole16(attr_handle);
702 	table_entry->attr_type = attr_type;
703 	table_entry->value[0] = count;
704 	if (count != 0) {
705 		memcpy(&table_entry->value[1], handles, count);
706 	}
707 	return PLDM_SUCCESS;
708 }
709 
710 static ssize_t attr_value_table_entry_length_enum(const void *entry)
711 {
712 	uint8_t number =
713 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
714 	size_t len =
715 		pldm_bios_table_attr_value_entry_encode_enum_length(number);
716 	if (len > SSIZE_MAX) {
717 		return -1;
718 	}
719 	return (ssize_t)len;
720 }
721 
722 LIBPLDM_ABI_STABLE
723 size_t
724 pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
725 {
726 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
727 	       sizeof(string_length) + string_length;
728 }
729 
730 LIBPLDM_ABI_STABLE
731 uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
732 	const struct pldm_bios_attr_val_table_entry *entry)
733 {
734 	uint16_t str_length = 0;
735 	memcpy(&str_length, entry->value, sizeof(str_length));
736 	return le16toh(str_length);
737 }
738 
739 LIBPLDM_ABI_STABLE
740 void pldm_bios_table_attr_value_entry_string_decode_string(
741 	const struct pldm_bios_attr_val_table_entry *entry,
742 	struct variable_field *current_string)
743 {
744 	current_string->length =
745 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
746 	current_string->ptr =
747 		entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
748 }
749 
750 LIBPLDM_ABI_STABLE
751 int pldm_bios_table_attr_value_entry_encode_string_check(
752 	void *entry, size_t entry_length, uint16_t attr_handle,
753 	uint8_t attr_type, uint16_t str_length, const char *str)
754 {
755 	POINTER_CHECK(entry);
756 	if (str_length != 0 && str == NULL) {
757 		return PLDM_ERROR_INVALID_DATA;
758 	}
759 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
760 	size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
761 		str_length);
762 	BUFFER_SIZE_EXPECT(entry_length, length);
763 	struct pldm_bios_attr_val_table_entry *table_entry = entry;
764 	table_entry->attr_handle = htole16(attr_handle);
765 	table_entry->attr_type = attr_type;
766 	if (str_length != 0) {
767 		memcpy(table_entry->value + sizeof(str_length), str,
768 		       str_length);
769 	}
770 	str_length = htole16(str_length);
771 	memcpy(table_entry->value, &str_length, sizeof(str_length));
772 	return PLDM_SUCCESS;
773 }
774 
775 static ssize_t attr_value_table_entry_length_string(const void *entry)
776 {
777 	uint16_t str_length =
778 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
779 	size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
780 		str_length);
781 	if (len > SSIZE_MAX) {
782 		return -1;
783 	}
784 	return (ssize_t)len;
785 }
786 
787 LIBPLDM_ABI_STABLE
788 size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
789 {
790 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
791 	       sizeof(uint64_t);
792 }
793 
794 LIBPLDM_ABI_STABLE
795 int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
796 							  size_t entry_length,
797 							  uint16_t attr_handle,
798 							  uint8_t attr_type,
799 							  uint64_t cv)
800 {
801 	POINTER_CHECK(entry);
802 	size_t length =
803 		pldm_bios_table_attr_value_entry_encode_integer_length();
804 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
805 	BUFFER_SIZE_EXPECT(entry_length, length);
806 	struct pldm_bios_attr_val_table_entry *table_entry = entry;
807 	table_entry->attr_handle = htole16(attr_handle);
808 	table_entry->attr_type = attr_type;
809 	cv = htole64(cv);
810 	memcpy(table_entry->value, &cv, sizeof(uint64_t));
811 	return PLDM_SUCCESS;
812 }
813 
814 LIBPLDM_ABI_STABLE
815 uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
816 	const struct pldm_bios_attr_val_table_entry *entry)
817 {
818 	uint64_t cv = 0;
819 	memcpy(&cv, entry->value, sizeof(cv));
820 	cv = le64toh(cv);
821 	return cv;
822 }
823 
824 static ssize_t attr_value_table_entry_length_integer(const void *entry)
825 {
826 	(void)entry;
827 	size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
828 	if (len > SSIZE_MAX) {
829 		return -1;
830 	}
831 	return (ssize_t)len;
832 }
833 
834 static const struct table_entry_length attr_value_table_entries[] = {
835 	{ .attr_type = PLDM_BIOS_ENUMERATION,
836 	  .entry_length_handler = attr_value_table_entry_length_enum },
837 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
838 	  .entry_length_handler = attr_value_table_entry_length_enum },
839 	{ .attr_type = PLDM_BIOS_STRING,
840 	  .entry_length_handler = attr_value_table_entry_length_string },
841 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
842 	  .entry_length_handler = attr_value_table_entry_length_string },
843 	{ .attr_type = PLDM_BIOS_INTEGER,
844 	  .entry_length_handler = attr_value_table_entry_length_integer },
845 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
846 	  .entry_length_handler = attr_value_table_entry_length_integer },
847 };
848 
849 static ssize_t attr_value_table_entry_length(const void *table_entry)
850 {
851 	const struct pldm_bios_attr_val_table_entry *entry = table_entry;
852 	const struct table_entry_length *entry_length =
853 		find_table_entry_length_by_type(
854 			entry->attr_type, attr_value_table_entries,
855 			ARRAY_SIZE(attr_value_table_entries));
856 	assert(entry_length != NULL);
857 	if (!entry_length) {
858 		return -1;
859 	}
860 	assert(entry_length->entry_length_handler != NULL);
861 	if (!entry_length->entry_length_handler) {
862 		return -1;
863 	}
864 
865 	return entry_length->entry_length_handler(entry);
866 }
867 
868 LIBPLDM_ABI_STABLE
869 size_t pldm_bios_table_attr_value_entry_length(
870 	const struct pldm_bios_attr_val_table_entry *entry)
871 {
872 	return attr_value_table_entry_length(entry);
873 }
874 
875 LIBPLDM_ABI_STABLE
876 uint16_t pldm_bios_table_attr_value_entry_decode_handle(
877 	const struct pldm_bios_attr_val_table_entry *entry)
878 {
879 	return le16toh(entry->attr_handle);
880 }
881 
882 static size_t pad_size_get(size_t size_without_pad)
883 {
884 	return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
885 }
886 
887 static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
888 {
889 	while (pad_size--) {
890 		*table_end++ = 0;
891 	}
892 
893 	return table_end;
894 }
895 
896 static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
897 {
898 	checksum = htole32(checksum);
899 	memcpy(table_end, &checksum, sizeof(checksum));
900 
901 	return table_end + sizeof(checksum);
902 }
903 
904 LIBPLDM_ABI_STABLE
905 size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
906 {
907 	size_t size = pad_size_get(size_without_pad) +
908 		      sizeof(uint32_t) /*sizeof(checksum)*/;
909 	return size;
910 }
911 
912 LIBPLDM_ABI_STABLE
913 int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
914 					      size_t *size)
915 {
916 	if (!table || !size) {
917 		return PLDM_ERROR_INVALID_DATA;
918 	}
919 
920 	size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
921 	size_t total_length = *size + pad_checksum_size;
922 	if (capacity < total_length) {
923 		return PLDM_ERROR_INVALID_LENGTH;
924 	}
925 
926 	uint8_t *table_end = (uint8_t *)table + *size;
927 	size_t pad_size = pad_size_get(*size);
928 	table_end = pad_append(table_end, pad_size);
929 
930 	uint32_t checksum = crc32(table, *size + pad_size);
931 	checksum_append(table_end, checksum);
932 	*size = total_length;
933 
934 	return PLDM_SUCCESS;
935 }
936 
937 struct pldm_bios_table_iter {
938 	const uint8_t *table_data;
939 	size_t table_len;
940 	size_t current_pos;
941 	ssize_t (*entry_length_handler)(const void *table_entry);
942 };
943 
944 LIBPLDM_ABI_STABLE
945 struct pldm_bios_table_iter *
946 pldm_bios_table_iter_create(const void *table, size_t length,
947 			    enum pldm_bios_table_types type)
948 {
949 	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
950 	assert(iter != NULL);
951 	if (!iter) {
952 		return NULL;
953 	}
954 	iter->table_data = table;
955 	iter->table_len = length;
956 	iter->current_pos = 0;
957 	iter->entry_length_handler = NULL;
958 	switch (type) {
959 	case PLDM_BIOS_STRING_TABLE:
960 		iter->entry_length_handler = string_table_entry_length;
961 		break;
962 	case PLDM_BIOS_ATTR_TABLE:
963 		iter->entry_length_handler = attr_table_entry_length;
964 		break;
965 	case PLDM_BIOS_ATTR_VAL_TABLE:
966 		iter->entry_length_handler = attr_value_table_entry_length;
967 		break;
968 	}
969 
970 	return iter;
971 }
972 
973 LIBPLDM_ABI_STABLE
974 void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
975 {
976 	free(iter);
977 }
978 
979 #define pad_and_check_max 7
980 LIBPLDM_ABI_STABLE
981 bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
982 {
983 	ssize_t len;
984 
985 	if (iter->table_len - iter->current_pos <= pad_and_check_max) {
986 		return true;
987 	}
988 
989 	len = iter->entry_length_handler(iter->table_data + iter->current_pos);
990 
991 	return len < 0;
992 }
993 
994 LIBPLDM_ABI_STABLE
995 void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
996 {
997 	if (pldm_bios_table_iter_is_end(iter)) {
998 		return;
999 	}
1000 	const void *entry = iter->table_data + iter->current_pos;
1001 	ssize_t rc = iter->entry_length_handler(entry);
1002 	/* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1003 	if (rc < 0) {
1004 		return;
1005 	}
1006 	iter->current_pos += rc;
1007 }
1008 
1009 LIBPLDM_ABI_STABLE
1010 const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1011 {
1012 	return iter->table_data + iter->current_pos;
1013 }
1014 
1015 typedef bool (*equal_handler)(const void *entry, const void *key);
1016 
1017 static const void *
1018 pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1019 				   const void *key, equal_handler equal)
1020 {
1021 	const void *entry;
1022 	while (!pldm_bios_table_iter_is_end(iter)) {
1023 		entry = pldm_bios_table_iter_value(iter);
1024 		if (equal(entry, key)) {
1025 			return entry;
1026 		}
1027 		pldm_bios_table_iter_next(iter);
1028 	}
1029 	return NULL;
1030 }
1031 
1032 static const void *
1033 pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1034 				      enum pldm_bios_table_types type,
1035 				      equal_handler equal, const void *key)
1036 {
1037 	struct pldm_bios_table_iter *iter =
1038 		pldm_bios_table_iter_create(table, length, type);
1039 	const void *entry =
1040 		pldm_bios_table_entry_find_by_iter(iter, key, equal);
1041 	pldm_bios_table_iter_free(iter);
1042 	return entry;
1043 }
1044 
1045 static bool string_table_handle_equal(const void *entry, const void *key)
1046 {
1047 	const struct pldm_bios_string_table_entry *string_entry = entry;
1048 	uint16_t handle = *(uint16_t *)key;
1049 	if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1050 	    handle) {
1051 		return true;
1052 	}
1053 	return false;
1054 }
1055 
1056 LIBPLDM_ABI_STABLE
1057 const struct pldm_bios_string_table_entry *
1058 pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1059 				      uint16_t handle)
1060 {
1061 	return pldm_bios_table_entry_find_from_table(table, length,
1062 						     PLDM_BIOS_STRING_TABLE,
1063 						     string_table_handle_equal,
1064 						     &handle);
1065 }
1066 
1067 struct string_equal_arg {
1068 	uint16_t str_length;
1069 	const char *str;
1070 };
1071 
1072 static bool string_table_string_equal(const void *entry, const void *key)
1073 {
1074 	const struct pldm_bios_string_table_entry *string_entry = entry;
1075 	const struct string_equal_arg *arg = key;
1076 	if (arg->str_length !=
1077 	    pldm_bios_table_string_entry_decode_string_length(string_entry)) {
1078 		return false;
1079 	}
1080 	if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
1081 		return false;
1082 	}
1083 	return true;
1084 }
1085 
1086 LIBPLDM_ABI_STABLE
1087 const struct pldm_bios_string_table_entry *
1088 pldm_bios_table_string_find_by_string(const void *table, size_t length,
1089 				      const char *str)
1090 {
1091 	uint16_t str_length = strlen(str);
1092 	struct string_equal_arg arg = { str_length, str };
1093 	return pldm_bios_table_entry_find_from_table(table, length,
1094 						     PLDM_BIOS_STRING_TABLE,
1095 						     string_table_string_equal,
1096 						     &arg);
1097 }
1098 
1099 static bool attr_table_handle_equal(const void *entry, const void *key)
1100 {
1101 	uint16_t handle = *(uint16_t *)key;
1102 	return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1103 	       handle;
1104 }
1105 
1106 LIBPLDM_ABI_STABLE
1107 const struct pldm_bios_attr_table_entry *
1108 pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1109 				    uint16_t handle)
1110 {
1111 	return pldm_bios_table_entry_find_from_table(table, length,
1112 						     PLDM_BIOS_ATTR_TABLE,
1113 						     attr_table_handle_equal,
1114 						     &handle);
1115 }
1116 
1117 static bool attr_table_string_handle_equal(const void *entry, const void *key)
1118 {
1119 	uint16_t handle = *(uint16_t *)key;
1120 	return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1121 }
1122 
1123 LIBPLDM_ABI_STABLE
1124 const struct pldm_bios_attr_table_entry *
1125 pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1126 					   uint16_t handle)
1127 {
1128 	return pldm_bios_table_entry_find_from_table(
1129 		table, length, PLDM_BIOS_ATTR_TABLE,
1130 		attr_table_string_handle_equal, &handle);
1131 }
1132 
1133 static bool attr_value_table_handle_equal(const void *entry, const void *key)
1134 {
1135 	uint16_t handle = *(uint16_t *)key;
1136 	return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1137 }
1138 
1139 LIBPLDM_ABI_STABLE
1140 const struct pldm_bios_attr_val_table_entry *
1141 pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1142 					  uint16_t handle)
1143 {
1144 	return pldm_bios_table_entry_find_from_table(
1145 		table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1146 		attr_value_table_handle_equal, &handle);
1147 }
1148 
1149 LIBPLDM_ABI_STABLE
1150 int pldm_bios_table_attr_value_copy_and_update(
1151 	const void *src_table, size_t src_length, void *dest_table,
1152 	size_t *dest_length, const void *entry, size_t entry_length)
1153 {
1154 	struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
1155 		src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
1156 
1157 	int rc = PLDM_SUCCESS;
1158 	const struct pldm_bios_attr_val_table_entry *tmp;
1159 	const struct pldm_bios_attr_val_table_entry *to_update = entry;
1160 	size_t buffer_length = *dest_length;
1161 	size_t copied_length = 0;
1162 	size_t length = 0;
1163 	while (!pldm_bios_table_iter_is_end(iter)) {
1164 		tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1165 		length = attr_value_table_entry_length(tmp);
1166 
1167 		/* we need the tmp's entry_length here, iter_next will calculate
1168 		 * it too, use current_pos directly to avoid calculating it
1169 		 * twice */
1170 		iter->current_pos += length;
1171 		if (tmp->attr_handle == to_update->attr_handle) {
1172 			if (tmp->attr_type != to_update->attr_type) {
1173 				rc = PLDM_ERROR_INVALID_DATA;
1174 				goto out;
1175 			}
1176 			length = entry_length;
1177 			tmp = entry;
1178 		}
1179 		if (copied_length + length > buffer_length) {
1180 			rc = PLDM_ERROR_INVALID_LENGTH;
1181 			goto out;
1182 		}
1183 		memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1184 		copied_length += length;
1185 	}
1186 
1187 	size_t pad_checksum_size =
1188 		pldm_bios_table_pad_checksum_size(copied_length);
1189 	if ((pad_checksum_size + copied_length) > buffer_length) {
1190 		rc = PLDM_ERROR_INVALID_LENGTH;
1191 		goto out;
1192 	}
1193 
1194 	rc = pldm_bios_table_append_pad_checksum_check(
1195 		dest_table, buffer_length, &copied_length);
1196 	if (rc == PLDM_SUCCESS) {
1197 		*dest_length = copied_length;
1198 	}
1199 out:
1200 	pldm_bios_table_iter_free(iter);
1201 	return rc;
1202 }
1203 
1204 LIBPLDM_ABI_STABLE
1205 bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1206 {
1207 	if (table == NULL) {
1208 		return false;
1209 	}
1210 
1211 	// 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1212 	//     Variable(4) + checksum(uint32)
1213 	if (size < 12) {
1214 		return false;
1215 	}
1216 
1217 	uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1218 	uint32_t dst_crc = crc32(table, size - 4);
1219 
1220 	return src_crc == dst_crc;
1221 }
1222