OpenSolaris_b135/lib/libfru/libfruraw/raw_access.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <stdlib.h>
#include <alloca.h>
#include <sys/byteorder.h>
#include "fru_access_impl.h"
#include "fruraw.h"

#pragma init(initialize_raw_access)

static hash_obj_t	*hash_table[TABLE_SIZE];
extern raw_list_t 	*g_raw;

static void
initialize_raw_access(void)
{
	int	count;

	for (count = 0; count < TABLE_SIZE; count++) {
		hash_table[count] = NULL;
	}
}


static hash_obj_t *
lookup_handle_object(handle_t	handle, int object_type)
{
	handle_t index_to_hash;
	hash_obj_t *first_hash_obj;
	hash_obj_t *next_hash_obj;

	index_to_hash = (handle % TABLE_SIZE);

	first_hash_obj = hash_table[index_to_hash];
	for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
	    next_hash_obj = next_hash_obj->next) {
		if ((handle == next_hash_obj->obj_hdl) &&
		    (object_type == next_hash_obj->object_type)) {
			return (next_hash_obj);
		}
	}
	return (NULL);
}


static void
add_hashobject_to_hashtable(hash_obj_t *hash_obj)
{
	handle_t index_to_hash;
	static	uint64_t handle_count = 0;

	hash_obj->obj_hdl = ++handle_count;	/* store the handle */

	/* where to add ? */
	index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE);

	hash_obj->next = hash_table[index_to_hash];
	hash_table[index_to_hash] = hash_obj;	/* hash obj. added */

	if (hash_obj->next != NULL) {
		hash_obj->next->prev = hash_obj;
	}
}


static hash_obj_t *
create_container_hash_object(void)
{
	hash_obj_t *hash_obj;
	container_obj_t *cont_obj;

	cont_obj = malloc(sizeof (container_obj_t));
	if (cont_obj == NULL) {
		return (NULL);
	}

	hash_obj = malloc(sizeof (hash_obj_t));
	if (hash_obj == NULL) {
		free(cont_obj);
		return (NULL);
	}

	cont_obj->sec_obj_list = NULL;

	hash_obj->object_type = CONTAINER_TYPE;
	hash_obj->u.cont_obj = cont_obj;
	hash_obj->next = NULL;
	hash_obj->prev = NULL;

	return (hash_obj);
}


static hash_obj_t *
create_section_hash_object(void)
{
	hash_obj_t *hash_obj;
	section_obj_t *sec_obj;

	sec_obj	= malloc(sizeof (section_obj_t));
	if (sec_obj == NULL) {
		return (NULL);
	}

	hash_obj = malloc(sizeof (hash_obj_t));
	if (hash_obj == NULL) {
		free(sec_obj);
		return (NULL);
	}

	sec_obj->next = NULL;
	sec_obj->seg_obj_list = NULL;

	hash_obj->u.sec_obj = sec_obj;
	hash_obj->object_type = SECTION_TYPE;
	hash_obj->next = NULL;
	hash_obj->prev = NULL;

	return (hash_obj);
}


static hash_obj_t *
create_segment_hash_object(void)
{
	hash_obj_t *hash_obj;
	segment_obj_t *seg_obj;

	seg_obj	= malloc(sizeof (segment_obj_t));
	if (seg_obj == NULL) {
		return (NULL);
	}

	hash_obj = malloc(sizeof (hash_obj_t));
	if (hash_obj == NULL) {
		free(seg_obj);
		return (NULL);
	}

	seg_obj->next = NULL;
	seg_obj->pkt_obj_list = NULL;

	hash_obj->object_type = SEGMENT_TYPE;
	hash_obj->u.seg_obj = seg_obj;
	hash_obj->next = NULL;
	hash_obj->prev = NULL;

	return (hash_obj);
}


static hash_obj_t *
create_packet_hash_object(void)
{
	hash_obj_t *hash_obj;
	packet_obj_t *pkt_obj;

	pkt_obj	= malloc(sizeof (packet_obj_t));
	if (pkt_obj == NULL) {
		return (NULL);
	}

	hash_obj = malloc(sizeof (hash_obj_t));
	if (hash_obj == NULL) {
		free(pkt_obj);
		return (NULL);
	}

	pkt_obj->next = NULL;

	hash_obj->object_type = PACKET_TYPE;
	hash_obj->u.pkt_obj = pkt_obj;
	hash_obj->next = NULL;
	hash_obj->prev = NULL;

	return (hash_obj);
}



