OpenSolaris_b135/lib/libfru/libfruraw/fruraw.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 <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "fru_access_impl.h"

#include "libfruds.h"
#include "libfrup.h"
#include "fru_access.h"
#include "fruraw.h"


raw_list_t *g_raw = NULL;


/* ARGSUSED */
static raw_list_t *
treehdl_to_rawlist(fru_treehdl_t handle)
{
	return (g_raw);
}


static container_hdl_t
treehdl_to_conthdl(fru_treehdl_t handle)
{
	raw_list_t *ptr;

	ptr = treehdl_to_rawlist(handle);
	if (ptr == NULL) {
		return (-1);
	}

	return (ptr->cont);
}


static fru_errno_t
map_errno(int err)
{
	switch (err) {
	case ENFILE:
	case EEXIST:
		return (FRU_DUPSEG);
	case EAGAIN:
		return (FRU_NOSPACE);
	case EPERM:
		return (FRU_INVALPERM);
	default :
		return (FRU_IOERROR);
	}
}


static raw_list_t *
make_raw(uint8_t *buffer, size_t size, char *cont_type)
{
	raw_list_t *node;

	node = (raw_list_t *)malloc(sizeof (raw_list_t));
	if (node == NULL) {
		return (NULL);
	}

	node->hdl = 0;
	node->raw = buffer;
	node->size = size;
	node->cont_type = strdup(cont_type);
	if (node->cont_type == NULL) {
		free(node);
		return (NULL);
	}
	node->segs = NULL;

	return (node);
}


/*
 * Arguments :
 * 0 - pointer to byte buffer (in)
 * 1 - size of buffer (in)
 * 2 - container type, string (in)
 */
static fru_errno_t
frt_initialize(int num, char **args)
{


	if (num != 3) {
		return (FRU_FAILURE);
	}

	g_raw = make_raw((uint8_t *)args[0], (size_t)args[1], args[2]);
	if (g_raw == NULL) {
		return (FRU_FAILURE);
	}

	g_raw->cont = open_raw_data(g_raw);
	if (g_raw->cont == NULL) {
		return (FRU_FAILURE);
	}

	return (FRU_SUCCESS);
}


static fru_errno_t
frt_shutdown(void)
{
	segment_list_t *lptr, *lptr2;

	(void) fru_close_container(g_raw->cont);
	free(g_raw->cont_type);
	lptr = g_raw->segs;
	while (lptr) {
		lptr2 = lptr;
		lptr = lptr->next;
		free(lptr2);
	}
	g_raw = NULL;

	return (FRU_SUCCESS);
}


static fru_errno_t
frt_get_root(fru_treehdl_t *node)
{
	*node = g_raw->hdl;

	return (FRU_SUCCESS);
}

/* ARGSUSED */
static fru_errno_t
frt_get_peer(fru_treehdl_t sibling, fru_treehdl_t *peer)
{
	return (FRU_NODENOTFOUND);
}
/* ARGSUSED */
static fru_errno_t
frt_get_child(fru_treehdl_t handle, fru_treehdl_t *child)
{
	return (FRU_NODENOTFOUND);
}

/* ARGSUSED */
static fru_errno_t
frt_get_parent(fru_treehdl_t handle, fru_treehdl_t *parent)
{
	return (FRU_NODENOTFOUND);
}

/* ARGSUSED */
static fru_errno_t
frt_get_name_from_hdl(fru_treehdl_t handle, char **name)
{
	*name = strdup("unknown");
	return (FRU_SUCCESS);
}

/* ARGSUSED */
static fru_errno_t
frt_get_node_type(fru_treehdl_t node, fru_node_t *type)
{
	*type = FRU_NODE_CONTAINER;
	return (FRU_SUCCESS);
}



static fru_errno_t
add_segs_for_section(section_t *section, fru_strlist_t *list)
{
	int i = 0;
	segment_t *segs = NULL;
	int acc_err = 0;

	int num_segment = fru_get_num_segments(section->handle, NULL);
	if (num_segment == -1) {
		return (map_errno(errno));
	} else if (num_segment == 0) {
		return (FRU_SUCCESS);
	}

	segs = malloc(sizeof (*segs) * (num_segment));
	if (segs == NULL) {
		return (FRU_FAILURE);
	}

	acc_err = fru_get_segments(section->handle, segs, num_segment, NULL);
	if (acc_err == -1) {
		free(segs);
		return (map_errno(errno));
	}

	list->strs = realloc(list->strs, sizeof (char *)
	    * (list->num + num_segment));

	for (i = 0; i < num_segment; i++) {
		/* ensure NULL terminated. */
		char *tmp = malloc(sizeof (*tmp) * (sizeof (segs[i].name)+1));
		if (tmp == NULL) {
			free(segs);
			return (FRU_FAILURE);
		}
		(void) memcpy(tmp, segs[i].name, sizeof (segs[i].name));
		tmp[sizeof (segs[i].name)] = '\0';

		list->strs[(list->num)++] = tmp;
	}

	free(segs);

	return (FRU_SUCCESS);
}



