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