static hash_obj_t *
get_container_hash_object(int	object_type, handle_t	handle)
{
	hash_obj_t	*hash_obj;

	switch (object_type) {
	case CONTAINER_TYPE:
		break;
	case SECTION_TYPE:
		hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
		if (hash_obj == NULL) {
			return (NULL);
		}
		break;
	case SEGMENT_TYPE:
		hash_obj = lookup_handle_object(handle, SECTION_TYPE);
		if (hash_obj == NULL) {
			return (NULL);
		}
		hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
		    CONTAINER_TYPE);
		break;
	case PACKET_TYPE:
		break;
	default:
		return (NULL);
	}

	return (hash_obj);
}


static void
add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
{
	hash_obj_t *next_hash;

	/* add the packet object in the end of list */
	child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;

	if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
		parent_obj->u.seg_obj->pkt_obj_list = child_obj;
		return;
	}

	for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
	    next_hash->u.pkt_obj->next != NULL;
	    next_hash = next_hash->u.pkt_obj->next) {
		;
	}

	next_hash->u.pkt_obj->next = child_obj;
}


static void
free_pkt_object_list(hash_obj_t	*hash_obj)
{
	hash_obj_t *next_obj;
	hash_obj_t *free_obj;

	next_obj = hash_obj->u.seg_obj->pkt_obj_list;
	while (next_obj != NULL) {
		free_obj = next_obj;
		next_obj = next_obj->u.pkt_obj->next;
		/* if prev is NULL it's the first object in the list */
		if (free_obj->prev == NULL) {
			hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
			    free_obj->next;
			if (free_obj->next != NULL) {
				free_obj->next->prev = free_obj->prev;
			}
		} else {
			free_obj->prev->next = free_obj->next;
			if (free_obj->next != NULL) {
				free_obj->next->prev = free_obj->prev;
			}
		}

		free(free_obj->u.pkt_obj->payload);
		free(free_obj->u.pkt_obj);
		free(free_obj);
	}

	hash_obj->u.seg_obj->pkt_obj_list = NULL;
}


static void
free_segment_hash(handle_t handle, hash_obj_t *sec_hash)
{
	hash_obj_t *seg_hash;
	hash_obj_t *next_hash;

	seg_hash = sec_hash->u.sec_obj->seg_obj_list;
	if (seg_hash == NULL) {
		return;
	}

	if (seg_hash->obj_hdl == handle) {
		sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
	} else {
		while (seg_hash->obj_hdl != handle) {
			next_hash = seg_hash;
			seg_hash = seg_hash->u.seg_obj->next;
			if (seg_hash == NULL) {
				return;
			}
		}
		next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
	}

	if (seg_hash->prev == NULL) {
		hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
		if (seg_hash->next != NULL) {
			seg_hash->next->prev = NULL;
		}
	} else {
		seg_hash->prev->next = seg_hash->next;
		if (seg_hash->next != NULL) {
			seg_hash->next->prev = seg_hash->prev;
		}
	}

	free_pkt_object_list(seg_hash);
	free(seg_hash->u.seg_obj);
	free(seg_hash);
}



static void
add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
{
	hash_obj_t *next_hash;

	child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
	if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
		parent_obj->u.cont_obj->sec_obj_list = child_obj;
		return;
	}

	for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
	    next_hash->u.sec_obj->next != NULL;
	    next_hash = next_hash->u.sec_obj->next) {
		;
	}

	next_hash->u.sec_obj->next = child_obj;
}


static void
add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
{
	hash_obj_t *next_hash;

	child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
	if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
		parent_obj->u.sec_obj->seg_obj_list = child_obj;
		return;
	}

	for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
	    next_hash->u.seg_obj->next != NULL;
	    next_hash = next_hash->u.seg_obj->next) {
		;
	}

	next_hash->u.seg_obj->next = child_obj;
}