static fru_errno_t
frt_get_seg_list(fru_treehdl_t handle, fru_strlist_t *list)
{
	fru_strlist_t rc_list;
	fru_errno_t err = FRU_SUCCESS;
	int acc_err = 0;
	int i = 0;
	int num_section = 0;
	section_t *sects = NULL;
	container_hdl_t cont;

	cont = treehdl_to_conthdl(handle);

	num_section = fru_get_num_sections(cont, NULL);
	if (num_section == -1) {
		return (map_errno(errno));
	}

	sects = malloc(sizeof (*sects) * (num_section));
	if (sects == NULL) {
		return (FRU_FAILURE);
	}

	acc_err = fru_get_sections(cont, sects, num_section, NULL);
	if (acc_err == -1) {
		free(sects);
		return (map_errno(errno));
	}

	rc_list.num = 0;
	rc_list.strs = NULL;
	for (i = 0; i < num_section; i++) {
		if ((err = add_segs_for_section(&(sects[i]), &rc_list))
		    != FRU_SUCCESS) {
			fru_destroy_strlist(&rc_list);
			free(sects);
			return (err);
		}
	}

	list->strs = rc_list.strs;
	list->num = rc_list.num;

	return (FRU_SUCCESS);
}


static fru_errno_t
find_seg_in_sect(section_t *sect, const char *seg_name, int *prot_flg,
    segment_t *segment)
{
	int j = 0;
	int acc_err = 0;
	segment_t *segs = NULL;

	int num_seg = fru_get_num_segments(sect->handle, NULL);
	if (num_seg == -1) {
		return (FRU_FAILURE);
	}

	segs = malloc(sizeof (*segs) * (num_seg));
	if (segs == NULL) {
		return (FRU_FAILURE);
	}

	acc_err = fru_get_segments(sect->handle, segs, num_seg, NULL);
	if (acc_err == -1) {
		free(segs);
		return (map_errno(errno));
	}

	for (j = 0; j < num_seg; j++) {
		/* NULL terminate */
		char tmp[SEG_NAME_LEN+1];
		(void) memcpy(tmp, segs[j].name, SEG_NAME_LEN);
		tmp[SEG_NAME_LEN] = '\0';
		if (strcmp(tmp, seg_name) == 0) {
			*segment = segs[j];
			*prot_flg = (sect->protection ? 1 : 0);
			free(segs);
			return (FRU_SUCCESS);
		}
	}

	free(segs);
	return (FRU_INVALSEG);
}


static fru_errno_t
find_segment(fru_treehdl_t handle, const char *seg_name, int *prot_flg,
    segment_t *segment)
{
	int i = 0;
	int acc_err = 0;
	section_t *sect = NULL;
	container_hdl_t cont;
	int num_sect;

	cont = treehdl_to_conthdl(handle);

	num_sect = fru_get_num_sections(cont, NULL);
	if (num_sect == -1) {
		return (map_errno(errno));
	}

	sect = malloc(sizeof (*sect) * (num_sect));
	if (sect == NULL) {
		return (FRU_FAILURE);
	}

	acc_err = fru_get_sections(cont, sect, num_sect, NULL);
	if (acc_err == -1) {
		free(sect);
		return (map_errno(errno));
	}

	for (i = 0; i < num_sect; i++) {
		if (find_seg_in_sect(&(sect[i]), seg_name, prot_flg, segment)
		    == FRU_SUCCESS) {
			free(sect);
			return (FRU_SUCCESS);
		}
	}

	free(sect);
	return (FRU_INVALSEG);
}


