1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <alloca.h>
30 #include <sys/byteorder.h>
31 #include "fru_access_impl.h"
32 #include "fruraw.h"
33 
34 #pragma init(initialize_raw_access)
35 
36 static hash_obj_t	*hash_table[TABLE_SIZE];
37 extern raw_list_t 	*g_raw;
38 
39 static void
40 initialize_raw_access(void)
41 {
42 	int	count;
43 
44 	for (count = 0; count < TABLE_SIZE; count++) {
45 		hash_table[count] = NULL;
46 	}
47 }
48 
49 
50 static hash_obj_t *
51 lookup_handle_object(handle_t	handle, int object_type)
52 {
53 	handle_t index_to_hash;
54 	hash_obj_t *first_hash_obj;
55 	hash_obj_t *next_hash_obj;
56 
57 	index_to_hash = (handle % TABLE_SIZE);
58 
59 	first_hash_obj = hash_table[index_to_hash];
60 	for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
61 	    next_hash_obj = next_hash_obj->next) {
62 		if ((handle == next_hash_obj->obj_hdl) &&
63 		    (object_type == next_hash_obj->object_type)) {
64 			return (next_hash_obj);
65 		}
66 	}
67 	return (NULL);
68 }
69 
70 
71 static void
72 add_hashobject_to_hashtable(hash_obj_t *hash_obj)
73 {
74 	handle_t index_to_hash;
75 	static	uint64_t handle_count = 0;
76 
77 	hash_obj->obj_hdl = ++handle_count;	/* store the handle */
78 
79 	/* where to add ? */
80 	index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE);
81 
82 	hash_obj->next = hash_table[index_to_hash];
83 	hash_table[index_to_hash] = hash_obj;	/* hash obj. added */
84 
85 	if (hash_obj->next != NULL) {
86 		hash_obj->next->prev = hash_obj;
87 	}
88 }
89 
90 
91 static hash_obj_t *
92 create_container_hash_object(void)
93 {
94 	hash_obj_t *hash_obj;
95 	container_obj_t *cont_obj;
96 
97 	cont_obj = malloc(sizeof (container_obj_t));
98 	if (cont_obj == NULL) {
99 		return (NULL);
100 	}
101 
102 	hash_obj = malloc(sizeof (hash_obj_t));
103 	if (hash_obj == NULL) {
104 		free(cont_obj);
105 		return (NULL);
106 	}
107 
108 	cont_obj->sec_obj_list = NULL;
109 
110 	hash_obj->object_type = CONTAINER_TYPE;
111 	hash_obj->u.cont_obj = cont_obj;
112 	hash_obj->next = NULL;
113 	hash_obj->prev = NULL;
114 
115 	return (hash_obj);
116 }
117 
118 
119 static hash_obj_t *
120 create_section_hash_object(void)
121 {
122 	hash_obj_t *hash_obj;
123 	section_obj_t *sec_obj;
124 
125 	sec_obj	= malloc(sizeof (section_obj_t));
126 	if (sec_obj == NULL) {
127 		return (NULL);
128 	}
129 
130 	hash_obj = malloc(sizeof (hash_obj_t));
131 	if (hash_obj == NULL) {
132 		free(sec_obj);
133 		return (NULL);
134 	}
135 
136 	sec_obj->next = NULL;
137 	sec_obj->seg_obj_list = NULL;
138 
139 	hash_obj->u.sec_obj = sec_obj;
140 	hash_obj->object_type = SECTION_TYPE;
141 	hash_obj->next = NULL;
142 	hash_obj->prev = NULL;
143 
144 	return (hash_obj);
145 }
146 
147 
148 static hash_obj_t *
149 create_segment_hash_object(void)
150 {
151 	hash_obj_t *hash_obj;
152 	segment_obj_t *seg_obj;
153 
154 	seg_obj	= malloc(sizeof (segment_obj_t));
155 	if (seg_obj == NULL) {
156 		return (NULL);
157 	}
158 
159 	hash_obj = malloc(sizeof (hash_obj_t));
160 	if (hash_obj == NULL) {
161 		free(seg_obj);
162 		return (NULL);
163 	}
164 
165 	seg_obj->next = NULL;
166 	seg_obj->pkt_obj_list = NULL;
167 
168 	hash_obj->object_type = SEGMENT_TYPE;
169 	hash_obj->u.seg_obj = seg_obj;
170 	hash_obj->next = NULL;
171 	hash_obj->prev = NULL;
172 
173 	return (hash_obj);
174 }
175 
176 
177 static hash_obj_t *
178 create_packet_hash_object(void)
179 {
180 	hash_obj_t *hash_obj;
181 	packet_obj_t *pkt_obj;
182 
183 	pkt_obj	= malloc(sizeof (packet_obj_t));
184 	if (pkt_obj == NULL) {
185 		return (NULL);
186 	}
187 
188 	hash_obj = malloc(sizeof (hash_obj_t));
189 	if (hash_obj == NULL) {
190 		free(pkt_obj);
191 		return (NULL);
192 	}
193 
194 	pkt_obj->next = NULL;
195 
196 	hash_obj->object_type = PACKET_TYPE;
197 	hash_obj->u.pkt_obj = pkt_obj;
198 	hash_obj->next = NULL;
199 	hash_obj->prev = NULL;
200 
201 	return (hash_obj);
202 }
203 
204 
205 
206 static hash_obj_t *
207 get_container_hash_object(int	object_type, handle_t	handle)
208 {
209 	hash_obj_t	*hash_obj;
210 
211 	switch (object_type) {
212 	case CONTAINER_TYPE:
213 		break;
214 	case SECTION_TYPE:
215 		hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
216 		if (hash_obj == NULL) {
217 			return (NULL);
218 		}
219 		break;
220 	case SEGMENT_TYPE:
221 		hash_obj = lookup_handle_object(handle, SECTION_TYPE);
222 		if (hash_obj == NULL) {
223 			return (NULL);
224 		}
225 		hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
226 		    CONTAINER_TYPE);
227 		break;
228 	case PACKET_TYPE:
229 		break;
230 	default:
231 		return (NULL);
232 	}
233 
234 	return (hash_obj);
235 }
236 
237 
238 static void
239 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
240 {
241 	hash_obj_t *next_hash;
242 
243 	/* add the packet object in the end of list */
244 	child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;
245 
246 	if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
247 		parent_obj->u.seg_obj->pkt_obj_list = child_obj;
248 		return;
249 	}
250 
251 	for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
252 	    next_hash->u.pkt_obj->next != NULL;
253 	    next_hash = next_hash->u.pkt_obj->next) {
254 		;
255 	}
256 
257 	next_hash->u.pkt_obj->next = child_obj;
258 }
259 
260 
261 static void
262 free_pkt_object_list(hash_obj_t	*hash_obj)
263 {
264 	hash_obj_t *next_obj;
265 	hash_obj_t *free_obj;
266 
267 	next_obj = hash_obj->u.seg_obj->pkt_obj_list;
268 	while (next_obj != NULL) {
269 		free_obj = next_obj;
270 		next_obj = next_obj->u.pkt_obj->next;
271 		/* if prev is NULL it's the first object in the list */
272 		if (free_obj->prev == NULL) {
273 			hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
274 			    free_obj->next;
275 			if (free_obj->next != NULL) {
276 				free_obj->next->prev = free_obj->prev;
277 			}
278 		} else {
279 			free_obj->prev->next = free_obj->next;
280 			if (free_obj->next != NULL) {
281 				free_obj->next->prev = free_obj->prev;
282 			}
283 		}
284 
285 		free(free_obj->u.pkt_obj->payload);
286 		free(free_obj->u.pkt_obj);
287 		free(free_obj);
288 	}
289 
290 	hash_obj->u.seg_obj->pkt_obj_list = NULL;
291 }
292 
293 
294 static void
295 free_segment_hash(handle_t handle, hash_obj_t *sec_hash)
296 {
297 	hash_obj_t *seg_hash;
298 	hash_obj_t *next_hash;
299 
300 	seg_hash = sec_hash->u.sec_obj->seg_obj_list;
301 	if (seg_hash == NULL) {
302 		return;
303 	}
304 
305 	if (seg_hash->obj_hdl == handle) {
306 		sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
307 	} else {
308 		while (seg_hash->obj_hdl != handle) {
309 			next_hash = seg_hash;
310 			seg_hash = seg_hash->u.seg_obj->next;
311 			if (seg_hash == NULL) {
312 				return;
313 			}
314 		}
315 		next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
316 	}
317 
318 	if (seg_hash->prev == NULL) {
319 		hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
320 		if (seg_hash->next != NULL) {
321 			seg_hash->next->prev = NULL;
322 		}
323 	} else {
324 		seg_hash->prev->next = seg_hash->next;
325 		if (seg_hash->next != NULL) {
326 			seg_hash->next->prev = seg_hash->prev;
327 		}
328 	}
329 
330 	free_pkt_object_list(seg_hash);
331 	free(seg_hash->u.seg_obj);
332 	free(seg_hash);
333 }
334 
335 
336 
337 static void
338 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
339 {
340 	hash_obj_t *next_hash;
341 
342 	child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
343 	if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
344 		parent_obj->u.cont_obj->sec_obj_list = child_obj;
345 		return;
346 	}
347 
348 	for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
349 	    next_hash->u.sec_obj->next != NULL;
350 	    next_hash = next_hash->u.sec_obj->next) {
351 		;
352 	}
353 
354 	next_hash->u.sec_obj->next = child_obj;
355 }
356 
357 
358 static void
359 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
360 {
361 	hash_obj_t *next_hash;
362 
363 	child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
364 	if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
365 		parent_obj->u.sec_obj->seg_obj_list = child_obj;
366 		return;
367 	}
368 
369 	for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
370 	    next_hash->u.seg_obj->next != NULL;
371 	    next_hash = next_hash->u.seg_obj->next) {
372 		;
373 	}
374 
375 	next_hash->u.seg_obj->next = child_obj;
376 }
377 
378 
379 static char *
380 tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
381 {
382 	int i = 0;
383 	int j = 0;
384 
385 	for (i = 0; buf[i] != '\0'; i++) {
386 		for (j = 0; j < strlen(separator); j++) {
387 			if (buf[i] == separator[j]) {
388 				buf[i] = '\0';
389 				*nextBuf = &(buf[i+1]);
390 				*matched = separator[j];
391 				return (buf);
392 			}
393 		}
394 	}
395 
396 	*nextBuf = buf;
397 	*matched = '\0';
398 	return (NULL);
399 }
400 
401 
402 static void
403 copy_segment_layout(segment_t *seghdr, void *layout)
404 {
405 	segment_layout_t *seg_layout;
406 
407 	seg_layout = (segment_layout_t *)layout;
408 	(void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
409 	seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
410 	seghdr->offset = BE_16(seg_layout->offset);
411 	seghdr->length = BE_16(seg_layout->length);
412 }
413 
414 
415 static int
416 get_container_info(const char *def_file, const char *cont_desc_str,
417     container_info_t *cont_info)
418 {
419 	char *item;
420 	char *token;
421 	char *field;
422 	char matched;
423 	char buf[1024];
424 	int foundIt = 0;
425 	FILE *file = fopen(def_file, "r");
426 
427 	if (file == NULL)
428 		return (-1);
429 
430 	cont_info->num_sections = 0;
431 
432 	while (fgets(buf, sizeof (buf), file) != NULL) {
433 		/* ignore all comments */
434 		token = tokenizer(buf, "#", &field, &matched);
435 		/* find the names */
436 		token = tokenizer(buf, ":", &field, &matched);
437 		if (token != 0x00) {
438 			token = tokenizer(token, "|", &item, &matched);
439 			while (token != 0x00) {
440 				if (strcmp(token, cont_desc_str) == 0) {
441 					foundIt = 1;
442 					goto found;
443 				}
444 				token = tokenizer(item, "|", &item, &matched);
445 			}
446 			/* check the last remaining item */
447 			if ((item != 0x00) &&
448 			    (strcmp(item, cont_desc_str) == 0)) {
449 				foundIt = 1;
450 				goto found;
451 			}
452 		}
453 	}
454 
455 found :
456 	if (foundIt == 1) {
457 		token = tokenizer(field, ":", &field, &matched);
458 		if (token == 0x00) {
459 			(void) fclose(file);
460 			return (-1);
461 		}
462 		cont_info->header_ver = (headerrev_t)atoi(token);
463 
464 		token = tokenizer(field, ":\n", &field, &matched);
465 		while (token != 0x00) {
466 			token = tokenizer(token, ",", &item, &matched);
467 			if (token == 0x00) {
468 				(void) fclose(file);
469 				return (-1);
470 			}
471 			if (atoi(token) == 1) {
472 				cont_info->section_info[cont_info->
473 				    num_sections].description.field.read_only
474 				    = 1;
475 			} else if (atoi(token) == 0) {
476 				cont_info->section_info[cont_info->
477 				    num_sections].description.field.read_only
478 				    = 0;
479 			} else {
480 				(void) fclose(file);
481 				return (-1);
482 			}
483 
484 			token = tokenizer(item, ",", &item, &matched);
485 			if (token == 0x00) {
486 				(void) fclose(file);
487 				return (-1);
488 			}
489 
490 			cont_info->section_info[cont_info->
491 			    num_sections].address = atoi(token);
492 			if (item == '\0') {
493 				(void) fclose(file);
494 				return (-1);
495 			}
496 			cont_info->section_info[cont_info->num_sections].size =
497 			    atoi(item);
498 			(cont_info->num_sections)++;
499 
500 			token = tokenizer(field, ":\n ", &field, &matched);
501 		}
502 	}
503 	(void) fclose(file);
504 
505 	return (0);
506 }
507 
508 
509 /* ARGSUSED */
510 int
511 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
512     door_cred_t *cred)
513 {
514 	int count;
515 	hash_obj_t *sec_object;
516 	hash_obj_t *seg_object;
517 	section_obj_t *sec_obj;
518 
519 	sec_object = lookup_handle_object(section, SECTION_TYPE);
520 	if (sec_object == NULL) {
521 		return (-1);
522 	}
523 
524 	sec_obj	= sec_object->u.sec_obj;
525 	if (sec_obj == NULL) {
526 		return (-1);
527 	}
528 
529 	if (sec_obj->num_of_segment > maxseg) {
530 		return (-1);
531 	}
532 
533 	seg_object = sec_object->u.sec_obj->seg_obj_list;
534 	if (seg_object == NULL) {
535 		return (-1);
536 	}
537 
538 	for (count = 0; count < sec_obj->num_of_segment; count++) {
539 
540 		/* populate segment_t */
541 		segment->handle = seg_object->obj_hdl;
542 		(void) memcpy(segment->name,
543 		    seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
544 		segment->descriptor = seg_object->u.seg_obj->segment.descriptor;
545 
546 		segment->offset	= seg_object->u.seg_obj->segment.offset;
547 		segment->length	= seg_object->u.seg_obj->segment.length;
548 		seg_object = seg_object->u.seg_obj->next;
549 		segment++;
550 	}
551 	return (0);
552 }
553 
554 
555 static int
556 raw_memcpy(void *buffer, raw_list_t *rawlist, int offset, int size)
557 {
558 	if (offset + size > rawlist->size) {
559 		size = rawlist->size - offset;
560 	}
561 
562 	(void) memcpy(buffer, &rawlist->raw[offset], size);
563 
564 	return (size);
565 }
566 
567 
568 static int
569 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
570 {
571 	int crc_offset = 0;
572 	unsigned char orig_crc8 = 0;
573 	unsigned char calc_crc8 = 0;
574 
575 	switch (head_ver) {
576 		case SECTION_HDR_VER:
577 			crc_offset = 4;
578 			break;
579 		default:
580 			errno = EINVAL;
581 			return (0);
582 	}
583 
584 	orig_crc8 = bytes[crc_offset];
585 	bytes[crc_offset] = 0x00; /* clear for calc */
586 	calc_crc8 = compute_crc8(bytes, length);
587 	bytes[crc_offset] = orig_crc8; /* restore */
588 
589 	return (orig_crc8 == calc_crc8);
590 }
591 
592 
593 static int
594 get_section(raw_list_t *rawlist, hash_obj_t *sec_hash, section_t *section)
595 {
596 	int retval;
597 	int size;
598 	int count;
599 	uint16_t hdrver;
600 	hash_obj_t *seg_hash;
601 	unsigned char *buffer;
602 	section_obj_t *sec_obj;
603 	section_layout_t sec_hdr;
604 	segment_layout_t *seg_hdr;
605 	segment_layout_t *seg_buf;
606 
607 	sec_obj	= sec_hash->u.sec_obj;
608 	if (sec_obj == NULL) {
609 		return (-1);
610 	}
611 
612 	/* populate section_t */
613 	section->handle = sec_hash->obj_hdl;
614 	section->offset = sec_obj->section.offset;
615 	section->length = sec_obj->section.length;
616 	section->protection = sec_obj->section.protection;
617 	section->version = sec_obj->section.version;
618 
619 	/* read section header layout */
620 	retval = raw_memcpy(&sec_hdr, rawlist, sec_obj->section.offset,
621 	    sizeof (sec_hdr));
622 
623 	if (retval != sizeof (sec_hdr)) {
624 		return (-1);
625 	}
626 
627 
628 	hdrver = GET_SECTION_HDR_VERSION;
629 
630 	if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
631 	    (hdrver != section->version)) {
632 		return (-1);
633 	}
634 
635 	/* size = section layout + total sizeof segment header */
636 	size = sizeof (sec_hdr) + ((sec_hdr.segmentcount)
637 	    * sizeof (segment_layout_t));
638 
639 	buffer = alloca(size);
640 	if (buffer == NULL) {
641 		return (-1);
642 	}
643 
644 	/* segment header buffer */
645 	seg_buf = alloca(size - sizeof (sec_hdr));
646 	if (seg_buf == NULL) {
647 		return (-1);
648 	}
649 
650 	/* read segment header */
651 	retval = raw_memcpy(seg_buf, rawlist,
652 	    sec_obj->section.offset + sizeof (sec_hdr),
653 	    size - sizeof (sec_hdr));
654 
655 	if (retval != (size - sizeof (sec_hdr))) {
656 		return (-1);
657 	}
658 
659 	/* copy section header layout */
660 	(void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));
661 
662 	/* copy segment header layout */
663 	(void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
664 	    sizeof (sec_hdr));
665 
666 	/* verify crc8 */
667 	retval = verify_header_crc8(hdrver, buffer, size);
668 	if (retval != TRUE) {
669 		return (-1);
670 	}
671 
672 	section->version = hdrver;
673 	sec_obj->section.version = hdrver;
674 
675 	seg_hdr	= (segment_layout_t *)seg_buf;
676 
677 	/* bug fix for frutool */
678 	if (sec_hash->u.sec_obj->seg_obj_list != NULL) {
679 		return (0);
680 	} else {
681 		sec_obj->num_of_segment = 0;
682 	}
683 	for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {
684 
685 		seg_hash = create_segment_hash_object();
686 		if (seg_hash == NULL) {
687 			return (-1);
688 		}
689 		add_hashobject_to_hashtable(seg_hash);
690 		copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
691 		add_to_seg_object_list(sec_hash, seg_hash);
692 		sec_obj->num_of_segment++;
693 	}
694 	return (0);
695 }
696 
697 /* ARGSUSED */
698 int
699 fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
700     door_cred_t *cred)
701 {
702 	int count;
703 	int num_sec = 0;
704 	hash_obj_t *cont_object;
705 	hash_obj_t *sec_hash;
706 
707 	cont_object = lookup_handle_object(container, CONTAINER_TYPE);
708 	if (cont_object == NULL) {
709 		return (-1);
710 	}
711 
712 	if (cont_object->u.cont_obj->num_of_section > maxsec) {
713 		return (-1);
714 	}
715 
716 	sec_hash = cont_object->u.cont_obj->sec_obj_list;
717 	if (sec_hash == NULL) {
718 		return (-1);
719 	}
720 
721 	for (count = 0; count < cont_object->u.cont_obj->num_of_section;
722 	    count++) {
723 		section->version = -1;
724 		/* populate section_t */
725 		if (get_section(g_raw, sec_hash, section) == 0) {
726 			section++;
727 			num_sec++;
728 		}
729 		sec_hash = sec_hash->u.sec_obj->next;
730 	}
731 	return (num_sec);
732 }
733 
734 
735 static uint32_t
736 get_checksum_crc(hash_obj_t *seg_hash, int data_size)
737 {
738 	int protection;
739 	int offset = 0;
740 	uint32_t crc;
741 	hash_obj_t *sec_hash;
742 	hash_obj_t *pkt_hash;
743 	unsigned char *buffer;
744 
745 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
746 	    SECTION_TYPE);
747 	if (sec_hash == NULL) {
748 		return ((uint32_t)-1);
749 	}
750 
751 	buffer = alloca(data_size);
752 	if (buffer == NULL) {
753 		return ((uint32_t)-1);
754 	}
755 
756 	/* traverse the packet object list for all the tags and payload */
757 	for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL;
758 	    pkt_hash = pkt_hash->u.pkt_obj->next) {
759 		(void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
760 		    pkt_hash->u.pkt_obj->tag_size);
761 		offset += pkt_hash->u.pkt_obj->tag_size;
762 		(void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload,
763 		    pkt_hash->u.pkt_obj->paylen);
764 		offset += pkt_hash->u.pkt_obj->paylen;
765 	}
766 
767 	protection = sec_hash->u.sec_obj->section.protection;
768 
769 	if (protection == READ_ONLY_SECTION) { /* read-only section */
770 		crc = compute_crc32(buffer, data_size);
771 	} else {		/* read/write section */
772 		crc = compute_checksum32(buffer, data_size);
773 	}
774 	return (crc);	/* computed crc */
775 }
776 
777 
778 static int
779 get_packet(raw_list_t *rawlist, void *buffer, int size, int offset)
780 {
781 	int retval;
782 
783 	retval = raw_memcpy(buffer, rawlist, offset, size);
784 
785 	if (retval != -1) {
786 		return (0);
787 	}
788 	return (-1);
789 }
790 
791 
792 static int
793 get_packets(hash_obj_t *seg_hash, raw_list_t *rawlist, int offset, int length)
794 {
795 	int tag_size;
796 	int paylen;
797 	int retval;
798 	int seg_limit = 0;
799 	int pktcnt = 0;
800 	char *data;
801 	uint32_t crc;
802 	uint32_t origcrc;
803 	fru_tag_t tag;
804 	hash_obj_t *pkt_hash_obj;
805 	hash_obj_t *sec_hash;
806 	fru_segdesc_t *segdesc;
807 	fru_tagtype_t tagtype;
808 	char *ignore_flag;
809 
810 	retval = get_packet(rawlist, &tag, sizeof (fru_tag_t), offset);
811 	if (retval == -1) {
812 		return (-1);
813 	}
814 
815 	/* section hash object */
816 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
817 	    SECTION_TYPE);
818 
819 	if (sec_hash == NULL) {
820 		return (-1);
821 	}
822 
823 	seg_hash->u.seg_obj->trailer_offset = offset;
824 
825 	data = (char *)&tag;
826 	while (data[0] != SEG_TRAILER_TAG) {
827 		tagtype	= get_tag_type(&tag); /* verify tag type */
828 		if (tagtype == -1) {
829 			return (-1);
830 		}
831 
832 		tag_size = get_tag_size(tagtype);
833 		if (tag_size == -1) {
834 			return (-1);
835 		}
836 
837 		seg_limit += tag_size;
838 		if (seg_limit > length) {
839 			return (-1);
840 		}
841 
842 		paylen = get_payload_length((void *)&tag);
843 		if (paylen == -1) {
844 			return (-1);
845 		}
846 
847 		seg_limit += paylen;
848 		if (seg_limit > length) {
849 			return (-1);
850 		}
851 		if ((offset + tag_size + paylen) >
852 		    (sec_hash->u.sec_obj->section.offset +
853 		    sec_hash->u.sec_obj->section.length)) {
854 			return (-1);
855 		}
856 
857 		pkt_hash_obj = create_packet_hash_object();
858 		if (pkt_hash_obj == NULL) {
859 			return (-1);
860 		}
861 
862 		pkt_hash_obj->u.pkt_obj->payload = malloc(paylen);
863 		if (pkt_hash_obj->u.pkt_obj->payload == NULL) {
864 			free(pkt_hash_obj);
865 			return (-1);
866 		}
867 
868 		offset += tag_size;
869 
870 		retval = raw_memcpy(pkt_hash_obj->u.pkt_obj->payload, rawlist,
871 		    offset, paylen);
872 
873 		if (retval != paylen) {
874 			free(pkt_hash_obj->u.pkt_obj->payload);
875 			free(pkt_hash_obj);
876 			return (-1);
877 		}
878 
879 		/* don't change this */
880 		pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
881 		(void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
882 		pkt_hash_obj->u.pkt_obj->paylen = paylen;
883 		pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
884 		pkt_hash_obj->u.pkt_obj->payload_offset = offset;
885 
886 		offset += paylen;
887 
888 		add_hashobject_to_hashtable(pkt_hash_obj);
889 		add_to_pkt_object_list(seg_hash, pkt_hash_obj);
890 
891 		pktcnt++;
892 
893 		retval = get_packet(rawlist, &tag, sizeof (fru_tag_t),
894 		    offset);
895 		if (retval == -1) {
896 			return (retval);
897 		}
898 
899 		data = (char *)&tag;
900 	}
901 
902 	segdesc	= (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
903 
904 	seg_hash->u.seg_obj->trailer_offset = offset;
905 
906 	if (!segdesc->field.ignore_checksum)  {
907 		crc = get_checksum_crc(seg_hash, seg_limit);
908 		offset = seg_hash->u.seg_obj->segment.offset;
909 
910 		retval = raw_memcpy(&origcrc, rawlist, offset + seg_limit + 1,
911 		    sizeof (origcrc));
912 
913 		ignore_flag = getenv(IGNORE_CHECK);
914 		if (ignore_flag != NULL) {
915 			return (pktcnt);
916 		}
917 
918 		if (retval != sizeof (origcrc)) {
919 			return (-1);
920 		}
921 
922 		origcrc = BE_32(origcrc);
923 		if (origcrc != crc) {
924 			seg_hash->u.seg_obj->trailer_offset = offset;
925 			return (-1);
926 		}
927 	}
928 
929 	return (pktcnt);
930 }
931 
932 /* ARGSUSED */
933 int
934 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
935 {
936 	hash_obj_t *hash_object;
937 
938 	hash_object = lookup_handle_object(container, CONTAINER_TYPE);
939 	if (hash_object == NULL) {
940 		return (-1);
941 	}
942 
943 	return (hash_object->u.cont_obj->num_of_section);
944 }
945 
946 /* ARGSUSED */
947 int
948 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
949 {
950 	hash_obj_t *sec_object;
951 	section_obj_t *sec_obj;
952 
953 	sec_object = lookup_handle_object(section, SECTION_TYPE);
954 	if (sec_object == NULL) {
955 		return (-1);
956 	}
957 
958 	sec_obj	= sec_object->u.sec_obj;
959 	if (sec_obj == NULL) {
960 		return (-1);
961 	}
962 
963 	return (sec_obj->num_of_segment);
964 }
965 
966 /* ARGSUSED */
967 int
968 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
969 {
970 	int pktcnt;
971 	int length;
972 	uint16_t offset;
973 	hash_obj_t *cont_hash_obj;
974 	hash_obj_t *seg_hash;
975 	hash_obj_t *sec_hash;
976 	fru_segdesc_t *segdesc;
977 	segment_obj_t *segment_object;
978 
979 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
980 	if (seg_hash == NULL) {
981 		return (-1);
982 	}
983 
984 	segment_object = seg_hash->u.seg_obj;
985 	if (segment_object == NULL) {
986 		return (-1);
987 	}
988 
989 	segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
990 	if (segdesc->field.opaque) {
991 		return (0);
992 	}
993 
994 	offset = segment_object->segment.offset;
995 	length = segment_object->segment.length;
996 
997 	cont_hash_obj = get_container_hash_object(SEGMENT_TYPE,
998 	    segment_object->section_hdl);
999 
1000 	if (cont_hash_obj == NULL) {
1001 		return (-1);
1002 	}
1003 
1004 	if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
1005 		return (segment_object->num_of_packets);
1006 	}
1007 	/* section hash object */
1008 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1009 	    SECTION_TYPE);
1010 	if (sec_hash == NULL) {
1011 		return (-1);
1012 	}
1013 
1014 	/* valid segment header b'cos crc8 already validated */
1015 	if (offset < sec_hash->u.sec_obj->section.offset) {
1016 		return (-1);
1017 	}
1018 
1019 	segment_object->num_of_packets = 0;
1020 
1021 	pktcnt = get_packets(seg_hash, g_raw, offset, length);
1022 	if (pktcnt == -1) {
1023 		free_pkt_object_list(seg_hash);
1024 		seg_hash->u.seg_obj->pkt_obj_list = NULL;
1025 	}
1026 
1027 	segment_object->num_of_packets = pktcnt;
1028 
1029 	return (segment_object->num_of_packets);
1030 }
1031 
1032 /* ARGSUSED */
1033 int
1034 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
1035     door_cred_t *cred)
1036 {
1037 	int count;
1038 	hash_obj_t *seg_hash_obj;
1039 	hash_obj_t *pkt_hash_obj;
1040 
1041 	/* segment hash object */
1042 	seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE);
1043 	if (seg_hash_obj == NULL) {
1044 		return (-1);
1045 	}
1046 
1047 	if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
1048 		return (-1);
1049 	}
1050 
1051 	pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list;
1052 	if (pkt_hash_obj == NULL) {
1053 		return (-1);
1054 	}
1055 
1056 	for (count = 0; count < maxpackets; count++, packet++) {
1057 		packet->handle	= pkt_hash_obj->obj_hdl;
1058 		packet->tag = 0;
1059 		(void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
1060 		    pkt_hash_obj->u.pkt_obj->tag_size);
1061 		pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
1062 	}
1063 
1064 	return (0);
1065 }
1066 
1067 /* ARGSUSED */
1068 ssize_t
1069 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
1070     door_cred_t *cred)
1071 {
1072 	hash_obj_t *packet_hash_obj;
1073 
1074 	/* packet hash object */
1075 	packet_hash_obj	= lookup_handle_object(packet, PACKET_TYPE);
1076 	if (packet_hash_obj == NULL) {
1077 		return (-1);
1078 	}
1079 
1080 	/* verify payload length */
1081 	if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
1082 		return (-1);
1083 	}
1084 
1085 	(void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes);
1086 	return (nbytes);
1087 }
1088 
1089 
1090 container_hdl_t
1091 open_raw_data(raw_list_t *node)
1092 {
1093 	char *cont_conf_file = NULL;
1094 	hash_obj_t *cont_hash_obj;
1095 	hash_obj_t *sec_hash_obj;
1096 	container_info_t cont_info;
1097 	int retval;
1098 	int count;
1099 
1100 	cont_hash_obj = create_container_hash_object();
1101 	if (cont_hash_obj == NULL) {
1102 		return (NULL);
1103 	}
1104 
1105 	add_hashobject_to_hashtable(cont_hash_obj);
1106 
1107 	(void) strncpy(cont_hash_obj->u.cont_obj->device_pathname, "unknown",
1108 	    sizeof (cont_hash_obj->u.cont_obj->device_pathname));
1109 
1110 	cont_conf_file = getenv(FRU_CONT_CONF_ENV_VAR);
1111 	if (cont_conf_file == NULL) {
1112 		cont_conf_file = FRU_CONT_CONF_SPARC;
1113 		retval = get_container_info(cont_conf_file, node->cont_type,
1114 		    &cont_info);
1115 		if (retval < 0) {
1116 			cont_conf_file = FRU_CONT_CONF_X86;
1117 			retval = get_container_info(cont_conf_file,
1118 			    node->cont_type, &cont_info);
1119 		}
1120 	} else {
1121 		retval = get_container_info(cont_conf_file, node->cont_type,
1122 		    &cont_info);
1123 	}
1124 
1125 	if (retval < 0) {
1126 		return (NULL);
1127 	}
1128 
1129 	cont_hash_obj->u.cont_obj->num_of_section = cont_info.num_sections;
1130 	cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
1131 
1132 	for (count = 0; count < cont_info.num_sections; count++) {
1133 		sec_hash_obj = create_section_hash_object();
1134 		if (sec_hash_obj == NULL) {
1135 			return (NULL);
1136 		}
1137 
1138 		add_hashobject_to_hashtable(sec_hash_obj);
1139 
1140 		sec_hash_obj->u.sec_obj->section.offset =
1141 		    cont_info.section_info[count].address;
1142 
1143 		sec_hash_obj->u.sec_obj->section.protection =
1144 		    cont_info.section_info[count].description.field.read_only;
1145 
1146 		sec_hash_obj->u.sec_obj->section.length =
1147 		    cont_info.section_info[count].size;
1148 		sec_hash_obj->u.sec_obj->section.version =
1149 		    cont_info.header_ver;
1150 
1151 		add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
1152 	}
1153 
1154 	return (cont_hash_obj->obj_hdl);
1155 }
1156 
1157 
1158 int
1159 fru_close_container(container_hdl_t container)
1160 {
1161 	hash_obj_t *hash_obj;
1162 	hash_obj_t *prev_hash;
1163 	hash_obj_t *sec_hash_obj;
1164 	handle_t obj_hdl;
1165 
1166 	/* lookup for container hash object */
1167 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
1168 	if (hash_obj == NULL) {
1169 		return (0);
1170 	}
1171 
1172 	/* points to section object list */
1173 	sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
1174 
1175 	/* traverse section object list */
1176 	while (sec_hash_obj != NULL) {
1177 
1178 		/* traverse segment hash object in the section */
1179 		while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
1180 			/* object handle of the segment hash object */
1181 			obj_hdl	=
1182 			    sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
1183 			free_segment_hash(obj_hdl, sec_hash_obj);
1184 		}
1185 
1186 		/* going to free section hash object, relink the hash object */
1187 		if (sec_hash_obj->prev == NULL) {
1188 			hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
1189 			    sec_hash_obj->next;
1190 			if (sec_hash_obj->next != NULL) {
1191 				sec_hash_obj->next->prev = NULL;
1192 			}
1193 		} else {
1194 			sec_hash_obj->prev->next = sec_hash_obj->next;
1195 			if (sec_hash_obj->next != NULL) {
1196 				sec_hash_obj->next->prev = sec_hash_obj->prev;
1197 			}
1198 		}
1199 
1200 		free(sec_hash_obj->u.sec_obj); /* free section hash object */
1201 
1202 		prev_hash = sec_hash_obj;
1203 
1204 		sec_hash_obj = sec_hash_obj->u.sec_obj->next;
1205 
1206 		free(prev_hash); /* free section hash */
1207 	}
1208 
1209 	/* free container hash object */
1210 	if (hash_obj->prev == NULL) {
1211 		hash_table[(hash_obj->obj_hdl % TABLE_SIZE)] =
1212 		    hash_obj->next;
1213 		if (hash_obj->next != NULL) {
1214 			hash_obj->next->prev = NULL;
1215 		}
1216 	} else {
1217 		hash_obj->prev->next = hash_obj->next;
1218 		if (hash_obj->next != NULL) {
1219 			hash_obj->next->prev = hash_obj->prev;
1220 		}
1221 	}
1222 
1223 	free(hash_obj->u.cont_obj);
1224 	free(hash_obj);
1225 
1226 	return (0);
1227 }
1228