static char *
tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
{
	int i = 0;
	int j = 0;

	for (i = 0; buf[i] != '\0'; i++) {
		for (j = 0; j < strlen(separator); j++) {
			if (buf[i] == separator[j]) {
				buf[i] = '\0';
				*nextBuf = &(buf[i+1]);
				*matched = separator[j];
				return (buf);
			}
		}
	}

	*nextBuf = buf;
	*matched = '\0';
	return (NULL);
}


static void
copy_segment_layout(segment_t *seghdr, void *layout)
{
	segment_layout_t *seg_layout;

	seg_layout = (segment_layout_t *)layout;
	(void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
	seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
	seghdr->offset = BE_16(seg_layout->offset);
	seghdr->length = BE_16(seg_layout->length);
}


static int
get_container_info(const char *def_file, const char *cont_desc_str,
    container_info_t *cont_info)
{
	char *item;
	char *token;
	char *field;
	char matched;
	char buf[1024];
	int foundIt = 0;
	FILE *file = fopen(def_file, "r");

	if (file == NULL)
		return (-1);

	cont_info->num_sections = 0;

	while (fgets(buf, sizeof (buf), file) != NULL) {
		/* ignore all comments */
		token = tokenizer(buf, "#", &field, &matched);
		/* find the names */
		token = tokenizer(buf, ":", &field, &matched);
		if (token != 0x00) {
			token = tokenizer(token, "|", &item, &matched);
			while (token != 0x00) {
				if (strcmp(token, cont_desc_str) == 0) {
					foundIt = 1;
					goto found;
				}
				token = tokenizer(item, "|", &item, &matched);
			}
			/* check the last remaining item */
			if ((item != 0x00) &&
			    (strcmp(item, cont_desc_str) == 0)) {
				foundIt = 1;
				goto found;
			}
		}
	}

found :
	if (foundIt == 1) {
		token = tokenizer(field, ":", &field, &matched);
		if (token == 0x00) {
			(void) fclose(file);
			return (-1);
		}
		cont_info->header_ver = (headerrev_t)atoi(token);

		token = tokenizer(field, ":\n", &field, &matched);
		while (token != 0x00) {
			token = tokenizer(token, ",", &item, &matched);
			if (token == 0x00) {
				(void) fclose(file);
				return (-1);
			}
			if (atoi(token) == 1) {
				cont_info->section_info[cont_info->
				    num_sections].description.field.read_only
				    = 1;
			} else if (atoi(token) == 0) {
				cont_info->section_info[cont_info->
				    num_sections].description.field.read_only
				    = 0;
			} else {
				(void) fclose(file);
				return (-1);
			}

			token = tokenizer(item, ",", &item, &matched);
			if (token == 0x00) {
				(void) fclose(file);
				return (-1);
			}

			cont_info->section_info[cont_info->
			    num_sections].address = atoi(token);
			if (item == '\0') {
				(void) fclose(file);
				return (-1);
			}
			cont_info->section_info[cont_info->num_sections].size =
			    atoi(item);
			(cont_info->num_sections)++;

			token = tokenizer(field, ":\n ", &field, &matched);
		}
	}
	(void) fclose(file);

	return (0);
}


/* ARGSUSED */
int
fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
    door_cred_t *cred)
{
	int count;
	hash_obj_t *sec_object;
	hash_obj_t *seg_object;
	section_obj_t *sec_obj;

	sec_object = lookup_handle_object(section, SECTION_TYPE);
	if (sec_object == NULL) {
		return (-1);
	}

	sec_obj	= sec_object->u.sec_obj;
	if (sec_obj == NULL) {
		return (-1);
	}

	if (sec_obj->num_of_segment > maxseg) {
		return (-1);
	}

	seg_object = sec_object->u.sec_obj->seg_obj_list;
	if (seg_object == NULL) {
		return (-1);
	}

	for (count = 0; count < sec_obj->num_of_segment; count++) {

		/* populate segment_t */
		segment->handle = seg_object->obj_hdl;
		(void) memcpy(segment->name,
		    seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
		segment->descriptor = seg_object->u.seg_obj->segment.descriptor;

		segment->offset	= seg_object->u.seg_obj->segment.offset;
		segment->length	= seg_object->u.seg_obj->segment.length;
		seg_object = seg_object->u.seg_obj->next;
		segment++;
	}
	return (0);
}


static int
raw_memcpy(void *buffer, raw_list_t *rawlist, int offset, int size)
{
	if (offset + size > rawlist->size) {
		size = rawlist->size - offset;
	}

	(void) memcpy(buffer, &rawlist->raw[offset], size);

	return (size);
}


static int
verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
{
	int crc_offset = 0;
	unsigned char orig_crc8 = 0;
	unsigned char calc_crc8 = 0;

	switch (head_ver) {
		case SECTION_HDR_VER:
			crc_offset = 4;
			break;
		default:
			errno = EINVAL;
			return (0);
	}

	orig_crc8 = bytes[crc_offset];
	bytes[crc_offset] = 0x00; /* clear for calc */
	calc_crc8 = compute_crc8(bytes, length);
	bytes[crc_offset] = orig_crc8; /* restore */

	return (orig_crc8 == calc_crc8);
}


static int
get_section(raw_list_t *rawlist, hash_obj_t *sec_hash, section_t *section)
{
	int retval;
	int size;
	int count;
	uint16_t hdrver;
	hash_obj_t *seg_hash;
	unsigned char *buffer;
	section_obj_t *sec_obj;
	section_layout_t sec_hdr;
	segment_layout_t *seg_hdr;
	segment_layout_t *seg_buf;

	sec_obj	= sec_hash->u.sec_obj;
	if (sec_obj == NULL) {
		return (-1);
	}

	/* populate section_t */
	section->handle = sec_hash->obj_hdl;
	section->offset = sec_obj->section.offset;
	section->length = sec_obj->section.length;
	section->protection = sec_obj->section.protection;
	section->version = sec_obj->section.version;

	/* read section header layout */
	retval = raw_memcpy(&sec_hdr, rawlist, sec_obj->section.offset,
	    sizeof (sec_hdr));

	if (retval != sizeof (sec_hdr)) {
		return (-1);
	}


	hdrver = GET_SECTION_HDR_VERSION;

	if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
	    (hdrver != section->version)) {
		return (-1);
	}

	/* size = section layout + total sizeof segment header */
	size = sizeof (sec_hdr) + ((sec_hdr.segmentcount)
	    * sizeof (segment_layout_t));

	buffer = alloca(size);
	if (buffer == NULL) {
		return (-1);
	}

	/* segment header buffer */
	seg_buf = alloca(size - sizeof (sec_hdr));
	if (seg_buf == NULL) {
		return (-1);
	}

	/* read segment header */
	retval = raw_memcpy(seg_buf, rawlist,
	    sec_obj->section.offset + sizeof (sec_hdr),
	    size - sizeof (sec_hdr));

	if (retval != (size - sizeof (sec_hdr))) {
		return (-1);
	}

	/* copy section header layout */
	(void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));

	/* copy segment header layout */
	(void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
	    sizeof (sec_hdr));

	/* verify crc8 */
	retval = verify_header_crc8(hdrver, buffer, size);
	if (retval != TRUE) {
		return (-1);
	}

	section->version = hdrver;
	sec_obj->section.version = hdrver;

	seg_hdr	= (segment_layout_t *)seg_buf;

	/* bug fix for frutool */
	if (sec_hash->u.sec_obj->seg_obj_list != NULL) {
		return (0);
	} else {
		sec_obj->num_of_segment = 0;
	}
	for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {

		seg_hash = create_segment_hash_object();
		if (seg_hash == NULL) {
			return (-1);
		}
		add_hashobject_to_hashtable(seg_hash);
		copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
		add_to_seg_object_list(sec_hash, seg_hash);
		sec_obj->num_of_segment++;
	}
	return (0);
}

