fruraw.c revision 12126:60364f3f65c7
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/*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <stdio.h>
27#include <stdarg.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <string.h>
31
32#include "fru_access_impl.h"
33
34#include "libfruds.h"
35#include "libfrup.h"
36#include "fru_access.h"
37#include "fruraw.h"
38
39
40raw_list_t *g_raw = NULL;
41
42
43/* ARGSUSED */
44static raw_list_t *
45treehdl_to_rawlist(fru_treehdl_t handle)
46{
47	return (g_raw);
48}
49
50
51static container_hdl_t
52treehdl_to_conthdl(fru_treehdl_t handle)
53{
54	raw_list_t *ptr;
55
56	ptr = treehdl_to_rawlist(handle);
57	if (ptr == NULL) {
58		return (-1);
59	}
60
61	return (ptr->cont);
62}
63
64
65static fru_errno_t
66map_errno(int err)
67{
68	switch (err) {
69	case ENFILE:
70	case EEXIST:
71		return (FRU_DUPSEG);
72	case EAGAIN:
73		return (FRU_NOSPACE);
74	case EPERM:
75		return (FRU_INVALPERM);
76	default :
77		return (FRU_IOERROR);
78	}
79}
80
81
82static raw_list_t *
83make_raw(uint8_t *buffer, size_t size, char *cont_type)
84{
85	raw_list_t *node;
86
87	node = (raw_list_t *)malloc(sizeof (raw_list_t));
88	if (node == NULL) {
89		return (NULL);
90	}
91
92	node->hdl = 0;
93	node->raw = buffer;
94	node->size = size;
95	node->cont_type = strdup(cont_type);
96	if (node->cont_type == NULL) {
97		free(node);
98		return (NULL);
99	}
100	node->segs = NULL;
101
102	return (node);
103}
104
105
106/*
107 * Arguments :
108 * 0 - pointer to byte buffer (in)
109 * 1 - size of buffer (in)
110 * 2 - container type, string (in)
111 */
112static fru_errno_t
113frt_initialize(int num, char **args)
114{
115
116
117	if (num != 3) {
118		return (FRU_FAILURE);
119	}
120
121	g_raw = make_raw((uint8_t *)args[0], (size_t)args[1], args[2]);
122	if (g_raw == NULL) {
123		return (FRU_FAILURE);
124	}
125
126	g_raw->cont = open_raw_data(g_raw);
127	if (g_raw->cont == NULL) {
128		return (FRU_FAILURE);
129	}
130
131	return (FRU_SUCCESS);
132}
133
134
135static fru_errno_t
136frt_shutdown(void)
137{
138	segment_list_t *lptr, *lptr2;
139
140	(void) fru_close_container(g_raw->cont);
141	free(g_raw->cont_type);
142	lptr = g_raw->segs;
143	while (lptr) {
144		lptr2 = lptr;
145		lptr = lptr->next;
146		free(lptr2);
147	}
148	g_raw = NULL;
149
150	return (FRU_SUCCESS);
151}
152
153
154static fru_errno_t
155frt_get_root(fru_treehdl_t *node)
156{
157	*node = g_raw->hdl;
158
159	return (FRU_SUCCESS);
160}
161
162/* ARGSUSED */
163static fru_errno_t
164frt_get_peer(fru_treehdl_t sibling, fru_treehdl_t *peer)
165{
166	return (FRU_NODENOTFOUND);
167}
168/* ARGSUSED */
169static fru_errno_t
170frt_get_child(fru_treehdl_t handle, fru_treehdl_t *child)
171{
172	return (FRU_NODENOTFOUND);
173}
174
175/* ARGSUSED */
176static fru_errno_t
177frt_get_parent(fru_treehdl_t handle, fru_treehdl_t *parent)
178{
179	return (FRU_NODENOTFOUND);
180}
181
182/* ARGSUSED */
183static fru_errno_t
184frt_get_name_from_hdl(fru_treehdl_t handle, char **name)
185{
186	*name = strdup("unknown");
187	return (FRU_SUCCESS);
188}
189
190/* ARGSUSED */
191static fru_errno_t
192frt_get_node_type(fru_treehdl_t node, fru_node_t *type)
193{
194	*type = FRU_NODE_CONTAINER;
195	return (FRU_SUCCESS);
196}
197
198
199
200static fru_errno_t
201add_segs_for_section(section_t *section, fru_strlist_t *list)
202{
203	int i = 0;
204	segment_t *segs = NULL;
205	int acc_err = 0;
206
207	int num_segment = fru_get_num_segments(section->handle, NULL);
208	if (num_segment == -1) {
209		return (map_errno(errno));
210	} else if (num_segment == 0) {
211		return (FRU_SUCCESS);
212	}
213
214	segs = malloc(sizeof (*segs) * (num_segment));
215	if (segs == NULL) {
216		return (FRU_FAILURE);
217	}
218
219	acc_err = fru_get_segments(section->handle, segs, num_segment, NULL);
220	if (acc_err == -1) {
221		free(segs);
222		return (map_errno(errno));
223	}
224
225	list->strs = realloc(list->strs, sizeof (char *)
226	    * (list->num + num_segment));
227
228	for (i = 0; i < num_segment; i++) {
229		/* ensure NULL terminated. */
230		char *tmp = malloc(sizeof (*tmp) * (sizeof (segs[i].name)+1));
231		if (tmp == NULL) {
232			free(segs);
233			return (FRU_FAILURE);
234		}
235		(void) memcpy(tmp, segs[i].name, sizeof (segs[i].name));
236		tmp[sizeof (segs[i].name)] = '\0';
237
238		list->strs[(list->num)++] = tmp;
239	}
240
241	free(segs);
242
243	return (FRU_SUCCESS);
244}
245
246
247
248static fru_errno_t
249frt_get_seg_list(fru_treehdl_t handle, fru_strlist_t *list)
250{
251	fru_strlist_t rc_list;
252	fru_errno_t err = FRU_SUCCESS;
253	int acc_err = 0;
254	int i = 0;
255	int num_section = 0;
256	section_t *sects = NULL;
257	container_hdl_t cont;
258
259	cont = treehdl_to_conthdl(handle);
260
261	num_section = fru_get_num_sections(cont, NULL);
262	if (num_section == -1) {
263		return (map_errno(errno));
264	}
265
266	sects = malloc(sizeof (*sects) * (num_section));
267	if (sects == NULL) {
268		return (FRU_FAILURE);
269	}
270
271	acc_err = fru_get_sections(cont, sects, num_section, NULL);
272	if (acc_err == -1) {
273		free(sects);
274		return (map_errno(errno));
275	}
276
277	rc_list.num = 0;
278	rc_list.strs = NULL;
279	for (i = 0; i < num_section; i++) {
280		if ((err = add_segs_for_section(&(sects[i]), &rc_list))
281		    != FRU_SUCCESS) {
282			fru_destroy_strlist(&rc_list);
283			free(sects);
284			return (err);
285		}
286	}
287
288	list->strs = rc_list.strs;
289	list->num = rc_list.num;
290
291	return (FRU_SUCCESS);
292}
293
294
295static fru_errno_t
296find_seg_in_sect(section_t *sect, const char *seg_name, int *prot_flg,
297    segment_t *segment)
298{
299	int j = 0;
300	int acc_err = 0;
301	segment_t *segs = NULL;
302
303	int num_seg = fru_get_num_segments(sect->handle, NULL);
304	if (num_seg == -1) {
305		return (FRU_FAILURE);
306	}
307
308	segs = malloc(sizeof (*segs) * (num_seg));
309	if (segs == NULL) {
310		return (FRU_FAILURE);
311	}
312
313	acc_err = fru_get_segments(sect->handle, segs, num_seg, NULL);
314	if (acc_err == -1) {
315		free(segs);
316		return (map_errno(errno));
317	}
318
319	for (j = 0; j < num_seg; j++) {
320		/* NULL terminate */
321		char tmp[SEG_NAME_LEN+1];
322		(void) memcpy(tmp, segs[j].name, SEG_NAME_LEN);
323		tmp[SEG_NAME_LEN] = '\0';
324		if (strcmp(tmp, seg_name) == 0) {
325			*segment = segs[j];
326			*prot_flg = (sect->protection ? 1 : 0);
327			free(segs);
328			return (FRU_SUCCESS);
329		}
330	}
331
332	free(segs);
333	return (FRU_INVALSEG);
334}
335
336
337static fru_errno_t
338find_segment(fru_treehdl_t handle, const char *seg_name, int *prot_flg,
339    segment_t *segment)
340{
341	int i = 0;
342	int acc_err = 0;
343	section_t *sect = NULL;
344	container_hdl_t cont;
345	int num_sect;
346
347	cont = treehdl_to_conthdl(handle);
348
349	num_sect = fru_get_num_sections(cont, NULL);
350	if (num_sect == -1) {
351		return (map_errno(errno));
352	}
353
354	sect = malloc(sizeof (*sect) * (num_sect));
355	if (sect == NULL) {
356		return (FRU_FAILURE);
357	}
358
359	acc_err = fru_get_sections(cont, sect, num_sect, NULL);
360	if (acc_err == -1) {
361		free(sect);
362		return (map_errno(errno));
363	}
364
365	for (i = 0; i < num_sect; i++) {
366		if (find_seg_in_sect(&(sect[i]), seg_name, prot_flg, segment)
367		    == FRU_SUCCESS) {
368			free(sect);
369			return (FRU_SUCCESS);
370		}
371	}
372
373	free(sect);
374	return (FRU_INVALSEG);
375}
376
377
378static fru_errno_t
379frt_get_seg_def(fru_treehdl_t handle, const char *seg_name, fru_segdef_t *def)
380{
381	fru_errno_t err = FRU_SUCCESS;
382	int prot_flg = 0;
383	segment_t segment;
384
385	if ((err = find_segment(handle, seg_name, &prot_flg, &segment))
386	    != FRU_SUCCESS) {
387		return (err);
388	}
389
390	(void) memcpy(def->name, segment.name, SEG_NAME_LEN);
391	def->name[SEG_NAME_LEN] = '\0';
392	def->desc.raw_data = segment.descriptor;
393	def->size = segment.length;
394	def->address = segment.offset;
395
396	if (prot_flg == 0)
397		def->hw_desc.field.read_only = 0;
398	else
399		def->hw_desc.field.read_only = 1;
400
401	return (FRU_SUCCESS);
402
403}
404
405/* ARGSUSED */
406static fru_errno_t
407frt_add_seg(fru_treehdl_t handle, fru_segdef_t *def)
408{
409	/* NOT SUPPORTED */
410	return (FRU_NOTSUP);
411}
412
413/* ARGSUSED */
414static fru_errno_t
415frt_delete_seg(fru_treehdl_t handle, const char *seg_name)
416{
417	/* NOT SUPPORTED */
418	return (FRU_NOTSUP);
419}
420
421/* ARGSUSED */
422static fru_errno_t
423frt_for_each_segment(fru_nodehdl_t node,
424    int (*function)(fru_seghdl_t hdl, void *args), void *args)
425{
426	int num_segment;
427	int cnt;
428	int num_sect;
429	int each_seg;
430	section_t *sects;
431	segment_t *segs;
432	segment_list_t *tmp_list;
433	int acc_err;
434	int status;
435	container_hdl_t cont;
436
437	cont = g_raw->cont;
438
439	num_sect = fru_get_num_sections(cont, NULL);
440	if (num_sect == -1) {
441		return (map_errno(errno));
442	}
443
444	sects = malloc((num_sect + 1) * sizeof (section_t));
445	if (sects == NULL) {
446		return (FRU_FAILURE);
447	}
448	num_sect = fru_get_sections(cont, sects, num_sect, NULL);
449	if (num_sect == -1) {
450		free(sects);
451		return (map_errno(errno));
452	}
453	for (cnt = 0; cnt < num_sect; cnt++) {
454		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
455		if (num_segment == -1) {
456			return (map_errno(errno));
457		} else if (num_segment == 0) {
458			continue;
459		}
460		segs = malloc((num_segment + 1) * sizeof (segment_t));
461		if (segs == NULL) {
462			free(sects);
463			return (FRU_FAILURE);
464		}
465		acc_err = fru_get_segments(sects[cnt].handle, segs,
466		    num_segment, NULL);
467		if (acc_err == -1) {
468			free(sects);
469			free(segs);
470			return (map_errno(errno));
471		}
472		for (each_seg = 0; each_seg < num_segment; each_seg++) {
473			tmp_list = malloc(sizeof (segment_list_t));
474			tmp_list->segment = &segs[each_seg];
475			tmp_list->next = NULL;
476			if (g_raw->segs == NULL) {
477				g_raw->segs = tmp_list;
478			} else {
479				tmp_list->next = g_raw->segs;
480				g_raw->segs = tmp_list;
481			}
482
483			if ((status = function(segs[each_seg].handle, args))
484			    != FRU_SUCCESS) {
485				free(segs);
486				free(sects);
487				return (status);
488			}
489		}
490		free(segs);
491		free(sects);
492
493	}
494	return (FRU_SUCCESS);
495}
496
497
498static fru_errno_t
499frt_get_segment_name(fru_seghdl_t node, char **name)
500{
501	int num_sect;
502	int acc_err;
503	int cnt;
504	int num_segment;
505	section_t *sects;
506	segment_t *segs;
507	int each_seg;
508	container_hdl_t cont;
509
510	cont = treehdl_to_conthdl(node);
511
512	num_sect = fru_get_num_sections(cont, NULL);
513	if (num_sect == -1) {
514		return (map_errno(errno));
515	}
516
517	sects = malloc(sizeof (*sects) * (num_sect));
518	if (sects == NULL) {
519		return (FRU_FAILURE);
520	}
521	acc_err = fru_get_sections(cont, sects, num_sect, NULL);
522	if (acc_err == -1) {
523		free(sects);
524		return (map_errno(errno));
525	}
526
527	for (cnt = 0; cnt < num_sect; cnt++) {
528		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
529		if (num_segment == -1) {
530			free(sects);
531			return (map_errno(errno));
532		} else if (num_segment == 0) {
533			continue;
534		}
535
536		segs = malloc(sizeof (*segs) * (num_segment));
537		if (segs == NULL) {
538			free(sects);
539			return (FRU_FAILURE);
540		}
541
542		acc_err = fru_get_segments(sects[cnt].handle, segs,
543		    num_segment, NULL);
544		if (acc_err == -1) {
545			free(sects);
546			free(segs);
547			return (map_errno(errno));
548		}
549
550		for (each_seg = 0; each_seg < num_segment; each_seg++) {
551			if (segs[each_seg].handle == node) {
552				segs[each_seg].name[FRU_SEGNAMELEN] = '\0';
553				*name = strdup(segs[each_seg].name);
554				free(sects);
555				free(segs);
556				return (FRU_SUCCESS);
557			}
558		}
559		free(segs);
560	}
561
562	return (FRU_FAILURE);
563}
564
565
566/* ARGSUSED */
567static fru_errno_t
568frt_add_tag_to_seg(fru_treehdl_t handle, const char *seg_name,
569    fru_tag_t tag, uint8_t *data, size_t data_len)
570{
571	/* NOT SUPPORTED */
572	return (FRU_NOTSUP);
573}
574
575
576/* ARGSUSED */
577static fru_errno_t
578frt_get_tag_list(fru_treehdl_t handle, const char *seg_name,
579		fru_tag_t **tags, int *number)
580{
581	/* NOT SUPPORTED */
582	return (FRU_NOTSUP);
583}
584
585
586/* ARGSUSED */
587static fru_errno_t
588frt_get_tag_data(fru_treehdl_t handle, const char *seg_name,
589		fru_tag_t tag, int instance,
590		uint8_t **data, size_t *data_len)
591{
592	/* NOT SUPPORTED */
593	return (FRU_NOTSUP);
594}
595
596
597/* ARGSUSED */
598static fru_errno_t
599frt_set_tag_data(fru_treehdl_t handle, const char *seg_name,
600		fru_tag_t tag, int instance,
601		uint8_t *data, size_t data_len)
602{
603	/* NOT SUPPORTED */
604	return (FRU_NOTSUP);
605}
606
607
608/* ARGSUSED */
609static fru_errno_t
610frt_delete_tag(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
611    int instance)
612{
613	/* NOT SUPPORTED */
614	return (FRU_NOTSUP);
615}
616
617
618static fru_errno_t
619frt_for_each_packet(fru_seghdl_t node,
620    int (*function)(fru_tag_t *tag, uint8_t *payload, size_t length,
621	void *args), void *args)
622{
623	int rc_num;
624	int status;
625	char *rc_tags;
626	char *rc_data;
627	int i;
628	packet_t *packets = NULL;
629	segment_list_t *tmp_list;
630	fru_segdesc_t *descriptor;
631
632	tmp_list = g_raw->segs;
633
634	/* num of packet */
635	rc_num = fru_get_num_packets(node, NULL);
636	if (rc_num == -1) {
637		return (map_errno(errno));
638	} else if (rc_num == 0) {
639		return (FRU_SUCCESS);
640	}
641	while (tmp_list) {
642		if (node == tmp_list->segment->handle) {
643			break;
644		}
645		tmp_list = tmp_list->next;
646	}
647	if (tmp_list) {
648		descriptor = (fru_segdesc_t *)&tmp_list->segment->descriptor;
649		if (descriptor->field.opaque) {
650			return (FRU_SUCCESS);
651		}
652
653		if (descriptor->field.encrypted && (encrypt_func == NULL)) {
654			return (FRU_SUCCESS);
655		}
656	}
657
658	packets = malloc(sizeof (*packets) * (rc_num));
659	if (packets == NULL) {
660		return (FRU_FAILURE);
661	}
662	/* get all packets */
663	if (fru_get_packets(node, packets, rc_num, NULL) == -1) {
664		free(packets);
665		return (map_errno(errno));
666	}
667
668	rc_tags = malloc(sizeof (*rc_tags) * (rc_num));
669	if (rc_tags == NULL) {
670		free(packets);
671		return (FRU_FAILURE);
672	}
673
674	/* number of tags */
675	for (i = 0; i < rc_num; i++) {
676		size_t rc_len =
677		    get_payload_length((fru_tag_t *)&packets[i].tag);
678
679		rc_data = malloc(sizeof (*rc_data) * (rc_len));
680		if (rc_data == NULL) {
681			free(packets);
682			return (FRU_FAILURE);
683		}
684		/* get the payload data */
685		(void) fru_get_payload(packets[i].handle, (void *)rc_data,
686		    rc_len, NULL);
687
688		if (tmp_list) {
689			descriptor =
690			    (fru_segdesc_t *)&tmp_list->segment->descriptor;
691
692			if ((descriptor->field.encrypted) &&
693			    ((status = encrypt_func(FRU_DECRYPT,
694			    (void *)rc_data, rc_len))
695			    != FRU_SUCCESS)) {
696				return (status);
697			}
698		}
699		/* print packet */
700		if ((status = function((fru_tag_t *)&packets[i].tag,
701		    (uint8_t *)rc_data, rc_len, args)) != FRU_SUCCESS) {
702			free(rc_data);
703			free(packets);
704			return (status);
705		}
706		free(rc_data);
707	}
708	return (FRU_SUCCESS);
709
710}
711
712
713/* object for libfru to link to */
714fru_datasource_t data_source =
715{
716	LIBFRU_DS_VER,
717	frt_initialize,
718	frt_shutdown,
719	frt_get_root,
720	frt_get_child,
721	frt_get_peer,
722	frt_get_parent,
723	frt_get_name_from_hdl,
724	frt_get_node_type,
725	frt_get_seg_list,
726	frt_get_seg_def,
727	frt_add_seg,
728	frt_delete_seg,
729	frt_for_each_segment,
730	frt_get_segment_name,
731	frt_add_tag_to_seg,
732	frt_get_tag_list,
733	frt_get_tag_data,
734	frt_set_tag_data,
735	frt_delete_tag,
736	frt_for_each_packet
737};
738