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