/* * 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 #include #include #include #include #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 };