/* ARGSUSED */
int
fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
    door_cred_t *cred)
{
	int count;
	int num_sec = 0;
	hash_obj_t *cont_object;
	hash_obj_t *sec_hash;

	cont_object = lookup_handle_object(container, CONTAINER_TYPE);
	if (cont_object == NULL) {
		return (-1);
	}

	if (cont_object->u.cont_obj->num_of_section > maxsec) {
		return (-1);
	}

	sec_hash = cont_object->u.cont_obj->sec_obj_list;
	if (sec_hash == NULL) {
		return (-1);
	}

	for (count = 0; count < cont_object->u.cont_obj->num_of_section;
	    count++) {
		section->version = -1;
		/* populate section_t */
		if (get_section(g_raw, sec_hash, section) == 0) {
			section++;
			num_sec++;
		}
		sec_hash = sec_hash->u.sec_obj->next;
	}
	return (num_sec);
}


static uint32_t
get_checksum_crc(hash_obj_t *seg_hash, int data_size)
{
	int protection;
	int offset = 0;
	uint32_t crc;
	hash_obj_t *sec_hash;
	hash_obj_t *pkt_hash;
	unsigned char *buffer;

	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
	    SECTION_TYPE);
	if (sec_hash == NULL) {
		return ((uint32_t)-1);
	}

	buffer = alloca(data_size);
	if (buffer == NULL) {
		return ((uint32_t)-1);
	}

	/* traverse the packet object list for all the tags and payload */
	for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL;
	    pkt_hash = pkt_hash->u.pkt_obj->next) {
		(void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
		    pkt_hash->u.pkt_obj->tag_size);
		offset += pkt_hash->u.pkt_obj->tag_size;
		(void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload,
		    pkt_hash->u.pkt_obj->paylen);
		offset += pkt_hash->u.pkt_obj->paylen;
	}

	protection = sec_hash->u.sec_obj->section.protection;

	if (protection == READ_ONLY_SECTION) { /* read-only section */
		crc = compute_crc32(buffer, data_size);
	} else {		/* read/write section */
		crc = compute_checksum32(buffer, data_size);
	}
	return (crc);	/* computed crc */
}


