1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  */
15 
16 /*
17  * Tests for SMBIOS Type 3 - SMB_TYPE_CHASSIS.
18  */
19 
20 #include "smbios_test.h"
21 
22 static const char *smbios_chassis_mfg = "Shrina";
23 static const char *smbios_chassis_vers = "7R";
24 static const char *smbios_chassis_serial = "What's my number?";
25 static const char *smbios_chassis_asset = "lost";
26 static const char *smbios_chassis_sku = "Proud";
27 static const uint32_t smbios_chassis_oem = 0x36105997;
28 static const uint8_t smbios_chassis_uheight = 7;
29 
30 boolean_t
smbios_test_chassis_mktable_invlen_base(smbios_test_table_t * table)31 smbios_test_chassis_mktable_invlen_base(smbios_test_table_t *table)
32 {
33 	smb_header_t hdr;
34 
35 	hdr.smbh_type = SMB_TYPE_CHASSIS;
36 	hdr.smbh_len = sizeof (hdr);
37 
38 	(void) smbios_test_table_append(table, &hdr, sizeof (hdr));
39 	smbios_test_table_append_eot(table);
40 
41 	return (B_TRUE);
42 }
43 
44 static void
smbios_test_chassis_mktable_fill_chassis(smb_chassis_t * ch)45 smbios_test_chassis_mktable_fill_chassis(smb_chassis_t *ch)
46 {
47 	ch->smbch_hdr.smbh_type = SMB_TYPE_CHASSIS;
48 	ch->smbch_hdr.smbh_len = sizeof (*ch);
49 	ch->smbch_manufacturer = 1;
50 	ch->smbch_type = SMB_CHT_LUNCHBOX;
51 	ch->smbch_version = 2;
52 	ch->smbch_serial = 3;
53 	ch->smbch_asset = 4;
54 	ch->smbch_bustate = SMB_CHST_SAFE;
55 	ch->smbch_psstate = SMB_CHST_NONREC;
56 	ch->smbch_thstate = SMB_CHST_WARNING;
57 	ch->smbch_security = SMB_CHSC_NONE;
58 	ch->smbch_oemdata = htole32(smbios_chassis_oem);
59 	ch->smbch_uheight = smbios_chassis_uheight;
60 	ch->smbch_cords = smbios_chassis_uheight - 1;
61 	ch->smbch_cn = 0;
62 	ch->smbch_cm = sizeof (smb_chassis_entry_t);
63 }
64 
65 static void
smbios_test_chassis_mktable_fill_entries(smb_chassis_entry_t * ents)66 smbios_test_chassis_mktable_fill_entries(smb_chassis_entry_t *ents)
67 {
68 	ents[0].smbce_type = SMB_TYPE_COOLDEV | (1 << 7);
69 	ents[0].smbce_min = 1;
70 	ents[0].smbce_max = 42;
71 	ents[1].smbce_type = SMB_BBT_IO;
72 	ents[1].smbce_min = 5;
73 	ents[1].smbce_max = 123;
74 }
75 
76 static void
smbios_test_chassis_mktable_append_strings(smbios_test_table_t * table)77 smbios_test_chassis_mktable_append_strings(smbios_test_table_t *table)
78 {
79 	smbios_test_table_append_string(table, smbios_chassis_mfg);
80 	smbios_test_table_append_string(table, smbios_chassis_vers);
81 	smbios_test_table_append_string(table, smbios_chassis_serial);
82 	smbios_test_table_append_string(table, smbios_chassis_asset);
83 }
84 
85 /*
86  * This is an SMBIOS 2.4-esque table.
87  */
88 boolean_t
smbios_test_chassis_mktable_base(smbios_test_table_t * table)89 smbios_test_chassis_mktable_base(smbios_test_table_t *table)
90 {
91 	smb_chassis_t ch;
92 
93 	smbios_test_chassis_mktable_fill_chassis(&ch);
94 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
95 	smbios_test_chassis_mktable_append_strings(table);
96 	smbios_test_table_str_fini(table);
97 	smbios_test_table_append_eot(table);
98 
99 	return (B_TRUE);
100 }
101 
102 /*
103  * A variant of the base that doesn't include the element length becaue there
104  * are no elements.
105  */
106 boolean_t
smbios_test_chassis_mktable_part(smbios_test_table_t * table)107 smbios_test_chassis_mktable_part(smbios_test_table_t *table)
108 {
109 	smb_chassis_t ch;
110 	size_t len = offsetof(smb_chassis_t, smbch_cn);
111 
112 	smbios_test_chassis_mktable_fill_chassis(&ch);
113 	ch.smbch_hdr.smbh_len = len;
114 	(void) smbios_test_table_append(table, &ch, len);
115 	smbios_test_chassis_mktable_append_strings(table);
116 	smbios_test_table_str_fini(table);
117 	smbios_test_table_append_eot(table);
118 
119 	return (B_TRUE);
120 }
121 
122 boolean_t
smbios_test_chassis_mktable_comps(smbios_test_table_t * table)123 smbios_test_chassis_mktable_comps(smbios_test_table_t *table)
124 {
125 	smb_chassis_t ch;
126 	smb_chassis_entry_t ents[2];
127 
128 	smbios_test_chassis_mktable_fill_chassis(&ch);
129 	smbios_test_chassis_mktable_fill_entries(ents);
130 	ch.smbch_hdr.smbh_len += sizeof (ents);
131 	ch.smbch_cn = 2;
132 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
133 	smbios_test_table_append_raw(table, ents, sizeof (ents));
134 	smbios_test_chassis_mktable_append_strings(table);
135 	smbios_test_table_str_fini(table);
136 	smbios_test_table_append_eot(table);
137 
138 	return (B_TRUE);
139 }
140 
141 boolean_t
smbios_test_chassis_mktable_sku_nocomps(smbios_test_table_t * table)142 smbios_test_chassis_mktable_sku_nocomps(smbios_test_table_t *table)
143 {
144 	smb_chassis_t ch;
145 	const uint8_t sku_str = 5;
146 
147 	smbios_test_chassis_mktable_fill_chassis(&ch);
148 	ch.smbch_hdr.smbh_len++;
149 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
150 	smbios_test_table_append_raw(table, &sku_str, sizeof (sku_str));
151 	smbios_test_chassis_mktable_append_strings(table);
152 	smbios_test_table_append_string(table, smbios_chassis_sku);
153 	smbios_test_table_str_fini(table);
154 	smbios_test_table_append_eot(table);
155 
156 	return (B_TRUE);
157 }
158 
159 boolean_t
smbios_test_chassis_mktable_sku(smbios_test_table_t * table)160 smbios_test_chassis_mktable_sku(smbios_test_table_t *table)
161 {
162 	smb_chassis_t ch;
163 	const uint8_t sku_str = 5;
164 	smb_chassis_entry_t ents[2];
165 
166 	ch.smbch_cn = 2;
167 
168 	smbios_test_chassis_mktable_fill_chassis(&ch);
169 	smbios_test_chassis_mktable_fill_entries(ents);
170 	ch.smbch_hdr.smbh_len += sizeof (ents) + 1;
171 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
172 	smbios_test_table_append_raw(table, &sku_str, sizeof (sku_str));
173 	smbios_test_chassis_mktable_append_strings(table);
174 	smbios_test_table_append_string(table, smbios_chassis_sku);
175 	smbios_test_table_str_fini(table);
176 	smbios_test_table_append_eot(table);
177 
178 	return (B_TRUE);
179 }
180 
181 boolean_t
smbios_test_chassis_verify_invlen(smbios_hdl_t * hdl)182 smbios_test_chassis_verify_invlen(smbios_hdl_t *hdl)
183 {
184 	smbios_struct_t sp;
185 	smbios_chassis_t ch;
186 
187 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
188 		warnx("failed to lookup SMBIOS chassis: %s",
189 		    smbios_errmsg(smbios_errno(hdl)));
190 		return (B_FALSE);
191 	}
192 
193 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) != -1) {
194 		warnx("accidentally parsed invalid chassis as valid");
195 		return (B_FALSE);
196 	}
197 
198 	if (smbios_errno(hdl) != ESMB_SHORT) {
199 		warnx("encountered wrong error for chassis, expected: "
200 		    "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl));
201 		return (B_FALSE);
202 	}
203 
204 	return (B_TRUE);
205 }
206 
207 static boolean_t
smbios_test_chassis_verify_common(smbios_hdl_t * hdl,smbios_struct_t * sp,smbios_chassis_t * ch)208 smbios_test_chassis_verify_common(smbios_hdl_t *hdl, smbios_struct_t *sp,
209     smbios_chassis_t *ch)
210 {
211 	boolean_t ret = B_TRUE;
212 	smbios_info_t info;
213 
214 	if (ch->smbc_oemdata != smbios_chassis_oem) {
215 		warnx("chassis state mismatch, found unexpected oem data: 0x%x",
216 		    ch->smbc_oemdata);
217 		ret = B_FALSE;
218 	}
219 
220 	if (ch->smbc_lock != 0) {
221 		warnx("chassis state mismatch, found unexpected lock: 0x%x",
222 		    ch->smbc_lock);
223 		ret = B_FALSE;
224 	}
225 
226 	if (ch->smbc_type != SMB_CHT_LUNCHBOX) {
227 		warnx("chassis state mismatch, found unexpected type: 0x%x",
228 		    ch->smbc_type);
229 		ret = B_FALSE;
230 	}
231 
232 	if (ch->smbc_bustate != SMB_CHST_SAFE) {
233 		warnx("chassis state mismatch, found unexpected boot state: "
234 		    "0x%x", ch->smbc_bustate);
235 		ret = B_FALSE;
236 	}
237 
238 	if (ch->smbc_psstate != SMB_CHST_NONREC) {
239 		warnx("chassis state mismatch, found unexpected power state: "
240 		    "0x%x", ch->smbc_psstate);
241 		ret = B_FALSE;
242 	}
243 
244 	if (ch->smbc_thstate != SMB_CHST_WARNING) {
245 		warnx("chassis state mismatch, found unexpected thermal state: "
246 		    "0x%x", ch->smbc_thstate);
247 		ret = B_FALSE;
248 	}
249 
250 	if (ch->smbc_security != SMB_CHSC_NONE) {
251 		warnx("chassis state mismatch, found unexpected security "
252 		    "value: 0x%x", ch->smbc_security);
253 		ret = B_FALSE;
254 	}
255 
256 	if (ch->smbc_uheight != smbios_chassis_uheight) {
257 		warnx("chassis state mismatch, found unexpected uheight value: "
258 		    "0x%x", ch->smbc_uheight);
259 		ret = B_FALSE;
260 	}
261 
262 	if (ch->smbc_cords != smbios_chassis_uheight - 1) {
263 		warnx("chassis state mismatch, found unexpected cords value: "
264 		    "0x%x", ch->smbc_cords);
265 		ret = B_FALSE;
266 	}
267 
268 	if (smbios_info_common(hdl, sp->smbstr_id, &info) != 0) {
269 		warnx("failed to get common chassis info: %s",
270 		    smbios_errmsg(smbios_errno(hdl)));
271 		return (B_FALSE);
272 	}
273 
274 	if (strcmp(info.smbi_manufacturer, smbios_chassis_mfg) != 0) {
275 		warnx("chassis state mismatch, found unexpected mfg: "
276 		    "%s", info.smbi_manufacturer);
277 		ret = B_FALSE;
278 	}
279 
280 	if (strcmp(info.smbi_version, smbios_chassis_vers) != 0) {
281 		warnx("chassis state mismatch, found unexpected version: %s",
282 		    info.smbi_version);
283 		ret = B_FALSE;
284 	}
285 
286 	if (strcmp(info.smbi_serial, smbios_chassis_serial) != 0) {
287 		warnx("chassis state mismatch, found unexpected serial: %s",
288 		    info.smbi_serial);
289 		ret = B_FALSE;
290 	}
291 
292 	if (strcmp(info.smbi_asset, smbios_chassis_asset) != 0) {
293 		warnx("chassis state mismatch, found unexpected asset: %s",
294 		    info.smbi_asset);
295 		ret = B_FALSE;
296 	}
297 
298 	return (ret);
299 }
300 
301 boolean_t
smbios_test_chassis_verify_base(smbios_hdl_t * hdl)302 smbios_test_chassis_verify_base(smbios_hdl_t *hdl)
303 {
304 	boolean_t ret = B_TRUE;
305 	smbios_struct_t sp;
306 	smbios_chassis_t ch;
307 	smbios_chassis_entry_t *elts;
308 	uint_t nelts;
309 
310 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
311 		warnx("failed to lookup SMBIOS chassis: %s",
312 		    smbios_errmsg(smbios_errno(hdl)));
313 		return (B_FALSE);
314 	}
315 
316 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
317 		warnx("failed to get chassis: %s",
318 		    smbios_errmsg(smbios_errno(hdl)));
319 		return (B_FALSE);
320 	}
321 
322 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
323 		ret = B_FALSE;
324 	}
325 
326 	if (ch.smbc_elems != 0) {
327 		warnx("chassis state mismatch, found unexpected number of "
328 		    "elements: 0x%x", ch.smbc_elems);
329 		ret = B_FALSE;
330 	}
331 
332 	if (strcmp(ch.smbc_sku, "") != 0) {
333 		warnx("chassis state mismatch, found unexpected sku: %s",
334 		    ch.smbc_sku);
335 		ret = B_FALSE;
336 	}
337 
338 	if (smbios_info_chassis_elts(hdl, sp.smbstr_id, &nelts, &elts) != 0) {
339 		warnx("failed to get chassis elements: %s",
340 		    smbios_errmsg(smbios_errno(hdl)));
341 		return (B_FALSE);
342 	}
343 
344 	if (nelts != 0) {
345 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
346 		    "returned a non-zero number of entries: %u", nelts);
347 		ret = B_FALSE;
348 	}
349 
350 	if (elts != NULL) {
351 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
352 		    "returned a non-NULL pointer: %p", elts);
353 		ret = B_FALSE;
354 	}
355 
356 	return (ret);
357 }
358 
359 boolean_t
smbios_test_chassis_verify_sku_nocomps(smbios_hdl_t * hdl)360 smbios_test_chassis_verify_sku_nocomps(smbios_hdl_t *hdl)
361 {
362 	boolean_t ret = B_TRUE;
363 	smbios_struct_t sp;
364 	smbios_chassis_t ch;
365 	smbios_chassis_entry_t *elts;
366 	uint_t nelts;
367 
368 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
369 		warnx("failed to lookup SMBIOS chassis: %s",
370 		    smbios_errmsg(smbios_errno(hdl)));
371 		return (B_FALSE);
372 	}
373 
374 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
375 		warnx("failed to get chassis: %s",
376 		    smbios_errmsg(smbios_errno(hdl)));
377 		return (B_FALSE);
378 	}
379 
380 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
381 		ret = B_FALSE;
382 	}
383 
384 	if (ch.smbc_elems != 0) {
385 		warnx("chassis state mismatch, found unexpected number of "
386 		    "elements: 0x%x", ch.smbc_elems);
387 		ret = B_FALSE;
388 	}
389 
390 	if (ch.smbc_elemlen != sizeof (smb_chassis_entry_t)) {
391 		warnx("chassis state mismatch, found unexpected elemlen value: "
392 		    "0x%x", ch.smbc_elemlen);
393 		ret = B_FALSE;
394 	}
395 
396 	if (strcmp(ch.smbc_sku, smbios_chassis_sku) != 0) {
397 		warnx("chassis state mismatch, found unexpected sku: %s",
398 		    ch.smbc_sku);
399 		ret = B_FALSE;
400 	}
401 
402 	if (smbios_info_chassis_elts(hdl, sp.smbstr_id, &nelts, &elts) != 0) {
403 		warnx("failed to get chassis elements: %s",
404 		    smbios_errmsg(smbios_errno(hdl)));
405 		return (B_FALSE);
406 	}
407 
408 	if (nelts != 0) {
409 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
410 		    "returned a non-zero number of entries: %u", nelts);
411 		ret = B_FALSE;
412 	}
413 
414 	if (elts != NULL) {
415 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
416 		    "returned a non-NULL pointer: %p", elts);
417 		ret = B_FALSE;
418 	}
419 
420 
421 	return (ret);
422 }
423 
424 static boolean_t
smbios_test_chassis_verify_common_comps(smbios_hdl_t * hdl,smbios_struct_t * sp)425 smbios_test_chassis_verify_common_comps(smbios_hdl_t *hdl, smbios_struct_t *sp)
426 {
427 	boolean_t ret = B_TRUE;
428 	smbios_chassis_entry_t *elts;
429 	uint_t nelts;
430 
431 	if (smbios_info_chassis_elts(hdl, sp->smbstr_id, &nelts, &elts) != 0) {
432 		warnx("failed to get chassis elements: %s",
433 		    smbios_errmsg(smbios_errno(hdl)));
434 		return (B_FALSE);
435 	}
436 
437 	if (nelts != 2) {
438 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
439 		    "returned the wrong number of entries: %u", nelts);
440 		return (B_FALSE);
441 	}
442 
443 	if (elts[0].smbce_type != SMB_CELT_SMBIOS) {
444 		warnx("chassis elts[0] type mismatch, found: %u",
445 		    elts[0].smbce_type);
446 		ret = B_FALSE;
447 	}
448 
449 	if (elts[0].smbce_elt != SMB_TYPE_COOLDEV) {
450 		warnx("chassis elts[0] elt type mismatch, found: %u",
451 		    elts[0].smbce_elt);
452 		ret = B_FALSE;
453 	}
454 
455 	if (elts[0].smbce_min != 1) {
456 		warnx("chassis elts[0] minimum number mismatch, found: %u",
457 		    elts[0].smbce_min);
458 		ret = B_FALSE;
459 	}
460 
461 	if (elts[0].smbce_max != 42) {
462 		warnx("chassis elts[0] maximum number mismatch, found: %u",
463 		    elts[0].smbce_max);
464 		ret = B_FALSE;
465 	}
466 
467 	if (elts[1].smbce_type != SMB_CELT_BBOARD) {
468 		warnx("chassis elts[1] type mismatch, found: %u",
469 		    elts[1].smbce_type);
470 		ret = B_FALSE;
471 	}
472 
473 	if (elts[1].smbce_elt != SMB_BBT_IO) {
474 		warnx("chassis elts[1] elt type mismatch, found: %u",
475 		    elts[1].smbce_elt);
476 		ret = B_FALSE;
477 	}
478 
479 	if (elts[1].smbce_min != 5) {
480 		warnx("chassis elts[1] minimum number mismatch, found: %u",
481 		    elts[1].smbce_min);
482 		ret = B_FALSE;
483 	}
484 
485 	if (elts[1].smbce_max != 123) {
486 		warnx("chassis elts[1] maximum number mismatch, found: %u",
487 		    elts[1].smbce_max);
488 		ret = B_FALSE;
489 	}
490 	return (ret);
491 }
492 
493 boolean_t
smbios_test_chassis_verify_comps(smbios_hdl_t * hdl)494 smbios_test_chassis_verify_comps(smbios_hdl_t *hdl)
495 {
496 	boolean_t ret = B_TRUE;
497 	smbios_struct_t sp;
498 	smbios_chassis_t ch;
499 
500 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
501 		warnx("failed to lookup SMBIOS chassis: %s",
502 		    smbios_errmsg(smbios_errno(hdl)));
503 		return (B_FALSE);
504 	}
505 
506 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
507 		warnx("failed to get chassis: %s",
508 		    smbios_errmsg(smbios_errno(hdl)));
509 		return (B_FALSE);
510 	}
511 
512 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
513 		ret = B_FALSE;
514 	}
515 
516 	if (ch.smbc_elems != 2) {
517 		warnx("chassis state mismatch, found unexpected number of "
518 		    "elements: 0x%x", ch.smbc_elems);
519 		ret = B_FALSE;
520 	}
521 
522 	if (ch.smbc_elemlen != sizeof (smb_chassis_entry_t)) {
523 		warnx("chassis state mismatch, found unexpected elemlen value: "
524 		    "0x%x", ch.smbc_elemlen);
525 		ret = B_FALSE;
526 	}
527 
528 	if (strcmp(ch.smbc_sku, "") != 0) {
529 		warnx("chassis state mismatch, found unexpected sku: %s",
530 		    ch.smbc_sku);
531 		ret = B_FALSE;
532 	}
533 
534 	if (!smbios_test_chassis_verify_common_comps(hdl, &sp)) {
535 		ret = B_FALSE;
536 	}
537 
538 	return (ret);
539 }
540 
541 
542 boolean_t
smbios_test_chassis_verify_sku(smbios_hdl_t * hdl)543 smbios_test_chassis_verify_sku(smbios_hdl_t *hdl)
544 {
545 	boolean_t ret = B_TRUE;
546 	smbios_struct_t sp;
547 	smbios_chassis_t ch;
548 
549 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
550 		warnx("failed to lookup SMBIOS chassis: %s",
551 		    smbios_errmsg(smbios_errno(hdl)));
552 		return (B_FALSE);
553 	}
554 
555 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
556 		warnx("failed to get chassis: %s",
557 		    smbios_errmsg(smbios_errno(hdl)));
558 		return (B_FALSE);
559 	}
560 
561 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
562 		ret = B_FALSE;
563 	}
564 
565 	if (ch.smbc_elems != 2) {
566 		warnx("chassis state mismatch, found unexpected number of "
567 		    "elements: 0x%x", ch.smbc_elems);
568 		ret = B_FALSE;
569 	}
570 
571 	if (ch.smbc_elemlen != sizeof (smb_chassis_entry_t)) {
572 		warnx("chassis state mismatch, found unexpected elemlen value: "
573 		    "0x%x", ch.smbc_elemlen);
574 		ret = B_FALSE;
575 	}
576 
577 	if (strcmp(ch.smbc_sku, smbios_chassis_sku) != 0) {
578 		warnx("chassis state mismatch, found unexpected sku: %s",
579 		    ch.smbc_sku);
580 		ret = B_FALSE;
581 	}
582 
583 	if (!smbios_test_chassis_verify_common_comps(hdl, &sp)) {
584 		ret = B_FALSE;
585 	}
586 
587 	return (ret);
588 }
589