static fru_errno_t
frt_get_seg_def(fru_treehdl_t handle, const char *seg_name, fru_segdef_t *def)
{
	fru_errno_t err = FRU_SUCCESS;
	int prot_flg = 0;
	segment_t segment;

	if ((err = find_segment(handle, seg_name, &prot_flg, &segment))
	    != FRU_SUCCESS) {
		return (err);
	}

	(void) memcpy(def->name, segment.name, SEG_NAME_LEN);
	def->name[SEG_NAME_LEN] = '\0';
	def->desc.raw_data = segment.descriptor;
	def->size = segment.length;
	def->address = segment.offset;

	if (prot_flg == 0)
		def->hw_desc.field.read_only = 0;
	else
		def->hw_desc.field.read_only = 1;

	return (FRU_SUCCESS);

}

/* ARGSUSED */
static fru_errno_t
frt_add_seg(fru_treehdl_t handle, fru_segdef_t *def)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}

/* ARGSUSED */
static fru_errno_t
frt_delete_seg(fru_treehdl_t handle, const char *seg_name)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}

/* ARGSUSED */
static fru_errno_t
frt_for_each_segment(fru_nodehdl_t node,
    int (*function)(fru_seghdl_t hdl, void *args), void *args)
{
	int num_segment;
	int cnt;
	int num_sect;
	int each_seg;
	section_t *sects;
	segment_t *segs;
	segment_list_t *tmp_list;
	int acc_err;
	int status;
	container_hdl_t cont;

	cont = g_raw->cont;

	num_sect = fru_get_num_sections(cont, NULL);
	if (num_sect == -1) {
		return (map_errno(errno));
	}

	sects = malloc((num_sect + 1) * sizeof (section_t));
	if (sects == NULL) {
		return (FRU_FAILURE);
	}
	num_sect = fru_get_sections(cont, sects, num_sect, NULL);
	if (num_sect == -1) {
		free(sects);
		return (map_errno(errno));
	}
	for (cnt = 0; cnt < num_sect; cnt++) {
		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
		if (num_segment == -1) {
			return (map_errno(errno));
		} else if (num_segment == 0) {
			continue;
		}
		segs = malloc((num_segment + 1) * sizeof (segment_t));
		if (segs == NULL) {
			free(sects);
			return (FRU_FAILURE);
		}
		acc_err = fru_get_segments(sects[cnt].handle, segs,
		    num_segment, NULL);
		if (acc_err == -1) {
			free(sects);
			free(segs);
			return (map_errno(errno));
		}
		for (each_seg = 0; each_seg < num_segment; each_seg++) {
			tmp_list = malloc(sizeof (segment_list_t));
			tmp_list->segment = &segs[each_seg];
			tmp_list->next = NULL;
			if (g_raw->segs == NULL) {
				g_raw->segs = tmp_list;
			} else {
				tmp_list->next = g_raw->segs;
				g_raw->segs = tmp_list;
			}

			if ((status = function(segs[each_seg].handle, args))
			    != FRU_SUCCESS) {
				free(segs);
				free(sects);
				return (status);
			}
		}
		free(segs);
		free(sects);

	}
	return (FRU_SUCCESS);
}


static fru_errno_t
frt_get_segment_name(fru_seghdl_t node, char **name)
{
	int num_sect;
	int acc_err;
	int cnt;
	int num_segment;
	section_t *sects;
	segment_t *segs;
	int each_seg;
	container_hdl_t cont;

	cont = treehdl_to_conthdl(node);

	num_sect = fru_get_num_sections(cont, NULL);
	if (num_sect == -1) {
		return (map_errno(errno));
	}

	sects = malloc(sizeof (*sects) * (num_sect));
	if (sects == NULL) {
		return (FRU_FAILURE);
	}
	acc_err = fru_get_sections(cont, sects, num_sect, NULL);
	if (acc_err == -1) {
		free(sects);
		return (map_errno(errno));
	}

	for (cnt = 0; cnt < num_sect; cnt++) {
		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
		if (num_segment == -1) {
			free(sects);
			return (map_errno(errno));
		} else if (num_segment == 0) {
			continue;
		}

		segs = malloc(sizeof (*segs) * (num_segment));
		if (segs == NULL) {
			free(sects);
			return (FRU_FAILURE);
		}

		acc_err = fru_get_segments(sects[cnt].handle, segs,
		    num_segment, NULL);
		if (acc_err == -1) {
			free(sects);
			free(segs);
			return (map_errno(errno));
		}

		for (each_seg = 0; each_seg < num_segment; each_seg++) {
			if (segs[each_seg].handle == node) {
				segs[each_seg].name[FRU_SEGNAMELEN] = '\0';
				*name = segs[each_seg].name;
				free(sects);
				return (FRU_SUCCESS);
			}
		}
		free(segs);
	}

	return (FRU_FAILURE);
}