static int
get_packet(raw_list_t *rawlist, void *buffer, int size, int offset)
{
	int retval;

	retval = raw_memcpy(buffer, rawlist, offset, size);

	if (retval != -1) {
		return (0);
	}
	return (-1);
}


static int
get_packets(hash_obj_t *seg_hash, raw_list_t *rawlist, int offset, int length)
{
	int tag_size;
	int paylen;
	int retval;
	int seg_limit = 0;
	int pktcnt = 0;
	char *data;
	uint32_t crc;
	uint32_t origcrc;
	fru_tag_t tag;
	hash_obj_t *pkt_hash_obj;
	hash_obj_t *sec_hash;
	fru_segdesc_t *segdesc;
	fru_tagtype_t tagtype;
	char *ignore_flag;

	retval = get_packet(rawlist, &tag, sizeof (fru_tag_t), offset);
	if (retval == -1) {
		return (-1);
	}

	/* section hash object */
	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
	    SECTION_TYPE);

	if (sec_hash == NULL) {
		return (-1);
	}

	seg_hash->u.seg_obj->trailer_offset = offset;

	data = (char *)&tag;
	while (data[0] != SEG_TRAILER_TAG) {
		tagtype	= get_tag_type(&tag); /* verify tag type */
		if (tagtype == -1) {
			return (-1);
		}

		tag_size = get_tag_size(tagtype);
		if (tag_size == -1) {
			return (-1);
		}

		seg_limit += tag_size;
		if (seg_limit > length) {
			return (-1);
		}

		paylen = get_payload_length((void *)&tag);
		if (paylen == -1) {
			return (-1);
		}

		seg_limit += paylen;
		if (seg_limit > length) {
			return (-1);
		}
		if ((offset + tag_size + paylen) >
		    (sec_hash->u.sec_obj->section.offset +
		    sec_hash->u.sec_obj->section.length)) {
			return (-1);
		}

		pkt_hash_obj = create_packet_hash_object();
		if (pkt_hash_obj == NULL) {
			return (-1);
		}

		pkt_hash_obj->u.pkt_obj->payload = malloc(paylen);
		if (pkt_hash_obj->u.pkt_obj->payload == NULL) {
			free(pkt_hash_obj);
			return (-1);
		}

		offset += tag_size;

		retval = raw_memcpy(pkt_hash_obj->u.pkt_obj->payload, rawlist,
		    offset, paylen);

		if (retval != paylen) {
			free(pkt_hash_obj->u.pkt_obj->payload);
			free(pkt_hash_obj);
			return (-1);
		}

		/* don't change this */
		pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
		(void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
		pkt_hash_obj->u.pkt_obj->paylen = paylen;
		pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
		pkt_hash_obj->u.pkt_obj->payload_offset = offset;

		offset += paylen;

		add_hashobject_to_hashtable(pkt_hash_obj);
		add_to_pkt_object_list(seg_hash, pkt_hash_obj);

		pktcnt++;

		retval = get_packet(rawlist, &tag, sizeof (fru_tag_t),
		    offset);
		if (retval == -1) {
			return (retval);
		}

		data = (char *)&tag;
	}

	segdesc	= (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;

	seg_hash->u.seg_obj->trailer_offset = offset;

	if (!segdesc->field.ignore_checksum)  {
		crc = get_checksum_crc(seg_hash, seg_limit);
		offset = seg_hash->u.seg_obj->segment.offset;

		retval = raw_memcpy(&origcrc, rawlist, offset + seg_limit + 1,
		    sizeof (origcrc));

		ignore_flag = getenv(IGNORE_CHECK);
		if (ignore_flag != NULL) {
			return (pktcnt);
		}

		if (retval != sizeof (origcrc)) {
			return (-1);
		}

		origcrc = BE_32(origcrc);
		if (origcrc != crc) {
			seg_hash->u.seg_obj->trailer_offset = offset;
			return (-1);
		}
	}

	return (pktcnt);
}

/* ARGSUSED */
int
fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
{
	hash_obj_t *hash_object;

	hash_object = lookup_handle_object(container, CONTAINER_TYPE);
	if (hash_object == NULL) {
		return (-1);
	}

	return (hash_object->u.cont_obj->num_of_section);
}

/* ARGSUSED */
int
fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
{
	hash_obj_t *sec_object;
	section_obj_t *sec_obj;

	sec_object = lookup_handle_object(section, SECTION_TYPE);
	if (sec_object == NULL) {
		return (-1);
	}

	sec_obj	= sec_object->u.sec_obj;
	if (sec_obj == NULL) {
		return (-1);
	}

	return (sec_obj->num_of_segment);
}

/* ARGSUSED */
int
fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
{
	int pktcnt;
	int length;
	uint16_t offset;
	hash_obj_t *cont_hash_obj;
	hash_obj_t *seg_hash;
	hash_obj_t *sec_hash;
	fru_segdesc_t *segdesc;
	segment_obj_t *segment_object;

	seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
	if (seg_hash == NULL) {
		return (-1);
	}

	segment_object = seg_hash->u.seg_obj;
	if (segment_object == NULL) {
		return (-1);
	}

	segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
	if (segdesc->field.opaque) {
		return (0);
	}

	offset = segment_object->segment.offset;
	length = segment_object->segment.length;

	cont_hash_obj = get_container_hash_object(SEGMENT_TYPE,
	    segment_object->section_hdl);

	if (cont_hash_obj == NULL) {
		return (-1);
	}

	if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
		return (segment_object->num_of_packets);
	}
	/* section hash object */
	sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
	    SECTION_TYPE);
	if (sec_hash == NULL) {
		return (-1);
	}

	/* valid segment header b'cos crc8 already validated */
	if (offset < sec_hash->u.sec_obj->section.offset) {
		return (-1);
	}

	segment_object->num_of_packets = 0;

	pktcnt = get_packets(seg_hash, g_raw, offset, length);
	if (pktcnt == -1) {
		free_pkt_object_list(seg_hash);
		seg_hash->u.seg_obj->pkt_obj_list = NULL;
	}

	segment_object->num_of_packets = pktcnt;

	return (segment_object->num_of_packets);
}

