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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <limits.h>
30 #include <alloca.h>
31 #include "fru_access_impl.h"
32 
33 #pragma init(initialize_fruaccess)	/* .init section */
34 
35 static	hash_obj_t	*hash_table[TABLE_SIZE];
36 
37 /*
38  * seeprom is the driver_name for the SEEPROM device drivers in excalibur
39  * Define the devfsadm command to load the seeprom drivers if open fails.
40  */
41 
42 static	char	devfsadm_cmd[] = "/usr/sbin/devfsadm -i seeprom";
43 
44 /* this routine initialize the hash table. */
45 
46 static void
initialize_fruaccess(void)47 initialize_fruaccess(void)
48 {
49 	int	count;
50 	for (count = 0; count < TABLE_SIZE; count++) {
51 		hash_table[count] = NULL;
52 	}
53 }
54 
55 /*
56  * called to lookup hash object for specified handle in the hash table.
57  *
58  */
59 
60 static hash_obj_t *
lookup_handle_object(handle_t handle,int object_type)61 lookup_handle_object(handle_t	handle, int object_type)
62 {
63 	handle_t	index_to_hash;
64 	hash_obj_t	*first_hash_obj;
65 	hash_obj_t	*next_hash_obj;
66 
67 	index_to_hash	= (handle % TABLE_SIZE);
68 
69 	first_hash_obj = hash_table[index_to_hash];
70 	for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
71 				next_hash_obj = next_hash_obj->next) {
72 		if ((handle == next_hash_obj->obj_hdl) &&
73 				(object_type == next_hash_obj->object_type)) {
74 				return (next_hash_obj);
75 		}
76 	}
77 	return (NULL);
78 }
79 
80 /* called to allocate container hash object */
81 
82 static hash_obj_t *
create_container_hash_object(void)83 create_container_hash_object(void)
84 {
85 	hash_obj_t		*hash_obj;
86 	container_obj_t		*cont_obj;
87 
88 	cont_obj	= malloc(sizeof (container_obj_t));
89 	if (cont_obj == NULL) {
90 		return (NULL);
91 	}
92 
93 	hash_obj = malloc(sizeof (hash_obj_t));
94 	if (hash_obj == NULL) {
95 		free(cont_obj);
96 		return (NULL);
97 	}
98 
99 	cont_obj->sec_obj_list	= NULL;
100 
101 	hash_obj->object_type	= CONTAINER_TYPE;
102 	hash_obj->u.cont_obj	= cont_obj;
103 	hash_obj->next	= NULL;
104 	hash_obj->prev	= NULL;
105 
106 	return (hash_obj);
107 }
108 
109 /* called to allocate section hash object */
110 
111 static hash_obj_t *
create_section_hash_object(void)112 create_section_hash_object(void)
113 {
114 	hash_obj_t		*hash_obj;
115 	section_obj_t		*sec_obj;
116 
117 	sec_obj	= malloc(sizeof (section_obj_t));
118 	if (sec_obj == NULL) {
119 		return (NULL);
120 	}
121 
122 	hash_obj = malloc(sizeof (hash_obj_t));
123 	if (hash_obj == NULL) {
124 		free(sec_obj);
125 		return (NULL);
126 	}
127 
128 	sec_obj->next		= NULL;
129 	sec_obj->seg_obj_list	= NULL;
130 
131 	hash_obj->u.sec_obj	= sec_obj;
132 	hash_obj->object_type	= SECTION_TYPE;
133 	hash_obj->next		= NULL;
134 	hash_obj->prev		= NULL;
135 
136 	return (hash_obj);
137 }
138 
139 /* called to allocate segment hash object */
140 
141 static hash_obj_t *
create_segment_hash_object(void)142 create_segment_hash_object(void)
143 {
144 	hash_obj_t		*hash_obj;
145 	segment_obj_t		*seg_obj;
146 
147 	seg_obj	= malloc(sizeof (segment_obj_t));
148 	if (seg_obj == NULL) {
149 		return (NULL);
150 	}
151 
152 	hash_obj = malloc(sizeof (hash_obj_t));
153 	if (hash_obj == NULL) {
154 		free(seg_obj);
155 		return (NULL);
156 	}
157 
158 	seg_obj->next		= NULL;
159 	seg_obj->pkt_obj_list	= NULL;
160 
161 	hash_obj->object_type	= SEGMENT_TYPE;
162 	hash_obj->u.seg_obj	= seg_obj;
163 	hash_obj->next		= NULL;
164 	hash_obj->prev		= NULL;
165 
166 	return (hash_obj);
167 }
168 
169 /* called to allocate packet hash object */
170 
171 static hash_obj_t *
create_packet_hash_object(void)172 create_packet_hash_object(void)
173 {
174 	hash_obj_t		*hash_obj;
175 	packet_obj_t		*pkt_obj;
176 
177 	pkt_obj	= malloc(sizeof (packet_obj_t));
178 	if (pkt_obj == NULL) {
179 		return (NULL);
180 	}
181 
182 	hash_obj	= malloc(sizeof (hash_obj_t));
183 	if (hash_obj == NULL) {
184 		free(pkt_obj);
185 		return (NULL);
186 	}
187 
188 	pkt_obj->next		= NULL;
189 
190 	hash_obj->object_type	= PACKET_TYPE;
191 	hash_obj->u.pkt_obj	= pkt_obj;
192 	hash_obj->next		= NULL;
193 	hash_obj->prev		= NULL;
194 
195 	return (hash_obj);
196 }
197 
198 /* called to add allocated hash object into the hash table */
199 
200 static void
add_hashobject_to_hashtable(hash_obj_t * hash_obj)201 add_hashobject_to_hashtable(hash_obj_t *hash_obj)
202 {
203 	handle_t		index_to_hash;
204 	static	uint64_t	handle_count	= 0;
205 
206 	hash_obj->obj_hdl = ++handle_count;	/* store the handle */
207 
208 	/* where to add ? */
209 	index_to_hash	= ((hash_obj->obj_hdl) % TABLE_SIZE);
210 
211 	hash_obj->next	= hash_table[index_to_hash];
212 	hash_table[index_to_hash] = hash_obj;	/* hash obj. added */
213 
214 	if (hash_obj->next != NULL) {
215 		hash_obj->next->prev = hash_obj;
216 	}
217 }
218 
219 /* called to add section object list into the section list */
220 
221 static void
add_to_sec_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)222 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
223 {
224 	hash_obj_t	*next_hash;
225 
226 	child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
227 	if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
228 		parent_obj->u.cont_obj->sec_obj_list = child_obj;
229 		return;
230 	}
231 
232 	for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
233 			next_hash->u.sec_obj->next != NULL;
234 			next_hash = next_hash->u.sec_obj->next) {
235 		;
236 	}
237 
238 	next_hash->u.sec_obj->next	= child_obj;
239 }
240 
241 /* called to add segment object list into segment list */
242 
243 static void
add_to_seg_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)244 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
245 {
246 	hash_obj_t	*next_hash;
247 
248 	child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
249 	if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
250 		parent_obj->u.sec_obj->seg_obj_list = child_obj;
251 		return;
252 	}
253 
254 	for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
255 			next_hash->u.seg_obj->next != NULL;
256 			next_hash = next_hash->u.seg_obj->next) {
257 		;
258 	}
259 
260 	next_hash->u.seg_obj->next	= child_obj;
261 }
262 
263 /* called to add packet object list into packet list */
264 
265 static void
add_to_pkt_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)266 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
267 {
268 	hash_obj_t	*next_hash;
269 
270 	/* add the packet object in the end of list */
271 	child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;
272 
273 	if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
274 		parent_obj->u.seg_obj->pkt_obj_list = child_obj;
275 		return;
276 	}
277 
278 	for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
279 			next_hash->u.pkt_obj->next != NULL;
280 			next_hash = next_hash->u.pkt_obj->next) {
281 			;
282 	}
283 
284 	next_hash->u.pkt_obj->next = child_obj;
285 }
286 
287 static void
copy_segment_layout(segment_t * seghdr,void * layout)288 copy_segment_layout(segment_t	*seghdr, void	*layout)
289 {
290 	segment_layout_t	*seg_layout;
291 
292 	seg_layout	= (segment_layout_t *)layout;
293 	(void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
294 	seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
295 	seghdr->offset	= seg_layout->offset;
296 	seghdr->length	= seg_layout->length;
297 }
298 
299 static hash_obj_t *
get_container_hash_object(int object_type,handle_t handle)300 get_container_hash_object(int	object_type, handle_t	handle)
301 {
302 	hash_obj_t	*hash_obj;
303 
304 	switch (object_type) {
305 	case	CONTAINER_TYPE	:
306 		break;
307 	case	SECTION_TYPE	:
308 		hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
309 		if (hash_obj == NULL) {
310 			return (NULL);
311 		}
312 		break;
313 	case	SEGMENT_TYPE	:
314 		hash_obj = lookup_handle_object(handle, SECTION_TYPE);
315 		if (hash_obj == NULL) {
316 			return (NULL);
317 		}
318 		hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
319 							CONTAINER_TYPE);
320 		break;
321 	case	PACKET_TYPE	:
322 		break;
323 	default	:
324 		return (NULL);
325 	}
326 	return (hash_obj);
327 }
328 
329 
330 static void
sort_offsettbl(int segcnt,seg_info_t * offset_tbl)331 sort_offsettbl(int	segcnt, seg_info_t	*offset_tbl)
332 {
333 	int		cntx;
334 	int		cnty;
335 	seg_info_t	tmp;
336 
337 	for (cntx = 0; cntx < segcnt+2; cntx++) {
338 		for (cnty = cntx+1; cnty < segcnt + 2; cnty++) {
339 			if (offset_tbl[cntx].offset >
340 					offset_tbl[cnty].offset) {
341 				(void) memcpy(&tmp, &offset_tbl[cnty],
342 						sizeof (seg_info_t));
343 				(void) memcpy(&offset_tbl[cnty],
344 				&offset_tbl[cntx], sizeof (seg_info_t));
345 
346 				(void) memcpy(&offset_tbl[cntx], &tmp,
347 						sizeof (seg_info_t));
348 			}
349 		}
350 	}
351 }
352 
353 /*
354  * Description : move_segment_data() reads the segment data and writes it
355  *      back to the new segment offset.
356  */
357 
358 static void
move_segment_data(void * seghdr,int newoffset,container_hdl_t contfd)359 move_segment_data(void *seghdr, int newoffset, container_hdl_t contfd)
360 {
361 	int			ret;
362 	char			*buffer;
363 	segment_layout_t	*segment;
364 
365 	segment	= (segment_layout_t *)seghdr;
366 
367 	buffer = alloca(segment->length);
368 	if (buffer == NULL) {
369 		return;
370 	}
371 
372 	ret = pread(contfd, buffer,
373 			segment->length, segment->offset);
374 	if (ret != segment->length) {
375 		return;
376 	}
377 
378 	segment->offset = newoffset;
379 
380 	ret = pwrite(contfd, buffer, segment->length, segment->offset);
381 	if (ret != segment->length) {
382 		return;
383 	}
384 }
385 
386 /*
387  * Description : pack_segment_data() moves the segment data if there is
388  *              a hole between two segments.
389  */
390 
391 static void
pack_segment_data(char * seghdr,int segcnt,container_hdl_t contfd,seg_info_t * offset_tbl)392 pack_segment_data(char *seghdr, int segcnt, container_hdl_t contfd,
393 						seg_info_t *offset_tbl)
394 {
395 	int	cnt;
396 	int	diff;
397 	int	newoffset;
398 
399 	for (cnt = segcnt + 1; cnt > 0; cnt--) {
400 		if (!offset_tbl[cnt - 1].fixed) {
401 			if (offset_tbl[cnt].offset
402 				- (offset_tbl[cnt -1 ].offset
403 					+ offset_tbl[cnt - 1].length) > 0) {
404 
405 				diff = offset_tbl[cnt].offset -
406 					(offset_tbl[cnt - 1].offset
407 					+ offset_tbl[cnt - 1].length);
408 				newoffset = offset_tbl[cnt - 1].offset
409 								+ diff;
410 
411 				move_segment_data(seghdr, newoffset,
412 								contfd);
413 
414 				offset_tbl[cnt - 1].offset = newoffset;
415 
416 				sort_offsettbl(segcnt, offset_tbl);
417 			}
418 		}
419 	}
420 }
421 
422 /*
423  * Description : build_offset_tbl() builds the offset table by reading all the
424  *              segment header. it makes two more entry into the table one for
425  *              section size and another with start of the section after the
426  *              segment header.
427  */
428 
429 static int
build_offset_tbl(void * seghdr,int segcnt,int secsize,seg_info_t * offset_tbl)430 build_offset_tbl(void   *seghdr, int segcnt, int secsize,
431 						seg_info_t *offset_tbl)
432 {
433 	int			cnt;
434 	fru_segdesc_t		segdesc;
435 	segment_layout_t	*segment;
436 
437 	for (cnt = 0; cnt < segcnt; cnt++) {
438 		segment	= (segment_layout_t *)(seghdr) + cnt;
439 
440 		(void) memcpy(&segdesc, &segment->descriptor,
441 						sizeof (uint32_t));
442 		offset_tbl[cnt].segnum = cnt;
443 		offset_tbl[cnt].offset = segment->offset;
444 		offset_tbl[cnt].length = segment->length;
445 		offset_tbl[cnt].fixed = segdesc.field.fixed;
446 	}
447 
448 	/* upper boundary of segment area (lower address bytes) */
449 	offset_tbl[cnt].segnum = -1;
450 	offset_tbl[cnt].offset = sizeof (section_layout_t) + ((cnt + 1)
451 					* sizeof (segment_layout_t));
452 
453 	offset_tbl[cnt].length = 0;
454 	offset_tbl[cnt].fixed  = 1;
455 	/* lower boundary of segment area (higher address bytes) */
456 
457 	offset_tbl[cnt+1].segnum = -1;
458 	offset_tbl[cnt+1].offset = secsize;
459 	offset_tbl[cnt+1].length = 0;
460 	offset_tbl[cnt+1].fixed = 1;
461 	return (0);
462 }
463 
464 static int
hole_discovery(int bytes,int segcnt,int * totsize,seg_info_t * offset_tbl)465 hole_discovery(int bytes, int segcnt, int *totsize, seg_info_t *offset_tbl)
466 {
467 	int cnt = 0;
468 
469 	*totsize = 0;
470 	for (cnt = segcnt + 1; cnt > 0; cnt--) {
471 		if (bytes <= offset_tbl[cnt].offset -
472 				(offset_tbl[cnt - 1].offset +
473 					offset_tbl[cnt - 1].length)) {
474 			return (offset_tbl[cnt].offset - bytes);
475 		}
476 
477 		*totsize += offset_tbl[cnt].offset -
478 				(offset_tbl[cnt - 1].offset +
479 					offset_tbl[cnt - 1].length);
480 	}
481 	return (0);
482 }
483 
484 
485 /*
486  * Description : segment_hdr_present() verify space for new segment header to
487  *              be added.
488  */
489 
490 static int
segment_hdr_present(int segoffset,int size,seg_info_t * offset_tbl)491 segment_hdr_present(int segoffset, int size, seg_info_t *offset_tbl)
492 {
493 	if ((segoffset + size) <= offset_tbl[0].offset)
494 		return (0);
495 	else
496 		return (-1);
497 }
498 
499 /*
500  * Description : find_offset() is called from fru_add_segment routine to find
501  *              a valid offset.
502  */
503 
504 static int
find_offset(char * seghdr,int segcnt,int secsize,int * sectionoffset,int segsize,int fix,container_hdl_t contfd)505 find_offset(char *seghdr, int segcnt, int secsize, int *sectionoffset,
506 		int segsize, int fix, container_hdl_t contfd)
507 {
508 	int		ret;
509 	int		newoffset;
510 	int		totsize = 0;
511 	seg_info_t	*offset_tbl;
512 
513 	if (segcnt == 0) {
514 		if (!fix) {	/* if not fixed segment */
515 			*sectionoffset = secsize - segsize;
516 		}
517 		return (0);
518 	}
519 
520 	/*
521 	 * two extra segment info structure are allocated for start of segment
522 	 * and other end of segment. first segment offset is first available
523 	 * space and length is 0. second segment offset is is segment length and
524 	 * offset is 0. build_offset_tbl() explains how upper boundary and lower
525 	 * boudary segment area are initialized in seg_info_t table.
526 	 */
527 
528 	offset_tbl    = malloc((segcnt + 2) * sizeof (seg_info_t));
529 	if (offset_tbl == NULL) {
530 		return (-1);
531 	}
532 
533 	/* read all the segment header to make offset table */
534 	ret = build_offset_tbl(seghdr, segcnt, secsize, offset_tbl);
535 	if (ret != 0) {
536 		free(offset_tbl);
537 		return (-1);
538 	}
539 
540 	/* sort the table */
541 	sort_offsettbl(segcnt, offset_tbl);
542 
543 	/* new segment header offset */
544 	newoffset = sizeof (section_layout_t) + segcnt *
545 						sizeof (segment_layout_t);
546 
547 	/* do? new segment header overlap any existing data */
548 	ret = segment_hdr_present(newoffset, sizeof (segment_layout_t),
549 								offset_tbl);
550 	if (ret != 0) { /* make room for new segment if possible */
551 
552 	/* look for hole in order to move segment data */
553 		if (offset_tbl[0].fixed == SEGMENT_FIXED) { /* fixed segment */
554 			free(offset_tbl);
555 			return (-1);
556 		}
557 
558 		newoffset = hole_discovery(offset_tbl[0].length,
559 					segcnt, &totsize, offset_tbl);
560 		if (newoffset != 0) { /* found new offset */
561 				/* now new offset */
562 			offset_tbl[0].offset = newoffset;
563 
564 			/* move the segment data */
565 			move_segment_data(seghdr, newoffset, contfd);
566 			/* again sort the offset table */
567 			sort_offsettbl(segcnt, offset_tbl);
568 		} else {
569 			/* pack the existing hole */
570 			if (totsize > offset_tbl[0].length) {
571 				pack_segment_data(seghdr, segcnt,
572 							contfd, offset_tbl);
573 			} else {
574 				free(offset_tbl);
575 				return (-1);
576 			}
577 		}
578 	}
579 
580 	totsize = 0;
581 	newoffset = hole_discovery(segsize, segcnt, &totsize, offset_tbl);
582 
583 	if (newoffset == 0) { /* No hole found */
584 		if (totsize >= segsize) {
585 			pack_segment_data(seghdr, segcnt, contfd,
586 								offset_tbl);
587 			newoffset = hole_discovery(segsize, segcnt,
588 							&totsize, offset_tbl);
589 			if (newoffset != 0) {
590 				*sectionoffset = newoffset;
591 				free(offset_tbl);
592 				return (0);
593 			}
594 		}
595 	} else {
596 		*sectionoffset = newoffset;
597 		free(offset_tbl);
598 		return (0);
599 	}
600 	free(offset_tbl);
601 	return (-1);
602 }
603 
604 static char *
tokenizer(char * buf,char * separator,char ** nextBuf,char * matched)605 tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
606 {
607 	int i = 0;
608 	int j = 0;
609 
610 	for (i = 0; buf[i] != '\0'; i++) {
611 		for (j = 0; j < strlen(separator); j++) {
612 			if (buf[i] == separator[j]) {
613 				buf[i] = '\0';
614 				*nextBuf = &(buf[i+1]);
615 				*matched = separator[j];
616 				return (buf);
617 			}
618 		}
619 	}
620 
621 	*nextBuf = buf;
622 	*matched = '\0';
623 	return (NULL);
624 }
625 
626 static int
get_container_info(const char * def_file,const char * cont_desc_str,container_info_t * cont_info)627 get_container_info(const char *def_file, const char *cont_desc_str,
628 						container_info_t *cont_info)
629 {
630 	char	*item;
631 	char	*token;
632 	char	*field;
633 	char	matched;
634 	char	buf[1024];
635 	int	foundIt = 0;
636 	FILE	*file = fopen(def_file, "r");
637 
638 	if (file == NULL)
639 		return (-1);
640 
641 	cont_info->num_sections = 0;
642 
643 	while (fgets(buf, sizeof (buf), file) != NULL) {
644 		/* ignore all comments */
645 		token = tokenizer(buf, "#", &field, &matched);
646 		/* find the names */
647 		token = tokenizer(buf, ":", &field, &matched);
648 		if (token != 0x00) {
649 			token = tokenizer(token, "|", &item, &matched);
650 			while (token != 0x00) {
651 				if (strcmp(token, cont_desc_str) == 0) {
652 					foundIt = 1;
653 					goto found;
654 				}
655 				token = tokenizer(item, "|", &item, &matched);
656 			}
657 			/* check the last remaining item */
658 			if ((item != 0x00) &&
659 					(strcmp(item, cont_desc_str) == 0)) {
660 				foundIt = 1;
661 				goto found;
662 			}
663 		}
664 	}
665 
666 found :
667 	if (foundIt == 1) {
668 		token = tokenizer(field, ":", &field, &matched);
669 		if (token == 0x00) {
670 			(void) fclose(file);
671 			return (-1);
672 		}
673 		cont_info->header_ver = (headerrev_t)atoi(token);
674 
675 		token = tokenizer(field, ":\n", &field, &matched);
676 		while (token != 0x00) {
677 			token = tokenizer(token, ",", &item, &matched);
678 			if (token == 0x00) {
679 				(void) fclose(file);
680 				return (-1);
681 			}
682 			if (atoi(token) == 1) {
683 				cont_info->section_info[cont_info->
684 				num_sections].description.field.read_only = 1;
685 			} else if (atoi(token) == 0) {
686 				cont_info->section_info[cont_info->
687 				num_sections].description.field.read_only = 0;
688 			} else {
689 				(void) fclose(file);
690 				return (-1);
691 			}
692 
693 			token = tokenizer(item, ",", &item, &matched);
694 			if (token == 0x00) {
695 				(void) fclose(file);
696 				return (-1);
697 			}
698 
699 			if (atoi(token) == 1) {
700 				cont_info->section_info[cont_info->
701 				num_sections].description.field.chk_type = 1;
702 			} else if (atoi(token) == 0) {
703 				cont_info->section_info[cont_info->
704 				num_sections].description.field.chk_type = 0;
705 			} else {
706 				(void) fclose(file);
707 				return (-1);
708 			}
709 
710 
711 			token = tokenizer(item, ",", &item, &matched);
712 			if (token == 0x00) {
713 				(void) fclose(file);
714 				return (-1);
715 			}
716 
717 			cont_info->section_info[cont_info->num_sections].
718 					address = atoi(token);
719 
720 
721 			if (item == '\0') {
722 				(void) fclose(file);
723 				return (-1);
724 			}
725 			cont_info->section_info[cont_info->num_sections].size =
726 								atoi(item);
727 			(cont_info->num_sections)++;
728 
729 			token = tokenizer(field, ":\n ", &field, &matched);
730 		}
731 	}
732 	(void) fclose(file);
733 	return (0);
734 }
735 
736 /*
737  * Description :fru_open_container() opens the container associated with a fru.
738  *              it's called by data plugin module before creating container
739  *              property.  it calls picltree library routine to get the
740  *              device path and driver binding name for the fru to get the
741  *              corresponding fru name that describe the fru layout.
742  *
743  * Arguments   :picl_hdl_t      fru
744  *              A handle for PICL tree node of class "fru" representing the
745  *              FRU with the container to open.
746  *
747  * Return      :
748  *              On Success, a Positive integer container handle. is returned
749  *              for use in subsequent fru operations;on error, 0 is returned
750  *              and "errno" is set appropriately.
751  */
752 
753 container_hdl_t
fru_open_container(picl_nodehdl_t fruhdl)754 fru_open_container(picl_nodehdl_t fruhdl)
755 {
756 	int			retval;
757 	int			count;
758 	char			*bname;
759 	char			devpath[PATH_MAX];
760 	hash_obj_t		*cont_hash_obj;
761 	hash_obj_t		*sec_hash_obj;
762 	picl_nodehdl_t		tmphdl;
763 	picl_prophdl_t		prophdl;
764 	ptree_propinfo_t	propinfo;
765 	container_info_t	cont_info;
766 
767 	/* Get property handle of _seeprom_source under fru node */
768 	retval = ptree_get_propval_by_name(fruhdl, PICL_REFPROP_SEEPROM_SRC,
769 						&tmphdl, sizeof (tmphdl));
770 	if (retval != PICL_SUCCESS) {
771 		return (NULL);
772 	}
773 
774 	/* Get the device path of the fru */
775 	retval = ptree_get_propval_by_name(tmphdl, PICL_PROP_DEVICEPATH,
776 							devpath, PATH_MAX);
777 	if (retval != PICL_SUCCESS) {
778 		return (NULL);
779 	}
780 
781 	retval = ptree_get_prop_by_name(tmphdl, PICL_PROP_BINDING_NAME,
782 								&prophdl);
783 	if (retval != PICL_SUCCESS) {
784 		return (NULL);
785 	}
786 
787 	retval = ptree_get_propinfo(prophdl, &propinfo);
788 	if (retval != PICL_SUCCESS) {
789 		return (NULL);
790 	}
791 
792 	bname = alloca(propinfo.piclinfo.size);
793 	if (bname == NULL) {
794 		return (NULL);
795 	}
796 
797 	/* get the driver binding name */
798 	retval = ptree_get_propval(prophdl, bname, propinfo.piclinfo.size);
799 	if (retval != PICL_SUCCESS) {
800 		return (NULL);
801 	}
802 
803 	cont_hash_obj	= create_container_hash_object();
804 	if (cont_hash_obj == NULL) {
805 		return (NULL);
806 	}
807 
808 	add_hashobject_to_hashtable(cont_hash_obj);
809 
810 	(void) strlcpy(cont_hash_obj->u.cont_obj->device_pathname, devpath,
811 							sizeof (devpath));
812 
813 	/* takes driver binding name as to get container information */
814 	retval = get_container_info(CONTAINER_CONF_FILE, bname, &cont_info);
815 	if (retval < 0) {
816 		return (NULL);
817 	}
818 
819 	cont_hash_obj->u.cont_obj->num_of_section =  cont_info.num_sections;
820 	cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
821 
822 	for (count = 0; count < cont_info.num_sections; count++) {
823 		sec_hash_obj = create_section_hash_object();
824 		if (sec_hash_obj == NULL) {
825 			return (NULL);
826 		}
827 
828 		add_hashobject_to_hashtable(sec_hash_obj);
829 
830 		sec_hash_obj->u.sec_obj->section.offset =
831 				cont_info.section_info[count].address;
832 
833 		sec_hash_obj->u.sec_obj->section.protection =
834 		cont_info.section_info[count].description.field.read_only;
835 
836 		sec_hash_obj->u.sec_obj->checksum_method =
837 		cont_info.section_info[count].description.field.chk_type;
838 
839 		sec_hash_obj->u.sec_obj->section.length =
840 					cont_info.section_info[count].size;
841 
842 		sec_hash_obj->u.sec_obj->section.version = cont_info.header_ver;
843 
844 		add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
845 	}
846 	return (cont_hash_obj->obj_hdl);
847 }
848 
849 static int
verify_header_crc8(headerrev_t head_ver,unsigned char * bytes,int length)850 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
851 {
852 	int		crc_offset = 0;
853 	unsigned char	orig_crc8 = 0;
854 	unsigned char	calc_crc8 = 0;
855 
856 	switch (head_ver) {
857 		case SECTION_HDR_VER:
858 			crc_offset = 4;
859 			break;
860 		default:
861 			errno = EINVAL;
862 			return (0);
863 	}
864 
865 	orig_crc8 = bytes[crc_offset];
866 	bytes[crc_offset] = 0x00; /* clear for calc */
867 	calc_crc8 = compute_crc8(bytes, length);
868 	bytes[crc_offset] = orig_crc8; /* restore */
869 
870 	return (orig_crc8 == calc_crc8);
871 }
872 
873 /*
874  * Description	:
875  *		fru_get_num_sections() returns number of sections in a
876  *		container. it calls get_container_index() to get the container
877  *		index number in the container list.
878  *
879  * Arguments	:
880  *		container_hdl_t	: container handle.
881  *
882  * Return	:
883  *		int
884  *		On success, returns number of sections in a container.
885  *
886  */
887 /*ARGSUSED*/
888 int
fru_get_num_sections(container_hdl_t container,door_cred_t * cred)889 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
890 {
891 	hash_obj_t		*hash_object;
892 
893 	hash_object	= lookup_handle_object(container, CONTAINER_TYPE);
894 	if (hash_object == NULL) {
895 		return (-1);
896 	}
897 
898 	return (hash_object->u.cont_obj->num_of_section);
899 }
900 
901 /*
902  * called from fru_get_sections()
903  */
904 
905 static void
get_section(int fd,hash_obj_t * sec_hash,section_t * section)906 get_section(int fd, hash_obj_t *sec_hash, section_t *section)
907 {
908 	int			retval;
909 	int			size;
910 	int			count;
911 	uint16_t		hdrver;
912 	hash_obj_t		*seg_hash;
913 	unsigned char		*buffer;
914 	section_obj_t		*sec_obj;
915 	section_layout_t	sec_hdr;
916 	segment_layout_t	*seg_hdr;
917 	segment_layout_t	*seg_buf;
918 
919 	sec_obj	= sec_hash->u.sec_obj;
920 	if (sec_obj == NULL) {
921 		return;
922 	}
923 
924 	/* populate section_t */
925 	section->handle = sec_hash->obj_hdl;
926 	section->offset = sec_obj->section.offset;
927 	section->length = sec_obj->section.length;
928 	section->protection = sec_obj->section.protection;
929 	section->version = sec_obj->section.version;
930 	sec_obj->num_of_segment	= 0;
931 
932 	/* read section header layout */
933 	retval = pread(fd, &sec_hdr, sizeof (sec_hdr),
934 						sec_obj->section.offset);
935 	if (retval != sizeof (sec_hdr)) {
936 		return;
937 	}
938 
939 	hdrver	= GET_SECTION_HDR_VERSION;
940 
941 	if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
942 					(hdrver != section->version)) {
943 		return;
944 	}
945 
946 	/* size = section layout + total sizeof segment header */
947 	size	= sizeof (sec_hdr) + ((sec_hdr.segmentcount)
948 					* sizeof (segment_layout_t));
949 
950 	buffer	= alloca(size);
951 	if (buffer == NULL) {
952 		return;
953 	}
954 
955 	/* segment header buffer */
956 	seg_buf = alloca(size - sizeof (sec_hdr));
957 	if (seg_buf == NULL) {
958 		return;
959 	}
960 
961 	/* read segment header */
962 	retval = pread(fd, seg_buf, size - sizeof (sec_hdr),
963 				sec_obj->section.offset + sizeof (sec_hdr));
964 	if (retval != (size - sizeof (sec_hdr))) {
965 		return;
966 	}
967 
968 	/* copy section header layout */
969 	(void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));
970 
971 	/* copy segment header layout */
972 	(void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
973 							sizeof (sec_hdr));
974 
975 	/* verify crc8 */
976 	retval = verify_header_crc8(hdrver, buffer, size);
977 	if (retval != TRUE) {
978 		return;
979 	}
980 
981 
982 	section->version = hdrver;
983 	sec_obj->section.version = hdrver;
984 
985 	seg_hdr	= (segment_layout_t *)seg_buf;
986 
987 	for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {
988 		seg_hash = create_segment_hash_object();
989 		if (seg_hash == NULL) {
990 			return;
991 		}
992 
993 		add_hashobject_to_hashtable(seg_hash);
994 
995 		copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
996 
997 		add_to_seg_object_list(sec_hash, seg_hash);
998 
999 		sec_obj->num_of_segment++;
1000 	}
1001 }
1002 
1003 
1004 static int
call_devfsadm(void)1005 call_devfsadm(void)
1006 {
1007 	char		*phys_path;
1008 	di_node_t	root_node;
1009 	di_node_t	prom_node;
1010 	di_node_t	f_node;
1011 
1012 	if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1013 		return (-1);
1014 	}
1015 
1016 	f_node = di_drv_first_node(PICL_CLASS_SEEPROM, root_node);
1017 	if (f_node != DI_NODE_NIL) {
1018 		phys_path = di_devfs_path(f_node);
1019 		if ((prom_node = di_init(phys_path, DINFOMINOR))
1020 							!= DI_NODE_NIL) {
1021 			di_fini(prom_node);
1022 			di_fini(root_node);
1023 			(void) pclose(popen(devfsadm_cmd, "r"));
1024 			return (0);
1025 		}
1026 	}
1027 	di_fini(root_node);
1028 	return (-1);
1029 }
1030 
1031 /*
1032  * Description	:
1033  *   		fru_get_sections() fills an array of section structures passed
1034  *		as an argument.
1035  *
1036  * Arguments	:
1037  *		container_hdl_t : container handle(device descriptor).
1038  *		section_t	: array of section structure.
1039  *		int		: maximum number of section in a container.
1040  *
1041  * Returns	:
1042  *   		int
1043  *     		On success,the number of section structures written is returned;
1044  *     		on error, -1 is returned and "errno" is set appropriately.
1045  *
1046  */
1047 
1048 /* ARGSUSED */
1049 int
fru_get_sections(container_hdl_t container,section_t * section,int maxsec,door_cred_t * cred)1050 fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
1051 							door_cred_t *cred)
1052 {
1053 	int		device_fd;
1054 	int		retrys = 1;
1055 	int		count;
1056 	hash_obj_t	*cont_object;
1057 	hash_obj_t	*sec_hash;
1058 
1059 	cont_object	= lookup_handle_object(container, CONTAINER_TYPE);
1060 	if (cont_object == NULL) {
1061 		return (-1);
1062 	}
1063 
1064 	if (cont_object->u.cont_obj->num_of_section > maxsec) {
1065 		return (-1);
1066 	}
1067 
1068 	sec_hash = cont_object->u.cont_obj->sec_obj_list;
1069 	if (sec_hash == NULL) {
1070 		return (-1);
1071 	}
1072 
1073 	do {
1074 		device_fd = open(cont_object->u.cont_obj->device_pathname,
1075 								O_RDWR);
1076 		if (device_fd >= 0) {
1077 			break;
1078 		}
1079 	} while ((retrys-- > 0) && (call_devfsadm() == 0));
1080 
1081 	if (device_fd < 0) {
1082 		return (-1);
1083 	}
1084 
1085 	for (count = 0; count < cont_object->u.cont_obj->num_of_section;
1086 						count++, section++) {
1087 		section->version = -1;
1088 		/* populate section_t */
1089 		get_section(device_fd, sec_hash, section);
1090 		sec_hash = sec_hash->u.sec_obj->next;
1091 	}
1092 
1093 	(void) close(device_fd);
1094 
1095 	return (count);
1096 }
1097 
1098 /*
1099  * Description	:
1100  * 		fru_get_num_segments() returns the current number of segments
1101  *		in a section.
1102  *
1103  * Arguments	:
1104  *		section_hdl_t : section header holding section information.
1105  *
1106  * Return	:
1107  * 		int
1108  *     		On success, the number of segments in the argument section is
1109  *     		returned; on error -1 is returned.
1110  */
1111 /*ARGSUSED*/
1112 int
fru_get_num_segments(section_hdl_t section,door_cred_t * cred)1113 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
1114 {
1115 	hash_obj_t	*sec_object;
1116 	section_obj_t	*sec_obj;
1117 
1118 	sec_object	= lookup_handle_object(section, SECTION_TYPE);
1119 	if (sec_object == NULL) {
1120 		return (-1);
1121 	}
1122 
1123 	sec_obj	= sec_object->u.sec_obj;
1124 	if (sec_obj == NULL) {
1125 		return (-1);
1126 	}
1127 
1128 	return (sec_obj->num_of_segment);
1129 }
1130 
1131 /*
1132  * Description	:
1133  *		fru_get_segments() fills an array of structures representing the
1134  *		segments in a section.
1135  *
1136  * Arguments	:
1137  *		section_hdl_t : holds section number.
1138  *		segment_t : on success will hold segment information.
1139  *		int	: maximum number of segment.
1140  *
1141  * Return	:
1142  *		int
1143  *		On success, the number of segment structures written is
1144  *		returned; on errno -1 is returned.
1145  */
1146 
1147 /* ARGSUSED */
1148 int
fru_get_segments(section_hdl_t section,segment_t * segment,int maxseg,door_cred_t * cred)1149 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
1150 						door_cred_t *cred)
1151 {
1152 	int		count;
1153 	hash_obj_t	*sec_object;
1154 	hash_obj_t	*seg_object;
1155 	section_obj_t	*sec_obj;
1156 
1157 	sec_object = lookup_handle_object(section, SECTION_TYPE);
1158 	if (sec_object == NULL) {
1159 		return (-1);
1160 	}
1161 
1162 	sec_obj	= sec_object->u.sec_obj;
1163 	if (sec_obj == NULL) {
1164 		return (-1);
1165 	}
1166 
1167 	if (sec_obj->num_of_segment > maxseg) {
1168 		return (-1);
1169 	}
1170 
1171 	seg_object	= sec_object->u.sec_obj->seg_obj_list;
1172 	if (seg_object == NULL) {
1173 		return (-1);
1174 	}
1175 
1176 	for (count = 0; count < sec_obj->num_of_segment; count++) {
1177 
1178 		/* populate segment_t */
1179 		segment->handle = seg_object->obj_hdl;
1180 		(void) memcpy(segment->name,
1181 			seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
1182 		segment->descriptor = seg_object->u.seg_obj->segment.descriptor;
1183 
1184 		segment->offset	= seg_object->u.seg_obj->segment.offset;
1185 		segment->length	= seg_object->u.seg_obj->segment.length;
1186 		seg_object = seg_object->u.seg_obj->next;
1187 		segment++;
1188 	}
1189 	return (0);
1190 }
1191 
1192 /*
1193  * Description	:
1194  *		fru_add_segment() adds a segment to a section.
1195  *
1196  * Arguments	:
1197  *		section_hdl_t section
1198  *		A handle for the section in which to add the segment.
1199  *
1200  *		segment_t *segment
1201  *		On entry, the "handle" component of "segment" is ignored and the
1202  *		remaining components specify the parameters of the segment to be
1203  *		added.  On return, the "handle" component is set to the handle
1204  *		for the added segment. The segment offset is mandatory for FIXED
1205  *		segments; otherwise, the offset is advisory.
1206  *
1207  * Return	:
1208  *		int
1209  *		On success, 0 is returned; on error -1 is returned.
1210  *
1211  */
1212 
1213 int
fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)1214 fru_add_segment(section_hdl_t section, segment_t *segment,
1215 				section_hdl_t *newsection, door_cred_t *cred)
1216 {
1217 	int		fd;
1218 	int		retval;
1219 	int		offset;
1220 	int		sec_size;
1221 	int		seg_cnt;
1222 	int		bufsize;
1223 	int		new_seg_offset;
1224 	int		new_seg_length;
1225 	int		fixed_segment;
1226 	char		trailer[]	= { 0x0c, 0x00, 0x00, 0x00, 0x00 };
1227 	hash_obj_t	*cont_hash;
1228 	hash_obj_t	*sec_hash;
1229 	hash_obj_t	*seg_hash;
1230 	fru_segdesc_t	*new_seg_desc;
1231 	unsigned char 	*crcbuf;
1232 	section_layout_t sec_layout;
1233 	segment_layout_t *seg_layout;
1234 	segment_layout_t *segment_buf;
1235 
1236 	/* check the effective uid of the client */
1237 	if (cred->dc_euid != 0) {
1238 		errno = EPERM;
1239 		return (-1);	/* not a root */
1240 	}
1241 
1242 	/* section hash */
1243 	sec_hash = lookup_handle_object(section, SECTION_TYPE);
1244 	if (sec_hash == NULL) {
1245 		return (-1);
1246 	}
1247 
1248 	/* check for read-only section */
1249 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1250 		errno = EPERM;
1251 		return (-1);
1252 	}
1253 
1254 	/* look for duplicate segment */
1255 	seg_hash = sec_hash->u.sec_obj->seg_obj_list;
1256 	while (seg_hash != NULL) {
1257 		if (strncmp(segment->name, seg_hash->u.seg_obj->segment.name,
1258 					SEG_NAME_LEN) == 0) {
1259 			errno = EEXIST;
1260 			return (-1); /* can't add duplicate segment */
1261 		}
1262 		seg_hash = seg_hash->u.seg_obj->next;
1263 	}
1264 
1265 	/* get the container hash */
1266 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1267 							CONTAINER_TYPE);
1268 	if (cont_hash == NULL) {
1269 		return (-1);
1270 	}
1271 
1272 	/* open the container */
1273 	fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1274 	if (fd < 0) {
1275 		return (-1);
1276 	}
1277 
1278 	/* section start here */
1279 	offset	= sec_hash->u.sec_obj->section.offset;
1280 
1281 	/* read section header layout */
1282 	retval = pread(fd, &sec_layout, sizeof (sec_layout), offset);
1283 	if (retval != sizeof (sec_layout)) {
1284 		(void) close(fd);
1285 		return (-1);
1286 	}
1287 
1288 	/* check for valid section header */
1289 	if (sec_layout.headertag != SECTION_HDR_TAG) {
1290 		/* write a new one */
1291 		sec_layout.headertag		= SECTION_HDR_TAG;
1292 		sec_layout.headerversion[0]	= SECTION_HDR_VER_BIT0;
1293 		sec_layout.headerversion[1]	= SECTION_HDR_VER_BIT1;
1294 		sec_layout.headerlength		= sizeof (sec_layout);
1295 		sec_layout.segmentcount		= 0;
1296 	}
1297 
1298 	/* section size */
1299 	sec_size	= sec_hash->u.sec_obj->section.length;
1300 
1301 	/* number of segment in the section */
1302 	seg_cnt	= sec_layout.segmentcount;
1303 
1304 	/* total sizeof segment + new segment */
1305 	bufsize	=	sizeof (segment_layout_t) * (seg_cnt + 1);
1306 	segment_buf = alloca(bufsize);
1307 	if (segment_buf == NULL) {
1308 		return (-1);
1309 	}
1310 
1311 	/* read entire segment header */
1312 	retval = pread(fd, segment_buf,  (bufsize - sizeof (segment_layout_t)),
1313 					offset + sizeof (section_layout_t));
1314 	if (retval != (bufsize - sizeof (segment_layout_t))) {
1315 		(void) close(fd);
1316 		return (-1);
1317 	}
1318 
1319 	new_seg_offset	= segment->offset; /* new segment offset */
1320 	new_seg_length	= segment->length; /* new segment length */
1321 
1322 	new_seg_desc	= (fru_segdesc_t *)&segment->descriptor;
1323 
1324 	fixed_segment	= new_seg_desc->field.fixed;
1325 
1326 	/* get new offset for new segment to be addedd */
1327 	retval = find_offset((char *)segment_buf, seg_cnt, sec_size,
1328 			&new_seg_offset, new_seg_length, fixed_segment, fd);
1329 
1330 	if (retval != 0)	{
1331 		(void) close(fd);
1332 		errno = EAGAIN;
1333 		return (-1);
1334 	}
1335 
1336 	/* copy new segment data in segment layout */
1337 	seg_layout	= (segment_layout_t *)(segment_buf + seg_cnt);
1338 	(void) memcpy(&seg_layout->name, segment->name, SEG_NAME_LEN);
1339 	(void) memcpy(seg_layout->descriptor, &segment->descriptor,
1340 						sizeof (uint32_t));
1341 	seg_layout->length	= segment->length;
1342 	seg_layout->offset	= new_seg_offset; /* new segment offset */
1343 
1344 	sec_layout.segmentcount += 1;
1345 
1346 	crcbuf	= alloca(sizeof (section_layout_t) + bufsize);
1347 	if (crcbuf == NULL) {
1348 		(void) close(fd);
1349 		return (-1);
1350 	}
1351 
1352 	sec_layout.headercrc8 = 0;
1353 	sec_layout.headerlength += sizeof (segment_layout_t);
1354 
1355 	(void) memcpy(crcbuf, (char *)&sec_layout, sizeof (section_layout_t));
1356 	(void) memcpy(crcbuf + sizeof (section_layout_t), segment_buf, bufsize);
1357 
1358 	sec_layout.headercrc8 = compute_crc8(crcbuf, bufsize +
1359 						sizeof (section_layout_t));
1360 
1361 	/* write section header */
1362 	retval = pwrite(fd, &sec_layout, sizeof (section_layout_t), offset);
1363 	if (retval != sizeof (section_layout_t)) {
1364 		(void) close(fd);
1365 		return (-1);
1366 	}
1367 
1368 	/* write segment header */
1369 	retval = pwrite(fd, segment_buf, bufsize, offset +
1370 						sizeof (section_layout_t));
1371 	if (retval != bufsize) {
1372 		(void) close(fd);
1373 		return (-1);
1374 	}
1375 
1376 	/* write segment trailer */
1377 	retval = pwrite(fd, &trailer, sizeof (trailer), new_seg_offset);
1378 	if (retval != sizeof (trailer)) {
1379 		(void) close(fd);
1380 		return (-1);
1381 	}
1382 
1383 	(void) close(fd);
1384 
1385 	/* create new segment hash object */
1386 	seg_hash	= create_segment_hash_object();
1387 	if (seg_hash == NULL) {
1388 		return (-1);
1389 	}
1390 
1391 	add_hashobject_to_hashtable(seg_hash);
1392 
1393 	copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_layout);
1394 
1395 	add_to_seg_object_list(sec_hash, seg_hash);
1396 
1397 	sec_hash->u.sec_obj->num_of_segment += 1;
1398 	seg_hash->u.seg_obj->trailer_offset = new_seg_offset;
1399 	*newsection	= section; /* return the new section handle */
1400 	return (0);
1401 }
1402 
1403 static void
free_pkt_object_list(hash_obj_t * hash_obj)1404 free_pkt_object_list(hash_obj_t	*hash_obj)
1405 {
1406 	hash_obj_t	*next_obj;
1407 	hash_obj_t	*free_obj;
1408 
1409 	next_obj = hash_obj->u.seg_obj->pkt_obj_list;
1410 	while (next_obj != NULL) {
1411 		free_obj = next_obj;
1412 		next_obj = next_obj->u.pkt_obj->next;
1413 		/* if prev is NULL it's the first object in the list */
1414 		if (free_obj->prev == NULL) {
1415 			hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
1416 					free_obj->next;
1417 			if (free_obj->next != NULL) {
1418 				free_obj->next->prev = free_obj->prev;
1419 			}
1420 		} else {
1421 			free_obj->prev->next = free_obj->next;
1422 			if (free_obj->next != NULL) {
1423 				free_obj->next->prev = free_obj->prev;
1424 			}
1425 		}
1426 		free(free_obj->u.pkt_obj);
1427 		free(free_obj);
1428 	}
1429 
1430 	hash_obj->u.seg_obj->pkt_obj_list = NULL;
1431 }
1432 
1433 static void
free_segment_hash(handle_t handle,hash_obj_t * sec_hash)1434 free_segment_hash(handle_t	handle, hash_obj_t	*sec_hash)
1435 {
1436 	hash_obj_t	*seg_hash;
1437 	hash_obj_t	*next_hash;
1438 
1439 	seg_hash	= sec_hash->u.sec_obj->seg_obj_list;
1440 	if (seg_hash == NULL) {
1441 		return;
1442 	}
1443 
1444 	if (seg_hash->obj_hdl == handle) {
1445 		sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
1446 	} else {
1447 		while (seg_hash->obj_hdl != handle) {
1448 			next_hash	= seg_hash;
1449 			seg_hash = seg_hash->u.seg_obj->next;
1450 			if (seg_hash == NULL) {
1451 				return;
1452 			}
1453 		}
1454 		next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
1455 	}
1456 
1457 	if (seg_hash->prev == NULL) {
1458 		hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
1459 		if (seg_hash->next != NULL) {
1460 			seg_hash->next->prev = NULL;
1461 		}
1462 	} else {
1463 		seg_hash->prev->next = seg_hash->next;
1464 		if (seg_hash->next != NULL) {
1465 			seg_hash->next->prev = seg_hash->prev;
1466 		}
1467 	}
1468 
1469 	free_pkt_object_list(seg_hash);
1470 	free(seg_hash->u.seg_obj);
1471 	free(seg_hash);
1472 }
1473 
1474 /*
1475  * Description	:
1476  *		fru_delete_segment() deletes a segment from a section; the
1477  *		associated container data is not altered.
1478  *
1479  * Arguments	: segment_hdl_t	segment handle.
1480  *		  section_hdl_t	new section handle.
1481  *
1482  * Return	:
1483  *		int
1484  *		On success, 0 returned; On error -1 is returned.
1485  */
1486 
1487 int
fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)1488 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
1489 							door_cred_t *cred)
1490 {
1491 	int			num_of_seg;
1492 	int			bufsize;
1493 	int			count;
1494 	int			retval;
1495 	int			fd;
1496 	int			segnum;
1497 	hash_obj_t		*seg_hash;
1498 	hash_obj_t		*sec_hash;
1499 	hash_obj_t		*cont_hash;
1500 	hash_obj_t		*tmp_hash;
1501 	unsigned char		*buffer;
1502 	fru_segdesc_t		*desc;
1503 	segment_layout_t	*seg_buf;
1504 	section_layout_t	*sec_layout;
1505 	segment_layout_t	*seg_layout;
1506 	segment_layout_t	*next_layout;
1507 
1508 	/* check the effective uid of the client */
1509 	if (cred->dc_euid != 0) {
1510 		errno = EPERM;
1511 		return (-1);	/* not a root */
1512 	}
1513 
1514 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1515 	if (seg_hash == NULL) {
1516 		return (-1);
1517 	}
1518 
1519 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
1520 	if (!(desc->field.field_perm & SEGMENT_DELETE)) {
1521 		errno = EPERM;
1522 		return (-1); /* can't delete this segment */
1523 	}
1524 
1525 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1526 						SECTION_TYPE);
1527 	if (sec_hash == NULL) {
1528 		return (-1);
1529 	}
1530 
1531 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
1532 		errno = EPERM;
1533 		return (-1);
1534 	}
1535 
1536 	num_of_seg	= sec_hash->u.sec_obj->num_of_segment;
1537 
1538 	bufsize	= (sizeof (segment_layout_t) * num_of_seg);
1539 
1540 	seg_buf	= alloca(bufsize);
1541 	if (seg_buf == NULL) {
1542 		return (-1);
1543 	}
1544 
1545 	segnum	= 0;
1546 	for (tmp_hash = sec_hash->u.sec_obj->seg_obj_list; tmp_hash != NULL;
1547 			tmp_hash = tmp_hash->u.seg_obj->next) {
1548 		if (tmp_hash->obj_hdl == segment) {
1549 			break;
1550 		}
1551 		segnum++;
1552 	}
1553 
1554 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1555 						CONTAINER_TYPE);
1556 	if (cont_hash == NULL) {
1557 		return (-1);
1558 	}
1559 
1560 	fd  = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1561 	if (fd < 0) {
1562 		return (-1);
1563 	}
1564 
1565 	sec_layout	= alloca(sizeof (section_layout_t));
1566 	if (sec_layout == NULL) {
1567 		(void) close(fd);
1568 		return (-1);
1569 	}
1570 
1571 	/* read section layout header */
1572 	retval = pread(fd, sec_layout, sizeof (section_layout_t),
1573 					sec_hash->u.sec_obj->section.offset);
1574 	if (retval != sizeof (section_layout_t)) {
1575 		(void) close(fd);
1576 		return (-1);
1577 	}
1578 
1579 	/* read segment header layout */
1580 	retval = pread(fd, seg_buf, bufsize,
1581 			sec_hash->u.sec_obj->section.offset +
1582 						sizeof (section_layout_t));
1583 	if (retval != bufsize) {
1584 		(void) close(fd);
1585 		return (-1);
1586 	}
1587 
1588 	seg_layout = (segment_layout_t *)(seg_buf + segnum);
1589 	next_layout	= seg_layout;
1590 	for (count = segnum; count < sec_hash->u.sec_obj->num_of_segment-1;
1591 								count++) {
1592 		next_layout++;
1593 		(void) memcpy(seg_layout, next_layout,
1594 						sizeof (segment_layout_t));
1595 		seg_layout++;
1596 	}
1597 
1598 	(void) memset(seg_layout, '\0', sizeof (segment_layout_t));
1599 
1600 	sec_layout->headercrc8 = 0;
1601 
1602 	sec_layout->headerlength -= sizeof (segment_layout_t);
1603 	sec_layout->segmentcount -= 1;
1604 
1605 	buffer = alloca(sec_layout->headerlength);
1606 	if (buffer == NULL) {
1607 		(void) close(fd);
1608 		return (-1);
1609 	}
1610 
1611 	(void) memcpy(buffer, sec_layout, sizeof (section_layout_t));
1612 	(void) memcpy(buffer + sizeof (section_layout_t), seg_buf, bufsize
1613 						- sizeof (segment_layout_t));
1614 	sec_layout->headercrc8 = compute_crc8(buffer,
1615 						sec_layout->headerlength);
1616 
1617 	/* write section header with update crc8 and header length */
1618 	retval = pwrite(fd, sec_layout, sizeof (section_layout_t),
1619 					sec_hash->u.sec_obj->section.offset);
1620 	if (retval != sizeof (section_layout_t)) {
1621 		(void) close(fd);
1622 		return (-1);
1623 	}
1624 
1625 	/* write the update segment header */
1626 	retval = pwrite(fd, seg_buf, bufsize,
1627 		sec_hash->u.sec_obj->section.offset +
1628 						sizeof (section_layout_t));
1629 	(void) close(fd);
1630 	if (retval != bufsize) {
1631 		return (-1);
1632 	}
1633 
1634 	free_segment_hash(segment, sec_hash);
1635 
1636 	*newsection	= sec_hash->obj_hdl;
1637 	sec_hash->u.sec_obj->num_of_segment = sec_layout->segmentcount;
1638 
1639 	return (0);
1640 }
1641 
1642 /*
1643  * Description	:
1644  * 		fru_read_segment() reads the raw contents of a segment.
1645  *
1646  * Arguments	: segment_hdl_t : segment handle.
1647  *		 void *	: buffer containing segment data when function returns.
1648  *		size_t :number of bytes.
1649  *
1650  * Return	:
1651  * 		int
1652  *		On success, the number of bytes read is returned;
1653  *
1654  * Notes	:
1655  *		Segments containing packets can be read in structured fashion
1656  *		using the fru_get_packets() and fru_get_payload() primitives;the
1657  *		entire byte range of a segment can be read using
1658  *		fru_read_segment().
1659  */
1660 /*ARGSUSED*/
1661 ssize_t
fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)1662 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
1663 		door_cred_t *cred)
1664 {
1665 	int		fd;
1666 	int		retval;
1667 	hash_obj_t	*seg_hash;
1668 	hash_obj_t	*sec_hash;
1669 	hash_obj_t	*cont_hash;
1670 
1671 	/* segment hash object */
1672 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
1673 	if (seg_hash == NULL) {
1674 		return (-1);
1675 	}
1676 
1677 	/* section hash object */
1678 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1679 							SECTION_TYPE);
1680 	if (sec_hash == NULL) {
1681 		return (-1);
1682 	}
1683 
1684 	/* container hash object */
1685 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
1686 							CONTAINER_TYPE);
1687 	if (cont_hash == NULL) {
1688 		return (-1);
1689 	}
1690 
1691 	if (seg_hash->u.seg_obj->segment.length < nbytes) {
1692 		return (-1);
1693 	}
1694 
1695 	fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
1696 	if (fd < 0) {
1697 		return (-1);
1698 	}
1699 
1700 	retval = pread(fd, buffer, nbytes, seg_hash->u.seg_obj->segment.offset);
1701 	(void) close(fd);
1702 	if (retval != nbytes) {
1703 		return (-1);
1704 	}
1705 	return (nbytes);
1706 }
1707 
1708 /*
1709  * Description	:
1710  *		fru_write_segment() writes a raw segment.
1711  *
1712  * Arguments	: segment_hdl_t :segment handle.
1713  *		 const void * : data buffer.
1714  *		 size_t	: number of bytes.
1715  *		 segment_hdl_t : new segment handle.
1716  *
1717  * Returns	:
1718  *		int
1719  *		On success, the number of bytes written is returned
1720  *
1721  */
1722 /*ARGSUSED*/
1723 int
fru_write_segment(segment_hdl_t segment,const void * data,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)1724 fru_write_segment(segment_hdl_t segment, const void *data, size_t nbytes,
1725 				segment_hdl_t *newsegment, door_cred_t *cred)
1726 {
1727 	return (ENOTSUP);
1728 }
1729 
1730 
1731 static int
get_packet(int device_fd,void * buffer,int size,int offset)1732 get_packet(int device_fd, void *buffer, int size, int offset)
1733 {
1734 	int	retval;
1735 
1736 	retval = pread(device_fd, (char *)buffer, size, offset);
1737 	if (retval != -1) {
1738 		return (0);
1739 	}
1740 	return (-1);
1741 }
1742 
1743 /*
1744  * Description	:
1745  *		get_payload() populates a buffer with the packets payload
1746  *
1747  * Arguments	: hash_obj_t : packet.
1748  *                int  : device file descriptor
1749  *                uint8_t* : pointer to a pre allocated buffer
1750  *
1751  *
1752  * Return	:
1753  *		int
1754  *		On success, 0 is returned; on failure
1755  *		-1 returned.
1756  */
1757 int
get_payload(int device_fd,hash_obj_t * packet,uint8_t * payload)1758 get_payload(int device_fd, hash_obj_t *packet, uint8_t *payload)
1759 {
1760 	int		retval;
1761 	packet_obj_t	*packet_object;
1762 
1763 
1764 	packet_object = packet->u.pkt_obj;
1765 	if (packet_object == NULL) {
1766 		return (-1);
1767 	}
1768 
1769 	/* Get the data */
1770 	retval = pread(device_fd, payload, packet_object->paylen,
1771 			packet_object->payload_offset);
1772 	if (retval != packet_object->paylen) {
1773 	    free(payload);
1774 	    return (-1);
1775 	}
1776 
1777 	return (0);
1778 
1779 }
1780 
1781 
1782 static uint32_t
get_checksum_crc(int device_fd,hash_obj_t * seg_hash,int data_size)1783 get_checksum_crc(int device_fd, hash_obj_t	*seg_hash, int data_size)
1784 {
1785 	int		checksum;
1786 	int		offset = 0;
1787 	int		retval;
1788 	uint8_t		*payload;
1789 	uint32_t	crc;
1790 	hash_obj_t	*sec_hash;
1791 	hash_obj_t	*pkt_hash;
1792 	unsigned char	*buffer;
1793 
1794 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1795 							SECTION_TYPE);
1796 	if (sec_hash == NULL) {
1797 		return ((uint32_t)-1);
1798 	}
1799 
1800 	buffer = alloca(data_size);
1801 	if (buffer == NULL) {
1802 		return ((uint32_t)-1);
1803 	}
1804 
1805 	/* traverse the packet object list for all the tags and payload */
1806 	for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL;
1807 				pkt_hash = pkt_hash->u.pkt_obj->next) {
1808 		(void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
1809 					pkt_hash->u.pkt_obj->tag_size);
1810 		offset += pkt_hash->u.pkt_obj->tag_size;
1811 
1812 		/* read packet payload */
1813 		payload = malloc(pkt_hash->u.pkt_obj->paylen);
1814 		if (payload == NULL) {
1815 		    return ((uint32_t)-1);
1816 		}
1817 		retval = get_payload(device_fd, pkt_hash, payload);
1818 		if (retval == -1) {
1819 		    free(payload);
1820 		    return ((uint32_t)-1);
1821 		}
1822 		(void) memcpy(buffer + offset, payload,
1823 					pkt_hash->u.pkt_obj->paylen);
1824 		offset += pkt_hash->u.pkt_obj->paylen;
1825 		free(payload);
1826 	}
1827 
1828 	checksum	= sec_hash->u.sec_obj->checksum_method;
1829 
1830 	if (checksum == CRC32_SECTION) { /* read-only section */
1831 		crc = compute_crc32(buffer, data_size);
1832 	} else {		/* read/write section */
1833 		crc = compute_checksum32(buffer, data_size);
1834 	}
1835 	return (crc);	/* computed crc */
1836 }
1837 
1838 static int
get_packets(hash_obj_t * seg_hash,int device_fd,int offset,int length)1839 get_packets(hash_obj_t *seg_hash, int device_fd, int offset, int length)
1840 {
1841 	int		tag_size;
1842 	int		paylen;
1843 	int		retval;
1844 	int		seg_limit = 0;
1845 	int		pktcnt	= 0;
1846 	char		*data;
1847 	uint32_t	crc;
1848 	uint32_t	origcrc;
1849 	fru_tag_t	tag;
1850 	hash_obj_t	*pkt_hash_obj;
1851 	fru_segdesc_t	*segdesc;
1852 	fru_tagtype_t	tagtype;
1853 
1854 	retval = get_packet(device_fd, &tag, sizeof (fru_tag_t), offset);
1855 	if (retval == -1) {
1856 		return (-1);
1857 	}
1858 
1859 	seg_hash->u.seg_obj->trailer_offset = offset;
1860 
1861 	data	= (char *)&tag;
1862 	while (data[0] != SEG_TRAILER_TAG) {
1863 		tagtype	= get_tag_type(&tag); /* verify tag type */
1864 		if (tagtype == -1) {
1865 			return (-1);
1866 		}
1867 
1868 		tag_size = get_tag_size(tagtype);
1869 		if (tag_size == -1) {
1870 			return (-1);
1871 		}
1872 
1873 		seg_limit += tag_size;
1874 		if (seg_limit > length) {
1875 			return (-1);
1876 		}
1877 
1878 		paylen = get_payload_length((void *)&tag);
1879 		if (paylen == -1) {
1880 			return (-1);
1881 		}
1882 
1883 		seg_limit += paylen;
1884 		if (seg_limit > length) {
1885 			return (-1);
1886 		}
1887 
1888 		pkt_hash_obj = create_packet_hash_object();
1889 		if (pkt_hash_obj == NULL) {
1890 			return (-1);
1891 		}
1892 
1893 		offset += tag_size;
1894 
1895 		/* don't change this */
1896 		pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
1897 		(void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
1898 		pkt_hash_obj->u.pkt_obj->paylen = paylen;
1899 		pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
1900 		pkt_hash_obj->u.pkt_obj->payload_offset = offset;
1901 
1902 		offset += paylen;
1903 
1904 		add_hashobject_to_hashtable(pkt_hash_obj);
1905 		add_to_pkt_object_list(seg_hash, pkt_hash_obj);
1906 
1907 		pktcnt++;
1908 
1909 		retval = get_packet(device_fd, &tag, sizeof (fru_tag_t),
1910 									offset);
1911 		if (retval == -1) {
1912 			return (retval);
1913 		}
1914 
1915 		data	= (char *)&tag;
1916 	}
1917 
1918 	segdesc	= (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
1919 
1920 	seg_hash->u.seg_obj->trailer_offset = offset;
1921 
1922 	if (!segdesc->field.ignore_checksum)  {
1923 		crc = get_checksum_crc(device_fd, seg_hash, seg_limit);
1924 		offset	= seg_hash->u.seg_obj->segment.offset;
1925 
1926 		retval = pread(device_fd, &origcrc, sizeof (origcrc),
1927 						offset + seg_limit + 1);
1928 		if (retval != sizeof (origcrc)) {
1929 			return (-1);
1930 		}
1931 
1932 		if (origcrc != crc) {
1933 			seg_hash->u.seg_obj->trailer_offset = offset;
1934 			return (-1);
1935 		}
1936 	}
1937 
1938 	return (pktcnt);
1939 }
1940 
1941 /*
1942  * Description	:
1943  *		fru_get_num_packets() returns the current number of packets
1944  *		in a segment.
1945  *
1946  * Arguments	: segment_hdl_t : segment handle.
1947  *
1948  * Return	:
1949  *		int
1950  *		On success, the number of packets is returned;
1951  *		-1 on failure.
1952  */
1953 /*ARGSUSED*/
1954 int
fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)1955 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
1956 {
1957 	int		device_fd;
1958 	int		pktcnt;
1959 	int		length;
1960 	uint16_t	offset;
1961 	hash_obj_t	*cont_hash_obj;
1962 	hash_obj_t	*seg_hash;
1963 	fru_segdesc_t	*segdesc;
1964 	segment_obj_t	*segment_object;
1965 
1966 	seg_hash	= lookup_handle_object(segment, SEGMENT_TYPE);
1967 	if (seg_hash == NULL) {
1968 		return (-1);
1969 	}
1970 
1971 	segment_object	= seg_hash->u.seg_obj;
1972 	if (segment_object == NULL) {
1973 		return (-1);
1974 	}
1975 
1976 
1977 	segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
1978 	if (segdesc->field.opaque) {
1979 		return (0);
1980 	}
1981 
1982 	offset = segment_object->segment.offset;
1983 	length = segment_object->segment.length;
1984 
1985 	cont_hash_obj	= get_container_hash_object(SEGMENT_TYPE,
1986 						segment_object->section_hdl);
1987 
1988 	if (cont_hash_obj == NULL) {
1989 		return (-1);
1990 	}
1991 
1992 	if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
1993 		return (segment_object->num_of_packets);
1994 	}
1995 
1996 	segment_object->num_of_packets = 0;
1997 	device_fd = open(cont_hash_obj->u.cont_obj->device_pathname,
1998 								O_RDWR);
1999 	if (device_fd < 0) {
2000 		return (-1);
2001 	}
2002 
2003 	pktcnt = get_packets(seg_hash, device_fd, offset,
2004 							length);
2005 	if (pktcnt == -1) {
2006 		free_pkt_object_list(seg_hash);
2007 		seg_hash->u.seg_obj->pkt_obj_list = NULL;
2008 	}
2009 
2010 	segment_object->num_of_packets = pktcnt;
2011 	(void) close(device_fd);
2012 
2013 	return (segment_object->num_of_packets);
2014 }
2015 
2016 
2017 /*
2018  * Description	:
2019  *		fru_get_packets() fills an array of structures representing the
2020  *		packets in a segment.
2021  *
2022  * Arguments	: segment_hdl_t : segment handle.
2023  *		packet_t	: packet buffer.
2024  *		int	: maximum number of packets.
2025  *
2026  * Return	:
2027  *		int
2028  *		On success, the number of packet structures written is returned;
2029  *		On failure -1 is returned;
2030  *
2031  */
2032 /*ARGSUSED*/
2033 int
fru_get_packets(segment_hdl_t segment,packet_t * packet,int maxpackets,door_cred_t * cred)2034 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
2035 							door_cred_t *cred)
2036 {
2037 	int		count;
2038 	hash_obj_t	*seg_hash_obj;
2039 	hash_obj_t	*pkt_hash_obj;
2040 
2041 	/* segment hash object */
2042 	seg_hash_obj	= lookup_handle_object(segment, SEGMENT_TYPE);
2043 	if (seg_hash_obj == NULL) {
2044 		return (-1);
2045 	}
2046 
2047 	if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
2048 		return (-1);
2049 	}
2050 
2051 	pkt_hash_obj	= seg_hash_obj->u.seg_obj->pkt_obj_list;
2052 	if (pkt_hash_obj == NULL) {
2053 		return (-1);
2054 	}
2055 
2056 	for (count = 0; count < maxpackets; count++, packet++) {
2057 		packet->handle	= pkt_hash_obj->obj_hdl;
2058 		packet->tag = 0;
2059 		(void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
2060 				pkt_hash_obj->u.pkt_obj->tag_size);
2061 		pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
2062 	}
2063 
2064 	return (0);
2065 }
2066 
2067 /*
2068  * Description	:
2069  *		fru_get_payload() copies the contents of a packet's payload.
2070  *
2071  * Arguments	: packet_hdl_t : packet handle.
2072  *		void *	: payload buffer.
2073  *		size_t	: sizeof the buffer.
2074  *
2075  * Return	:
2076  *    		int
2077  *     		On success, the number of bytes copied is returned; On error
2078  *		-1 returned.
2079  */
2080 /*ARGSUSED*/
2081 ssize_t
fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)2082 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
2083 						door_cred_t *cred)
2084 {
2085 	int		retval;
2086 	int		device_fd;
2087 	uint8_t		*payload;
2088 	hash_obj_t	*packet_hash_obj;
2089 	hash_obj_t	*segment_hash_obj;
2090 	hash_obj_t	*container_hash_obj;
2091 
2092 	/* packet hash object */
2093 	packet_hash_obj	= lookup_handle_object(packet, PACKET_TYPE);
2094 	if (packet_hash_obj == NULL) {
2095 		return (-1);
2096 	}
2097 
2098 	payload = malloc(packet_hash_obj->u.pkt_obj->paylen);
2099 	if (payload == NULL) {
2100 	    return (-1);
2101 	}
2102 
2103 	/* lookup the segment hash object */
2104 	segment_hash_obj =
2105 	    lookup_handle_object(packet_hash_obj->u.pkt_obj->segment_hdl,
2106 	    SEGMENT_TYPE);
2107 	if (segment_hash_obj == NULL) {
2108 	    free(payload);
2109 	    return (-1);
2110 	}
2111 
2112 	/* Get the container hash object to get the seeprom device path */
2113 	container_hash_obj	= get_container_hash_object(SEGMENT_TYPE,
2114 				    segment_hash_obj->u.seg_obj->section_hdl);
2115 	if (container_hash_obj == NULL) {
2116 	    free(payload);
2117 	    return (-1);
2118 	}
2119 
2120 	/* Open the seeprom device */
2121 	device_fd = open(container_hash_obj->u.cont_obj->device_pathname,
2122 								O_RDWR);
2123 	if (device_fd < 0) {
2124 	    free(payload);
2125 	    return (-1);
2126 	}
2127 
2128 
2129 	/* Call to get the payload  */
2130 	retval  = get_payload(device_fd, packet_hash_obj, payload);
2131 	if (retval == -1) {
2132 	    free(payload);
2133 	    (void) close(device_fd);
2134 	    return (-1);
2135 	}
2136 
2137 
2138 	/* verify payload length */
2139 	if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
2140 	    free(payload);
2141 	    (void) close(device_fd);
2142 	    return (-1);
2143 	}
2144 
2145 	(void) memcpy(buffer, payload, nbytes);
2146 	free(payload);
2147 	(void) close(device_fd);
2148 	return (nbytes);
2149 }
2150 
2151 /*
2152  * Description	:
2153  * 		fru_update_payload() writes the contents of a packet's payload.
2154  *
2155  * Arguments	: packet_hdl_t : packet handle.
2156  *		const void * : data buffer.
2157  *		size_t	: buffer size.
2158  *		packet_hdl_t	: new packet handle.
2159  *
2160  * Return	:
2161  * 		int
2162  *		On success, 0 is returned; on failure
2163  *		-1 is returned.
2164  */
2165 
2166 int
fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)2167 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
2168 				packet_hdl_t *newpacket, door_cred_t *cred)
2169 {
2170 	int		fd;
2171 	int		segment_offset;
2172 	int		trailer_offset;
2173 	int		retval;
2174 	uint32_t	crc;
2175 	hash_obj_t	*pkt_hash;
2176 	hash_obj_t	*seg_hash;
2177 	hash_obj_t	*sec_hash;
2178 	hash_obj_t	*cont_hash;
2179 	fru_segdesc_t	*desc;
2180 
2181 	/* check the effective uid of the client */
2182 	if (cred->dc_euid != 0) {
2183 		errno = EPERM;
2184 		return (-1);	/* not a root */
2185 	}
2186 
2187 	/* packet hash object */
2188 	pkt_hash = lookup_handle_object(packet,	PACKET_TYPE);
2189 	if (pkt_hash == NULL) {
2190 		return (-1);
2191 	}
2192 
2193 	/* segment hash object */
2194 	seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2195 						SEGMENT_TYPE);
2196 	if (seg_hash == NULL) {
2197 		return (-1);
2198 	}
2199 
2200 	/* check for write perm. */
2201 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2202 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2203 		errno = EPERM;
2204 		return (-1); /* write not allowed */
2205 	}
2206 
2207 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2208 						SECTION_TYPE);
2209 	if (sec_hash == NULL) {
2210 		return (-1);
2211 	}
2212 
2213 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2214 		errno = EPERM;
2215 		return (-1);		/* read-only section */
2216 	}
2217 
2218 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2219 						CONTAINER_TYPE);
2220 	if (cont_hash == NULL) {
2221 		return (-1);
2222 	}
2223 
2224 	if (pkt_hash->u.pkt_obj->paylen != nbytes) {
2225 		return (-1);
2226 	}
2227 
2228 	fd	= open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2229 	if (fd < 0) {
2230 		return (-1);
2231 	}
2232 
2233 	trailer_offset	= seg_hash->u.seg_obj->trailer_offset;
2234 	segment_offset	= seg_hash->u.seg_obj->segment.offset;
2235 
2236 	crc = get_checksum_crc(fd, seg_hash, (trailer_offset - segment_offset));
2237 	retval = pwrite(fd, data, nbytes, pkt_hash->u.pkt_obj->payload_offset);
2238 	if (retval != nbytes) {
2239 		(void) close(fd);
2240 		return (-1);
2241 	}
2242 
2243 	retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2244 	(void) close(fd);
2245 	if (retval != sizeof (crc)) {
2246 		return (-1);
2247 	}
2248 	*newpacket	= packet;
2249 	return (0);
2250 }
2251 
2252 /*
2253  * Description	:
2254  *		fru_append_packet() appends a packet to a segment.
2255  *
2256  * Arguments	:
2257  *		segment_hdl_t segment
2258  *		A handle for the segment to which the packet will be appended.
2259  *
2260  *   		packet_t *packet
2261  *     		On entry, the "tag" component of "packet" specifies the tag
2262  *     		value for the added packet; the "handle" component is ignored.
2263  *     		On return, the "handle" component is set to the handle of the
2264  *     		appended packet.
2265  *
2266  *   		const void *payload
2267  *     		A pointer to the caller's buffer containing the payload data for
2268  *     		the appended packet.
2269  *
2270  *   		size_t nbytes
2271  *     		The size of the caller buffer.
2272  *
2273  * Return	:
2274  *   		int
2275  *     		On success, 0 is returned; on error -1 is returned;
2276  */
2277 
2278 int
fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)2279 fru_append_packet(segment_hdl_t segment, packet_t *packet, const void *payload,
2280 		size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred)
2281 {
2282 	int		trailer_offset;
2283 	int		tag_size;
2284 	int		fd;
2285 	int		retval;
2286 	char		trailer[] = {0x0c, 0x00, 0x00, 0x00, 0x00};
2287 	uint32_t	crc;
2288 	hash_obj_t	*seg_hash;
2289 	hash_obj_t	*sec_hash;
2290 	hash_obj_t	*pkt_hash;
2291 	hash_obj_t	*cont_hash;
2292 	fru_tagtype_t	tagtype;
2293 	fru_segdesc_t	*desc;
2294 
2295 	/* check the effective uid of the client */
2296 	if (cred->dc_euid != 0) {
2297 		errno = EPERM;
2298 		return (-1);	/* not a root */
2299 	}
2300 
2301 	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
2302 	if (seg_hash == NULL) {
2303 		return (-1);
2304 	}
2305 
2306 	/* check for write perm. */
2307 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2308 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2309 		errno = EPERM;
2310 		return (-1); /* write not allowed */
2311 	}
2312 
2313 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2314 							SECTION_TYPE);
2315 	if (sec_hash == NULL) {
2316 		return (-1);
2317 	}
2318 
2319 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2320 		errno = EPERM;
2321 		return (-1);		/* read-only section */
2322 	}
2323 
2324 	trailer_offset	= seg_hash->u.seg_obj->trailer_offset;
2325 
2326 	/*
2327 	 * if trailer offset is 0 than parse the segment data to get the trailer
2328 	 * offset to compute the remaining space left in the segment area for
2329 	 * new packet to be added.
2330 	 */
2331 	if (trailer_offset == 0) {
2332 		(void) fru_get_num_packets(segment, cred);
2333 		trailer_offset  = seg_hash->u.seg_obj->trailer_offset;
2334 	}
2335 
2336 	tagtype	= get_tag_type((void *)&packet->tag);
2337 	if (tagtype == -1) {
2338 		return (-1);
2339 	}
2340 
2341 	tag_size	= get_tag_size(tagtype);
2342 	if (tag_size == -1) {
2343 		return (-1);
2344 	}
2345 
2346 	if (seg_hash->u.seg_obj->segment.length >
2347 		((trailer_offset - seg_hash->u.seg_obj->segment.offset) +
2348 			tag_size + nbytes + sizeof (char)
2349 						+ sizeof (uint32_t))) {
2350 		/* create new packet hash */
2351 		pkt_hash = create_packet_hash_object();
2352 		if (pkt_hash == NULL) {
2353 			return (-1);
2354 		}
2355 
2356 		/* tag initialization */
2357 		(void) memcpy(&pkt_hash->u.pkt_obj->tag, &packet->tag,
2358 								tag_size);
2359 		pkt_hash->u.pkt_obj->tag_size	= tag_size;
2360 		pkt_hash->u.pkt_obj->paylen	= nbytes;
2361 		pkt_hash->u.pkt_obj->payload_offset = trailer_offset + tag_size;
2362 
2363 		/* add to hash table */
2364 		add_hashobject_to_hashtable(pkt_hash);
2365 
2366 		add_to_pkt_object_list(seg_hash, pkt_hash);
2367 
2368 		cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2369 								CONTAINER_TYPE);
2370 		if (cont_hash == NULL) {
2371 			return (-1);
2372 		}
2373 
2374 		fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2375 		if (fd < 0) {
2376 			return (-1);
2377 		}
2378 
2379 		/* update the trailer offset  */
2380 		trailer_offset += tag_size + nbytes;
2381 
2382 		/* calculate new checksum */
2383 		crc = get_checksum_crc(fd, seg_hash, (trailer_offset -
2384 					seg_hash->u.seg_obj->segment.offset));
2385 
2386 		retval = pwrite(fd, &packet->tag, tag_size, trailer_offset
2387 							- (tag_size + nbytes));
2388 		if (retval != tag_size) {
2389 			(void) close(fd);
2390 			return (-1);
2391 		}
2392 
2393 		retval = pwrite(fd, payload, nbytes, trailer_offset - nbytes);
2394 		if (retval != nbytes) {
2395 			(void) close(fd);
2396 			return (-1);
2397 		}
2398 
2399 		retval = pwrite(fd, trailer, sizeof (trailer), trailer_offset);
2400 		if (retval != sizeof (trailer)) {
2401 			(void) close(fd);
2402 			return (-1);
2403 		}
2404 
2405 		retval = pwrite(fd, &crc, sizeof (crc), trailer_offset + 1);
2406 		(void) close(fd);
2407 		if (retval != sizeof (crc)) {
2408 			return (-1);
2409 		}
2410 
2411 		seg_hash->u.seg_obj->trailer_offset = trailer_offset;
2412 		seg_hash->u.seg_obj->num_of_packets += 1;
2413 
2414 		*newsegment	= segment; 	/* return new segment handle */
2415 		return (0);
2416 	} else {
2417 		errno = EAGAIN;
2418 	}
2419 
2420 	return (-1);
2421 }
2422 
2423 static void
adjust_packets(int fd,hash_obj_t * free_obj,hash_obj_t * object_list)2424 adjust_packets(int	fd, hash_obj_t	*free_obj, hash_obj_t	*object_list)
2425 {
2426 	int		retval;
2427 	uint8_t		*payload;
2428 	uint32_t	new_offset;
2429 	hash_obj_t	*hash_ptr;
2430 
2431 
2432 	new_offset = free_obj->u.pkt_obj->payload_offset
2433 					- free_obj->u.pkt_obj->tag_size;
2434 	for (hash_ptr = object_list; hash_ptr != NULL;
2435 				hash_ptr = hash_ptr->u.pkt_obj->next) {
2436 
2437 		payload = malloc(hash_ptr->u.pkt_obj->paylen);
2438 		if (payload == NULL) {
2439 		    return;
2440 		}
2441 		retval = get_payload(fd, hash_ptr, payload);
2442 		if (retval == -1) {
2443 		    free(payload);
2444 		    return;
2445 		}
2446 
2447 		retval = pwrite(fd, &hash_ptr->u.pkt_obj->tag,
2448 				hash_ptr->u.pkt_obj->tag_size, new_offset);
2449 		if (retval != hash_ptr->u.pkt_obj->tag_size) {
2450 		    free(payload);
2451 		    return;
2452 		}
2453 		new_offset += hash_ptr->u.pkt_obj->tag_size;
2454 		hash_ptr->u.pkt_obj->payload_offset = new_offset;
2455 		retval = pwrite(fd, payload,
2456 				hash_ptr->u.pkt_obj->paylen, new_offset);
2457 		if (retval != hash_ptr->u.pkt_obj->paylen) {
2458 		    free(payload);
2459 		    return;
2460 		}
2461 		new_offset += hash_ptr->u.pkt_obj->paylen;
2462 		free(payload);
2463 	}
2464 }
2465 
2466 static void
free_packet_object(handle_t handle,hash_obj_t * seg_hash)2467 free_packet_object(handle_t	handle, hash_obj_t *seg_hash)
2468 {
2469 	hash_obj_t	*pkt_hash;
2470 	hash_obj_t	*next_hash;
2471 
2472 	pkt_hash	= seg_hash->u.seg_obj->pkt_obj_list;
2473 	if (pkt_hash == NULL) {
2474 		return;
2475 	}
2476 
2477 	if (pkt_hash->obj_hdl == handle) {
2478 		seg_hash->u.seg_obj->pkt_obj_list = pkt_hash->u.pkt_obj->next;
2479 	} else {
2480 		while (pkt_hash->obj_hdl != handle) {
2481 			next_hash = pkt_hash;
2482 			pkt_hash = pkt_hash->u.pkt_obj->next;
2483 			if (pkt_hash == NULL) {
2484 				return;
2485 			}
2486 		}
2487 		next_hash->u.pkt_obj->next = pkt_hash->u.pkt_obj->next;
2488 	}
2489 
2490 	if (pkt_hash->prev == NULL) {
2491 		hash_table[(pkt_hash->obj_hdl % TABLE_SIZE)] = pkt_hash->next;
2492 		if (pkt_hash->next != NULL) {
2493 			pkt_hash->next->prev = NULL;
2494 		}
2495 	} else {
2496 		pkt_hash->prev->next = pkt_hash->next;
2497 		if (pkt_hash->next != NULL) {
2498 			pkt_hash->next->prev = pkt_hash->prev;
2499 		}
2500 	}
2501 
2502 	free(pkt_hash->u.pkt_obj);
2503 	free(pkt_hash);
2504 }
2505 
2506 /*
2507  * Description	:
2508  *   		fru_delete_packet() deletes a packet from a segment.
2509  *
2510  * Arguments	: packet_hdl_t : packet number to be deleted.
2511  *		segment_hdl_t : new segment handler.
2512  *
2513  * Return	:
2514  *   		int
2515  *     		On success, 0 is returned; on error, -1.
2516  *
2517  * NOTES
2518  * 		Packets are adjacent; thus, deleting a packet requires moving
2519  *   		succeeding packets to compact the resulting hole.
2520  */
2521 
2522 int
fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)2523 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
2524 						door_cred_t *cred)
2525 {
2526 	int		retval;
2527 	int		fd;
2528 	char		trailer[] = { 0x0c, 0x00, 0x00, 0x00, 0x00};
2529 	uint32_t	crc;
2530 	hash_obj_t	*tmp_obj;
2531 	hash_obj_t	*pkt_hash;
2532 	hash_obj_t	*sec_hash;
2533 	hash_obj_t	*cont_hash;
2534 	hash_obj_t	*prev_obj;
2535 	hash_obj_t	*seg_hash;
2536 	fru_segdesc_t	*desc;
2537 
2538 	/* check the effective uid of the client */
2539 	if (cred->dc_euid != 0) {
2540 		errno = EPERM;
2541 		return (-1);	/* not a root */
2542 	}
2543 
2544 	/* packet hash object */
2545 	pkt_hash = lookup_handle_object(packet, PACKET_TYPE);
2546 	if (pkt_hash == NULL) {
2547 		return (-1);
2548 	}
2549 
2550 	/* segment hash object */
2551 	seg_hash = lookup_handle_object(pkt_hash->u.pkt_obj->segment_hdl,
2552 							SEGMENT_TYPE);
2553 	if (seg_hash == NULL) {
2554 		return (-1);
2555 	}
2556 
2557 	/* check for write perm. */
2558 	desc    = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
2559 	if (!(desc->field.field_perm & SEGMENT_WRITE)) {
2560 		errno = EPERM;
2561 		return (-1); /* write not allowed */
2562 	}
2563 
2564 	/* section hash object */
2565 	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
2566 							SECTION_TYPE);
2567 	if (sec_hash == NULL) {
2568 		return (-1);
2569 	}
2570 
2571 	if (sec_hash->u.sec_obj->section.protection == READ_ONLY_SECTION) {
2572 		errno = EPERM;
2573 		return (-1); 		/* read-only section */
2574 	}
2575 
2576 	prev_obj	= seg_hash->u.seg_obj->pkt_obj_list;
2577 	if (prev_obj == NULL) {
2578 		return (-1);
2579 	}
2580 
2581 	/* container hash object */
2582 	cont_hash = lookup_handle_object(sec_hash->u.sec_obj->cont_hdl,
2583 							CONTAINER_TYPE);
2584 	if (cont_hash == NULL) {
2585 		return (-1);
2586 	}
2587 
2588 	fd = open(cont_hash->u.cont_obj->device_pathname, O_RDWR);
2589 	if (fd < 0) {
2590 		return (-1);
2591 	}
2592 
2593 	if (prev_obj->obj_hdl == packet) { /* first object to be deleted */
2594 		adjust_packets(fd, prev_obj, prev_obj->u.pkt_obj->next);
2595 		seg_hash->u.seg_obj->trailer_offset -=
2596 			(prev_obj->u.pkt_obj->tag_size
2597 					+ prev_obj->u.pkt_obj->paylen);
2598 		free_packet_object(packet, seg_hash);
2599 	} else {
2600 		for (tmp_obj = prev_obj;
2601 			tmp_obj != NULL; tmp_obj = tmp_obj->u.pkt_obj->next) {
2602 			/* found the object */
2603 			if (tmp_obj->obj_hdl == packet) {
2604 				adjust_packets(fd, tmp_obj,
2605 						tmp_obj->u.pkt_obj->next);
2606 				seg_hash->u.seg_obj->trailer_offset -=
2607 					(tmp_obj->u.pkt_obj->tag_size
2608 						+ tmp_obj->u.pkt_obj->paylen);
2609 				free_packet_object(packet, seg_hash);
2610 			}
2611 		}
2612 	}
2613 
2614 	seg_hash->u.seg_obj->num_of_packets -= 1;
2615 
2616 	/* calculate checksum */
2617 	crc = get_checksum_crc(fd, seg_hash,
2618 				(seg_hash->u.seg_obj->trailer_offset
2619 				- seg_hash->u.seg_obj->segment.offset));
2620 	/* write trailer at new offset */
2621 	retval = pwrite(fd, &trailer, sizeof (trailer),
2622 					seg_hash->u.seg_obj->trailer_offset);
2623 	if (retval != sizeof (trailer)) {
2624 		(void) close(fd);
2625 		return (-1);
2626 	}
2627 
2628 	/* write the checksum value */
2629 	retval = pwrite(fd, &crc, sizeof (crc),
2630 				seg_hash->u.seg_obj->trailer_offset + 1);
2631 	(void) close(fd);
2632 	if (retval != sizeof (crc)) {
2633 		return (-1);
2634 	}
2635 
2636 	*newsegment = seg_hash->obj_hdl; /* return new segment handle */
2637 	return (0);
2638 }
2639 
2640 /*
2641  * Description :
2642  *		fru_close_container() removes the association between a
2643  *		container and its handle. this routines free's up all the
2644  *		hash object contained under container.
2645  *
2646  * Arguments   :
2647  *		container_hdl_t holds the file descriptor of the fru.
2648  *
2649  * Return      :
2650  *		int
2651  *		return 0.
2652  *
2653  */
2654 
2655 /* ARGSUSED */
2656 int
fru_close_container(container_hdl_t container)2657 fru_close_container(container_hdl_t container)
2658 {
2659 	hash_obj_t	*hash_obj;
2660 	hash_obj_t	*prev_hash;
2661 	hash_obj_t	*sec_hash_obj;
2662 	handle_t	obj_hdl;
2663 
2664 	/* lookup for container hash object */
2665 	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
2666 	if (hash_obj == NULL) {
2667 		return (0);
2668 	}
2669 
2670 	/* points to section object list */
2671 	sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
2672 
2673 	/* traverse section object list */
2674 	while (sec_hash_obj != NULL) {
2675 
2676 		/* traverse segment hash object in the section */
2677 		while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
2678 			/* object handle of the segment hash object */
2679 			obj_hdl	=
2680 			sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
2681 			free_segment_hash(obj_hdl, sec_hash_obj);
2682 		}
2683 
2684 		/* going to free section hash object, relink the hash object */
2685 		if (sec_hash_obj->prev == NULL) {
2686 			hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)]
2687 							= sec_hash_obj->next;
2688 			if (sec_hash_obj->next != NULL) {
2689 				sec_hash_obj->next->prev = NULL;
2690 			}
2691 		} else {
2692 			sec_hash_obj->prev->next = sec_hash_obj->next;
2693 			if (sec_hash_obj->next != NULL) {
2694 				sec_hash_obj->next->prev = sec_hash_obj->prev;
2695 			}
2696 		}
2697 
2698 		free(sec_hash_obj->u.sec_obj); /* free section hash object */
2699 
2700 		prev_hash = sec_hash_obj;
2701 
2702 		sec_hash_obj = sec_hash_obj->u.sec_obj->next;
2703 
2704 		free(prev_hash); /* free section hash */
2705 	}
2706 
2707 	/* free container hash object */
2708 	if (hash_obj->prev == NULL) {
2709 		hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
2710 							hash_obj->next;
2711 		if (hash_obj->next != NULL) {
2712 			hash_obj->next->prev = NULL;
2713 		}
2714 	} else {
2715 		hash_obj->prev->next = hash_obj->next;
2716 		if (hash_obj->next != NULL) {
2717 			hash_obj->next->prev = hash_obj->prev;
2718 		}
2719 	}
2720 
2721 	free(hash_obj->u.cont_obj);
2722 	free(hash_obj);
2723 	return (0);
2724 }
2725 
2726 /*
2727  * Description :
2728  *		fru_is_data_available() checks to see if the frudata
2729  *		is available on a fru.
2730  *
2731  * Arguments   :
2732  *		picl_nodehdl_t holds the picl node handle of the fru.
2733  *
2734  * Return      :
2735  *		int
2736  *		return 1: if FRUID information is available
2737  *		return 0: if FRUID information is not present
2738  *
2739  */
2740 
2741 /* ARGSUSED */
2742 int
fru_is_data_available(picl_nodehdl_t fru)2743 fru_is_data_available(picl_nodehdl_t fru)
2744 {
2745 	return (0);
2746 }
2747