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 2021 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 boolean_t
smbios_test_chassis_mktable_comps(smbios_test_table_t * table)103 smbios_test_chassis_mktable_comps(smbios_test_table_t *table)
104 {
105 	smb_chassis_t ch;
106 	smb_chassis_entry_t ents[2];
107 
108 	smbios_test_chassis_mktable_fill_chassis(&ch);
109 	smbios_test_chassis_mktable_fill_entries(ents);
110 	ch.smbch_hdr.smbh_len += sizeof (ents);
111 	ch.smbch_cn = 2;
112 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
113 	smbios_test_table_append_raw(table, ents, sizeof (ents));
114 	smbios_test_chassis_mktable_append_strings(table);
115 	smbios_test_table_str_fini(table);
116 	smbios_test_table_append_eot(table);
117 
118 	return (B_TRUE);
119 }
120 
121 boolean_t
smbios_test_chassis_mktable_sku_nocomps(smbios_test_table_t * table)122 smbios_test_chassis_mktable_sku_nocomps(smbios_test_table_t *table)
123 {
124 	smb_chassis_t ch;
125 	const uint8_t sku_str = 5;
126 
127 	smbios_test_chassis_mktable_fill_chassis(&ch);
128 	ch.smbch_hdr.smbh_len++;
129 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
130 	smbios_test_table_append_raw(table, &sku_str, sizeof (sku_str));
131 	smbios_test_chassis_mktable_append_strings(table);
132 	smbios_test_table_append_string(table, smbios_chassis_sku);
133 	smbios_test_table_str_fini(table);
134 	smbios_test_table_append_eot(table);
135 
136 	return (B_TRUE);
137 }
138 
139 boolean_t
smbios_test_chassis_mktable_sku(smbios_test_table_t * table)140 smbios_test_chassis_mktable_sku(smbios_test_table_t *table)
141 {
142 	smb_chassis_t ch;
143 	const uint8_t sku_str = 5;
144 	smb_chassis_entry_t ents[2];
145 
146 	ch.smbch_cn = 2;
147 
148 	smbios_test_chassis_mktable_fill_chassis(&ch);
149 	smbios_test_chassis_mktable_fill_entries(ents);
150 	ch.smbch_hdr.smbh_len += sizeof (ents) + 1;
151 	(void) smbios_test_table_append(table, &ch, sizeof (ch));
152 	smbios_test_table_append_raw(table, &sku_str, sizeof (sku_str));
153 	smbios_test_chassis_mktable_append_strings(table);
154 	smbios_test_table_append_string(table, smbios_chassis_sku);
155 	smbios_test_table_str_fini(table);
156 	smbios_test_table_append_eot(table);
157 
158 	return (B_TRUE);
159 }
160 
161 boolean_t
smbios_test_chassis_verify_invlen(smbios_hdl_t * hdl)162 smbios_test_chassis_verify_invlen(smbios_hdl_t *hdl)
163 {
164 	smbios_struct_t sp;
165 	smbios_chassis_t ch;
166 
167 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
168 		warnx("failed to lookup SMBIOS chassis: %s",
169 		    smbios_errmsg(smbios_errno(hdl)));
170 		return (B_FALSE);
171 	}
172 
173 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) != -1) {
174 		warnx("accidentally parsed invalid chassis as valid");
175 		return (B_FALSE);
176 	}
177 
178 	if (smbios_errno(hdl) != ESMB_SHORT) {
179 		warnx("encountered wrong error for chassis, expected: "
180 		    "0x%x, found: 0x%x", ESMB_SHORT, smbios_errno(hdl));
181 		return (B_FALSE);
182 	}
183 
184 	return (B_TRUE);
185 }
186 
187 static boolean_t
smbios_test_chassis_verify_common(smbios_hdl_t * hdl,smbios_struct_t * sp,smbios_chassis_t * ch)188 smbios_test_chassis_verify_common(smbios_hdl_t *hdl, smbios_struct_t *sp,
189     smbios_chassis_t *ch)
190 {
191 	boolean_t ret = B_TRUE;
192 	smbios_info_t info;
193 
194 	if (ch->smbc_oemdata != smbios_chassis_oem) {
195 		warnx("chassis state mismatch, found unexpected oem data: 0x%x",
196 		    ch->smbc_oemdata);
197 		ret = B_FALSE;
198 	}
199 
200 	if (ch->smbc_lock != 0) {
201 		warnx("chassis state mismatch, found unexpected lock: 0x%x",
202 		    ch->smbc_lock);
203 		ret = B_FALSE;
204 	}
205 
206 	if (ch->smbc_type != SMB_CHT_LUNCHBOX) {
207 		warnx("chassis state mismatch, found unexpected type: 0x%x",
208 		    ch->smbc_type);
209 		ret = B_FALSE;
210 	}
211 
212 	if (ch->smbc_bustate != SMB_CHST_SAFE) {
213 		warnx("chassis state mismatch, found unexpected boot state: "
214 		    "0x%x", ch->smbc_bustate);
215 		ret = B_FALSE;
216 	}
217 
218 	if (ch->smbc_psstate != SMB_CHST_NONREC) {
219 		warnx("chassis state mismatch, found unexpected power state: "
220 		    "0x%x", ch->smbc_psstate);
221 		ret = B_FALSE;
222 	}
223 
224 	if (ch->smbc_thstate != SMB_CHST_WARNING) {
225 		warnx("chassis state mismatch, found unexpected thermal state: "
226 		    "0x%x", ch->smbc_thstate);
227 		ret = B_FALSE;
228 	}
229 
230 	if (ch->smbc_security != SMB_CHSC_NONE) {
231 		warnx("chassis state mismatch, found unexpected security "
232 		    "value: 0x%x", ch->smbc_security);
233 		ret = B_FALSE;
234 	}
235 
236 	if (ch->smbc_uheight != smbios_chassis_uheight) {
237 		warnx("chassis state mismatch, found unexpected uheight value: "
238 		    "0x%x", ch->smbc_uheight);
239 		ret = B_FALSE;
240 	}
241 
242 	if (ch->smbc_cords != smbios_chassis_uheight - 1) {
243 		warnx("chassis state mismatch, found unexpected cords value: "
244 		    "0x%x", ch->smbc_cords);
245 		ret = B_FALSE;
246 	}
247 
248 	if (ch->smbc_elemlen != sizeof (smb_chassis_entry_t)) {
249 		warnx("chassis state mismatch, found unexpected elemlen value: "
250 		    "0x%x", ch->smbc_elemlen);
251 		ret = B_FALSE;
252 	}
253 
254 	if (smbios_info_common(hdl, sp->smbstr_id, &info) != 0) {
255 		warnx("failed to get common chassis info: %s",
256 		    smbios_errmsg(smbios_errno(hdl)));
257 		return (B_FALSE);
258 	}
259 
260 	if (strcmp(info.smbi_manufacturer, smbios_chassis_mfg) != 0) {
261 		warnx("chassis state mismatch, found unexpected mfg: "
262 		    "%s", info.smbi_manufacturer);
263 		ret = B_FALSE;
264 	}
265 
266 	if (strcmp(info.smbi_version, smbios_chassis_vers) != 0) {
267 		warnx("chassis state mismatch, found unexpected version: %s",
268 		    info.smbi_version);
269 		ret = B_FALSE;
270 	}
271 
272 	if (strcmp(info.smbi_serial, smbios_chassis_serial) != 0) {
273 		warnx("chassis state mismatch, found unexpected serial: %s",
274 		    info.smbi_serial);
275 		ret = B_FALSE;
276 	}
277 
278 	if (strcmp(info.smbi_asset, smbios_chassis_asset) != 0) {
279 		warnx("chassis state mismatch, found unexpected asset: %s",
280 		    info.smbi_asset);
281 		ret = B_FALSE;
282 	}
283 
284 	return (ret);
285 }
286 
287 boolean_t
smbios_test_chassis_verify_base(smbios_hdl_t * hdl)288 smbios_test_chassis_verify_base(smbios_hdl_t *hdl)
289 {
290 	boolean_t ret = B_TRUE;
291 	smbios_struct_t sp;
292 	smbios_chassis_t ch;
293 	smbios_chassis_entry_t *elts;
294 	uint_t nelts;
295 
296 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
297 		warnx("failed to lookup SMBIOS chassis: %s",
298 		    smbios_errmsg(smbios_errno(hdl)));
299 		return (B_FALSE);
300 	}
301 
302 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
303 		warnx("failed to get chassis: %s",
304 		    smbios_errmsg(smbios_errno(hdl)));
305 		return (B_FALSE);
306 	}
307 
308 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
309 		ret = B_FALSE;
310 	}
311 
312 	if (ch.smbc_elems != 0) {
313 		warnx("chassis state mismatch, found unexpected number of "
314 		    "elements: 0x%x", ch.smbc_elems);
315 		ret = B_FALSE;
316 	}
317 
318 	if (strcmp(ch.smbc_sku, "") != 0) {
319 		warnx("chassis state mismatch, found unexpected sku: %s",
320 		    ch.smbc_sku);
321 		ret = B_FALSE;
322 	}
323 
324 	if (smbios_info_chassis_elts(hdl, sp.smbstr_id, &nelts, &elts) != 0) {
325 		warnx("failed to get chassis elements: %s",
326 		    smbios_errmsg(smbios_errno(hdl)));
327 		return (B_FALSE);
328 	}
329 
330 	if (nelts != 0) {
331 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
332 		    "returned a non-zero number of entries: %u", nelts);
333 		ret = B_FALSE;
334 	}
335 
336 	if (elts != NULL) {
337 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
338 		    "returned a non-NULL pointer: %p", elts);
339 		ret = B_FALSE;
340 	}
341 
342 	return (ret);
343 }
344 
345 boolean_t
smbios_test_chassis_verify_sku_nocomps(smbios_hdl_t * hdl)346 smbios_test_chassis_verify_sku_nocomps(smbios_hdl_t *hdl)
347 {
348 	boolean_t ret = B_TRUE;
349 	smbios_struct_t sp;
350 	smbios_chassis_t ch;
351 	smbios_chassis_entry_t *elts;
352 	uint_t nelts;
353 
354 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
355 		warnx("failed to lookup SMBIOS chassis: %s",
356 		    smbios_errmsg(smbios_errno(hdl)));
357 		return (B_FALSE);
358 	}
359 
360 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
361 		warnx("failed to get chassis: %s",
362 		    smbios_errmsg(smbios_errno(hdl)));
363 		return (B_FALSE);
364 	}
365 
366 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
367 		ret = B_FALSE;
368 	}
369 
370 	if (ch.smbc_elems != 0) {
371 		warnx("chassis state mismatch, found unexpected number of "
372 		    "elements: 0x%x", ch.smbc_elems);
373 		ret = B_FALSE;
374 	}
375 
376 	if (strcmp(ch.smbc_sku, smbios_chassis_sku) != 0) {
377 		warnx("chassis state mismatch, found unexpected sku: %s",
378 		    ch.smbc_sku);
379 		ret = B_FALSE;
380 	}
381 
382 	if (smbios_info_chassis_elts(hdl, sp.smbstr_id, &nelts, &elts) != 0) {
383 		warnx("failed to get chassis elements: %s",
384 		    smbios_errmsg(smbios_errno(hdl)));
385 		return (B_FALSE);
386 	}
387 
388 	if (nelts != 0) {
389 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
390 		    "returned a non-zero number of entries: %u", nelts);
391 		ret = B_FALSE;
392 	}
393 
394 	if (elts != NULL) {
395 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
396 		    "returned a non-NULL pointer: %p", elts);
397 		ret = B_FALSE;
398 	}
399 
400 
401 	return (ret);
402 }
403 
404 static boolean_t
smbios_test_chassis_verify_common_comps(smbios_hdl_t * hdl,smbios_struct_t * sp)405 smbios_test_chassis_verify_common_comps(smbios_hdl_t *hdl, smbios_struct_t *sp)
406 {
407 	boolean_t ret = B_TRUE;
408 	smbios_chassis_entry_t *elts;
409 	uint_t nelts;
410 
411 	if (smbios_info_chassis_elts(hdl, sp->smbstr_id, &nelts, &elts) != 0) {
412 		warnx("failed to get chassis elements: %s",
413 		    smbios_errmsg(smbios_errno(hdl)));
414 		return (B_FALSE);
415 	}
416 
417 	if (nelts != 2) {
418 		warnx("chassis state mismatch, smbios_info_chassis_elts() "
419 		    "returned the wrong number of entries: %u", nelts);
420 		return (B_FALSE);
421 	}
422 
423 	if (elts[0].smbce_type != SMB_CELT_SMBIOS) {
424 		warnx("chassis elts[0] type mismatch, found: %u",
425 		    elts[0].smbce_type);
426 		ret = B_FALSE;
427 	}
428 
429 	if (elts[0].smbce_elt != SMB_TYPE_COOLDEV) {
430 		warnx("chassis elts[0] elt type mismatch, found: %u",
431 		    elts[0].smbce_elt);
432 		ret = B_FALSE;
433 	}
434 
435 	if (elts[0].smbce_min != 1) {
436 		warnx("chassis elts[0] minimum number mismatch, found: %u",
437 		    elts[0].smbce_min);
438 		ret = B_FALSE;
439 	}
440 
441 	if (elts[0].smbce_max != 42) {
442 		warnx("chassis elts[0] maximum number mismatch, found: %u",
443 		    elts[0].smbce_max);
444 		ret = B_FALSE;
445 	}
446 
447 	if (elts[1].smbce_type != SMB_CELT_BBOARD) {
448 		warnx("chassis elts[1] type mismatch, found: %u",
449 		    elts[1].smbce_type);
450 		ret = B_FALSE;
451 	}
452 
453 	if (elts[1].smbce_elt != SMB_BBT_IO) {
454 		warnx("chassis elts[1] elt type mismatch, found: %u",
455 		    elts[1].smbce_elt);
456 		ret = B_FALSE;
457 	}
458 
459 	if (elts[1].smbce_min != 5) {
460 		warnx("chassis elts[1] minimum number mismatch, found: %u",
461 		    elts[1].smbce_min);
462 		ret = B_FALSE;
463 	}
464 
465 	if (elts[1].smbce_max != 123) {
466 		warnx("chassis elts[1] maximum number mismatch, found: %u",
467 		    elts[1].smbce_max);
468 		ret = B_FALSE;
469 	}
470 	return (ret);
471 }
472 
473 boolean_t
smbios_test_chassis_verify_comps(smbios_hdl_t * hdl)474 smbios_test_chassis_verify_comps(smbios_hdl_t *hdl)
475 {
476 	boolean_t ret = B_TRUE;
477 	smbios_struct_t sp;
478 	smbios_chassis_t ch;
479 
480 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
481 		warnx("failed to lookup SMBIOS chassis: %s",
482 		    smbios_errmsg(smbios_errno(hdl)));
483 		return (B_FALSE);
484 	}
485 
486 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
487 		warnx("failed to get chassis: %s",
488 		    smbios_errmsg(smbios_errno(hdl)));
489 		return (B_FALSE);
490 	}
491 
492 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
493 		ret = B_FALSE;
494 	}
495 
496 	if (ch.smbc_elems != 2) {
497 		warnx("chassis state mismatch, found unexpected number of "
498 		    "elements: 0x%x", ch.smbc_elems);
499 		ret = B_FALSE;
500 	}
501 
502 	if (strcmp(ch.smbc_sku, "") != 0) {
503 		warnx("chassis state mismatch, found unexpected sku: %s",
504 		    ch.smbc_sku);
505 		ret = B_FALSE;
506 	}
507 
508 	if (!smbios_test_chassis_verify_common_comps(hdl, &sp)) {
509 		ret = B_FALSE;
510 	}
511 
512 	return (ret);
513 }
514 
515 
516 boolean_t
smbios_test_chassis_verify_sku(smbios_hdl_t * hdl)517 smbios_test_chassis_verify_sku(smbios_hdl_t *hdl)
518 {
519 	boolean_t ret = B_TRUE;
520 	smbios_struct_t sp;
521 	smbios_chassis_t ch;
522 
523 	if (smbios_lookup_type(hdl, SMB_TYPE_CHASSIS, &sp) == -1) {
524 		warnx("failed to lookup SMBIOS chassis: %s",
525 		    smbios_errmsg(smbios_errno(hdl)));
526 		return (B_FALSE);
527 	}
528 
529 	if (smbios_info_chassis(hdl, sp.smbstr_id, &ch) == -1) {
530 		warnx("failed to get chassis: %s",
531 		    smbios_errmsg(smbios_errno(hdl)));
532 		return (B_FALSE);
533 	}
534 
535 	if (!smbios_test_chassis_verify_common(hdl, &sp, &ch)) {
536 		ret = B_FALSE;
537 	}
538 
539 	if (ch.smbc_elems != 2) {
540 		warnx("chassis state mismatch, found unexpected number of "
541 		    "elements: 0x%x", ch.smbc_elems);
542 		ret = B_FALSE;
543 	}
544 
545 	if (strcmp(ch.smbc_sku, smbios_chassis_sku) != 0) {
546 		warnx("chassis state mismatch, found unexpected sku: %s",
547 		    ch.smbc_sku);
548 		ret = B_FALSE;
549 	}
550 
551 	if (!smbios_test_chassis_verify_common_comps(hdl, &sp)) {
552 		ret = B_FALSE;
553 	}
554 
555 	return (ret);
556 }
557