/* ARGSUSED */
int
fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
    door_cred_t *cred)
{
	int count;
	hash_obj_t *seg_hash_obj;
	hash_obj_t *pkt_hash_obj;

	/* segment hash object */
	seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE);
	if (seg_hash_obj == NULL) {
		return (-1);
	}

	if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
		return (-1);
	}

	pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list;
	if (pkt_hash_obj == NULL) {
		return (-1);
	}

	for (count = 0; count < maxpackets; count++, packet++) {
		packet->handle	= pkt_hash_obj->obj_hdl;
		packet->tag = 0;
		(void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
		    pkt_hash_obj->u.pkt_obj->tag_size);
		pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
	}

	return (0);
}

/* ARGSUSED */
ssize_t
fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
    door_cred_t *cred)
{
	hash_obj_t *packet_hash_obj;

	/* packet hash object */
	packet_hash_obj	= lookup_handle_object(packet, PACKET_TYPE);
	if (packet_hash_obj == NULL) {
		return (-1);
	}

	/* verify payload length */
	if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
		return (-1);
	}

	(void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes);
	return (nbytes);
}


container_hdl_t
open_raw_data(raw_list_t *node)
{
	char *cont_conf_file = NULL;
	hash_obj_t *cont_hash_obj;
	hash_obj_t *sec_hash_obj;
	container_info_t cont_info;
	int retval;
	int count;

	cont_hash_obj = create_container_hash_object();
	if (cont_hash_obj == NULL) {
		return (NULL);
	}

	add_hashobject_to_hashtable(cont_hash_obj);

	(void) strncpy(cont_hash_obj->u.cont_obj->device_pathname, "unknown",
	    sizeof (cont_hash_obj->u.cont_obj->device_pathname));

	cont_conf_file = getenv(FRU_CONT_CONF_ENV_VAR);
	if (cont_conf_file == NULL) {
		cont_conf_file = FRU_CONT_CONF_SPARC;
		retval = get_container_info(cont_conf_file, node->cont_type,
		    &cont_info);
		if (retval < 0) {
			cont_conf_file = FRU_CONT_CONF_X86;
			retval = get_container_info(cont_conf_file,
			    node->cont_type, &cont_info);
		}
	} else {
		retval = get_container_info(cont_conf_file, node->cont_type,
		    &cont_info);
	}

	if (retval < 0) {
		return (NULL);
	}

	cont_hash_obj->u.cont_obj->num_of_section = cont_info.num_sections;
	cont_hash_obj->u.cont_obj->sec_obj_list = NULL;

	for (count = 0; count < cont_info.num_sections; count++) {
		sec_hash_obj = create_section_hash_object();
		if (sec_hash_obj == NULL) {
			return (NULL);
		}

		add_hashobject_to_hashtable(sec_hash_obj);

		sec_hash_obj->u.sec_obj->section.offset =
		    cont_info.section_info[count].address;

		sec_hash_obj->u.sec_obj->section.protection =
		    cont_info.section_info[count].description.field.read_only;

		sec_hash_obj->u.sec_obj->section.length =
		    cont_info.section_info[count].size;
		sec_hash_obj->u.sec_obj->section.version =
		    cont_info.header_ver;

		add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
	}

	return (cont_hash_obj->obj_hdl);
}