/* ARGSUSED */
static fru_errno_t
frt_add_tag_to_seg(fru_treehdl_t handle, const char *seg_name,
    fru_tag_t tag, uint8_t *data, size_t data_len)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}


/* ARGSUSED */
static fru_errno_t
frt_get_tag_list(fru_treehdl_t handle, const char *seg_name,
		fru_tag_t **tags, int *number)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}


/* ARGSUSED */
static fru_errno_t
frt_get_tag_data(fru_treehdl_t handle, const char *seg_name,
		fru_tag_t tag, int instance,
		uint8_t **data, size_t *data_len)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}


/* ARGSUSED */
static fru_errno_t
frt_set_tag_data(fru_treehdl_t handle, const char *seg_name,
		fru_tag_t tag, int instance,
		uint8_t *data, size_t data_len)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}


/* ARGSUSED */
static fru_errno_t
frt_delete_tag(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
    int instance)
{
	/* NOT SUPPORTED */
	return (FRU_NOTSUP);
}


static fru_errno_t
frt_for_each_packet(fru_seghdl_t node,
    int (*function)(fru_tag_t *tag, uint8_t *payload, size_t length,
	void *args), void *args)
{
	int rc_num;
	int status;
	char *rc_tags;
	char *rc_data;
	int i;
	packet_t *packets = NULL;
	segment_list_t *tmp_list;
	fru_segdesc_t *descriptor;

	tmp_list = g_raw->segs;

	/* num of packet */
	rc_num = fru_get_num_packets(node, NULL);
	if (rc_num == -1) {
		return (map_errno(errno));
	} else if (rc_num == 0) {
		return (FRU_SUCCESS);
	}
	while (tmp_list) {
		if (node == tmp_list->segment->handle) {
			break;
		}
		tmp_list = tmp_list->next;
	}
	if (tmp_list) {
		descriptor = (fru_segdesc_t *)&tmp_list->segment->descriptor;
		if (descriptor->field.opaque) {
			return (FRU_SUCCESS);
		}

		if (descriptor->field.encrypted && (encrypt_func == NULL)) {
			return (FRU_SUCCESS);
		}
	}

	packets = malloc(sizeof (*packets) * (rc_num));
	if (packets == NULL) {
		return (FRU_FAILURE);
	}
	/* get all packets */
	if (fru_get_packets(node, packets, rc_num, NULL) == -1) {
		free(packets);
		return (map_errno(errno));
	}

	rc_tags = malloc(sizeof (*rc_tags) * (rc_num));
	if (rc_tags == NULL) {
		free(packets);
		return (FRU_FAILURE);
	}

	/* number of tags */
	for (i = 0; i < rc_num; i++) {
		size_t rc_len =
		    get_payload_length((fru_tag_t *)&packets[i].tag);

		rc_data = malloc(sizeof (*rc_data) * (rc_len));
		if (rc_data == NULL) {
			free(packets);
			return (FRU_FAILURE);
		}
		/* get the payload data */
		(void) fru_get_payload(packets[i].handle, (void *)rc_data,
		    rc_len, NULL);

		if (tmp_list) {
			descriptor =
			    (fru_segdesc_t *)&tmp_list->segment->descriptor;

			if ((descriptor->field.encrypted) &&
			    ((status = encrypt_func(FRU_DECRYPT,
			    (void *)rc_data, rc_len))
			    != FRU_SUCCESS)) {
				return (status);
			}
		}
		/* print packet */
		if ((status = function((fru_tag_t *)&packets[i].tag,
		    (uint8_t *)rc_data, rc_len, args)) != FRU_SUCCESS) {
			free(rc_data);
			free(packets);
			return (status);
		}
		free(rc_data);
	}
	return (FRU_SUCCESS);

}


/* object for libfru to link to */
fru_datasource_t data_source =
{
	LIBFRU_DS_VER,
	frt_initialize,
	frt_shutdown,
	frt_get_root,
	frt_get_child,
	frt_get_peer,
	frt_get_parent,
	frt_get_name_from_hdl,
	frt_get_node_type,
	frt_get_seg_list,
	frt_get_seg_def,
	frt_add_seg,
	frt_delete_seg,
	frt_for_each_segment,
	frt_get_segment_name,
	frt_add_tag_to_seg,
	frt_get_tag_list,
	frt_get_tag_data,
	frt_set_tag_data,
	frt_delete_tag,
	frt_for_each_packet
};