int
fru_close_container(container_hdl_t container)
{
	hash_obj_t *hash_obj;
	hash_obj_t *prev_hash;
	hash_obj_t *sec_hash_obj;
	handle_t obj_hdl;

	/* lookup for container hash object */
	hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
	if (hash_obj == NULL) {
		return (0);
	}

	/* points to section object list */
	sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;

	/* traverse section object list */
	while (sec_hash_obj != NULL) {

		/* traverse segment hash object in the section */
		while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
			/* object handle of the segment hash object */
			obj_hdl	=
			    sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
			free_segment_hash(obj_hdl, sec_hash_obj);
		}

		/* going to free section hash object, relink the hash object */
		if (sec_hash_obj->prev == NULL) {
			hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
			    sec_hash_obj->next;
			if (sec_hash_obj->next != NULL) {
				sec_hash_obj->next->prev = NULL;
			}
		} else {
			sec_hash_obj->prev->next = sec_hash_obj->next;
			if (sec_hash_obj->next != NULL) {
				sec_hash_obj->next->prev = sec_hash_obj->prev;
			}
		}

		free(sec_hash_obj->u.sec_obj); /* free section hash object */

		prev_hash = sec_hash_obj;

		sec_hash_obj = sec_hash_obj->u.sec_obj->next;

		free(prev_hash); /* free section hash */
	}

	/* free container hash object */
	if (hash_obj->prev == NULL) {
		hash_table[(hash_obj->obj_hdl % TABLE_SIZE)] =
		    hash_obj->next;
		if (hash_obj->next != NULL) {
			hash_obj->next->prev = NULL;
		}
	} else {
		hash_obj->prev->next = hash_obj->next;
		if (hash_obj->next != NULL) {
			hash_obj->next->prev = hash_obj->prev;
		}
	}

	free(hash_obj->u.cont_obj);
	free(hash_obj);

	return (0);
}