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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 
33 #include "fru_access_impl.h"
34 
35 #include "libfruds.h"
36 #include "libfrup.h"
37 #include "fru_access.h"
38 #include "fruraw.h"
39 
40 
41 raw_list_t *g_raw = NULL;
42 
43 
44 /* ARGSUSED */
45 static raw_list_t *
46 treehdl_to_rawlist(fru_treehdl_t handle)
47 {
48 	return (g_raw);
49 }
50 
51 
52 static container_hdl_t
53 treehdl_to_conthdl(fru_treehdl_t handle)
54 {
55 	raw_list_t *ptr;
56 
57 	ptr = treehdl_to_rawlist(handle);
58 	if (ptr == NULL) {
59 		return (-1);
60 	}
61 
62 	return (ptr->cont);
63 }
64 
65 
66 static fru_errno_t
67 map_errno(int err)
68 {
69 	switch (err) {
70 	case ENFILE:
71 	case EEXIST:
72 		return (FRU_DUPSEG);
73 	case EAGAIN:
74 		return (FRU_NOSPACE);
75 	case EPERM:
76 		return (FRU_INVALPERM);
77 	default :
78 		return (FRU_IOERROR);
79 	}
80 }
81 
82 
83 static raw_list_t *
84 make_raw(uint8_t *buffer, size_t size, char *cont_type)
85 {
86 	raw_list_t *node;
87 
88 	node = (raw_list_t *)malloc(sizeof (raw_list_t));
89 	if (node == NULL) {
90 		return (NULL);
91 	}
92 
93 	node->hdl = 0;
94 	node->raw = buffer;
95 	node->size = size;
96 	node->cont_type = strdup(cont_type);
97 	if (node->cont_type == NULL) {
98 		free(node);
99 		return (NULL);
100 	}
101 	node->segs = NULL;
102 
103 	return (node);
104 }
105 
106 
107 /*
108  * Arguments :
109  * 0 - pointer to byte buffer (in)
110  * 1 - size of buffer (in)
111  * 2 - container type, string (in)
112  */
113 static fru_errno_t
114 frt_initialize(int num, char **args)
115 {
116 
117 
118 	if (num != 3) {
119 		return (FRU_FAILURE);
120 	}
121 
122 	g_raw = make_raw((uint8_t *)args[0], (size_t)args[1], args[2]);
123 	if (g_raw == NULL) {
124 		return (FRU_FAILURE);
125 	}
126 
127 	g_raw->cont = open_raw_data(g_raw);
128 	if (g_raw->cont == NULL) {
129 		return (FRU_FAILURE);
130 	}
131 
132 	return (FRU_SUCCESS);
133 }
134 
135 
136 static fru_errno_t
137 frt_shutdown(void)
138 {
139 	segment_list_t *lptr, *lptr2;
140 
141 	(void) fru_close_container(g_raw->cont);
142 	free(g_raw->cont_type);
143 	lptr = g_raw->segs;
144 	while (lptr) {
145 		lptr2 = lptr;
146 		lptr = lptr->next;
147 		free(lptr2);
148 	}
149 	g_raw = NULL;
150 
151 	return (FRU_SUCCESS);
152 }
153 
154 
155 static fru_errno_t
156 frt_get_root(fru_treehdl_t *node)
157 {
158 	*node = g_raw->hdl;
159 
160 	return (FRU_SUCCESS);
161 }
162 
163 /* ARGSUSED */
164 static fru_errno_t
165 frt_get_peer(fru_treehdl_t sibling, fru_treehdl_t *peer)
166 {
167 	return (FRU_NODENOTFOUND);
168 }
169 /* ARGSUSED */
170 static fru_errno_t
171 frt_get_child(fru_treehdl_t handle, fru_treehdl_t *child)
172 {
173 	return (FRU_NODENOTFOUND);
174 }
175 
176 /* ARGSUSED */
177 static fru_errno_t
178 frt_get_parent(fru_treehdl_t handle, fru_treehdl_t *parent)
179 {
180 	return (FRU_NODENOTFOUND);
181 }
182 
183 /* ARGSUSED */
184 static fru_errno_t
185 frt_get_name_from_hdl(fru_treehdl_t handle, char **name)
186 {
187 	*name = strdup("unknown");
188 	return (FRU_SUCCESS);
189 }
190 
191 /* ARGSUSED */
192 static fru_errno_t
193 frt_get_node_type(fru_treehdl_t node, fru_node_t *type)
194 {
195 	*type = FRU_NODE_CONTAINER;
196 	return (FRU_SUCCESS);
197 }
198 
199 
200 
201 static fru_errno_t
202 add_segs_for_section(section_t *section, fru_strlist_t *list)
203 {
204 	int i = 0;
205 	segment_t *segs = NULL;
206 	int acc_err = 0;
207 
208 	int num_segment = fru_get_num_segments(section->handle, NULL);
209 	if (num_segment == -1) {
210 		return (map_errno(errno));
211 	} else if (num_segment == 0) {
212 		return (FRU_SUCCESS);
213 	}
214 
215 	segs = malloc(sizeof (*segs) * (num_segment));
216 	if (segs == NULL) {
217 		return (FRU_FAILURE);
218 	}
219 
220 	acc_err = fru_get_segments(section->handle, segs, num_segment, NULL);
221 	if (acc_err == -1) {
222 		free(segs);
223 		return (map_errno(errno));
224 	}
225 
226 	list->strs = realloc(list->strs, sizeof (char *)
227 	    * (list->num + num_segment));
228 
229 	for (i = 0; i < num_segment; i++) {
230 		/* ensure NULL terminated. */
231 		char *tmp = malloc(sizeof (*tmp) * (sizeof (segs[i].name)+1));
232 		if (tmp == NULL) {
233 			free(segs);
234 			return (FRU_FAILURE);
235 		}
236 		(void) memcpy(tmp, segs[i].name, sizeof (segs[i].name));
237 		tmp[sizeof (segs[i].name)] = '\0';
238 
239 		list->strs[(list->num)++] = tmp;
240 	}
241 
242 	free(segs);
243 
244 	return (FRU_SUCCESS);
245 }
246 
247 
248 
249 static fru_errno_t
250 frt_get_seg_list(fru_treehdl_t handle, fru_strlist_t *list)
251 {
252 	fru_strlist_t rc_list;
253 	fru_errno_t err = FRU_SUCCESS;
254 	int acc_err = 0;
255 	int i = 0;
256 	int num_section = 0;
257 	section_t *sects = NULL;
258 	container_hdl_t cont;
259 
260 	cont = treehdl_to_conthdl(handle);
261 
262 	num_section = fru_get_num_sections(cont, NULL);
263 	if (num_section == -1) {
264 		return (map_errno(errno));
265 	}
266 
267 	sects = malloc(sizeof (*sects) * (num_section));
268 	if (sects == NULL) {
269 		return (FRU_FAILURE);
270 	}
271 
272 	acc_err = fru_get_sections(cont, sects, num_section, NULL);
273 	if (acc_err == -1) {
274 		free(sects);
275 		return (map_errno(errno));
276 	}
277 
278 	rc_list.num = 0;
279 	rc_list.strs = NULL;
280 	for (i = 0; i < num_section; i++) {
281 		if ((err = add_segs_for_section(&(sects[i]), &rc_list))
282 		    != FRU_SUCCESS) {
283 			fru_destroy_strlist(&rc_list);
284 			free(sects);
285 			return (err);
286 		}
287 	}
288 
289 	list->strs = rc_list.strs;
290 	list->num = rc_list.num;
291 
292 	return (FRU_SUCCESS);
293 }
294 
295 
296 static fru_errno_t
297 find_seg_in_sect(section_t *sect, const char *seg_name, int *prot_flg,
298     segment_t *segment)
299 {
300 	int j = 0;
301 	int acc_err = 0;
302 	segment_t *segs = NULL;
303 
304 	int num_seg = fru_get_num_segments(sect->handle, NULL);
305 	if (num_seg == -1) {
306 		return (FRU_FAILURE);
307 	}
308 
309 	segs = malloc(sizeof (*segs) * (num_seg));
310 	if (segs == NULL) {
311 		return (FRU_FAILURE);
312 	}
313 
314 	acc_err = fru_get_segments(sect->handle, segs, num_seg, NULL);
315 	if (acc_err == -1) {
316 		free(segs);
317 		return (map_errno(errno));
318 	}
319 
320 	for (j = 0; j < num_seg; j++) {
321 		/* NULL terminate */
322 		char tmp[SEG_NAME_LEN+1];
323 		(void) memcpy(tmp, segs[j].name, SEG_NAME_LEN);
324 		tmp[SEG_NAME_LEN] = '\0';
325 		if (strcmp(tmp, seg_name) == 0) {
326 			*segment = segs[j];
327 			*prot_flg = (sect->protection ? 1 : 0);
328 			free(segs);
329 			return (FRU_SUCCESS);
330 		}
331 	}
332 
333 	free(segs);
334 	return (FRU_INVALSEG);
335 }
336 
337 
338 static fru_errno_t
339 find_segment(fru_treehdl_t handle, const char *seg_name, int *prot_flg,
340     segment_t *segment)
341 {
342 	int i = 0;
343 	int acc_err = 0;
344 	section_t *sect = NULL;
345 	container_hdl_t cont;
346 	int num_sect;
347 
348 	cont = treehdl_to_conthdl(handle);
349 
350 	num_sect = fru_get_num_sections(cont, NULL);
351 	if (num_sect == -1) {
352 		return (map_errno(errno));
353 	}
354 
355 	sect = malloc(sizeof (*sect) * (num_sect));
356 	if (sect == NULL) {
357 		return (FRU_FAILURE);
358 	}
359 
360 	acc_err = fru_get_sections(cont, sect, num_sect, NULL);
361 	if (acc_err == -1) {
362 		free(sect);
363 		return (map_errno(errno));
364 	}
365 
366 	for (i = 0; i < num_sect; i++) {
367 		if (find_seg_in_sect(&(sect[i]), seg_name, prot_flg, segment)
368 		    == FRU_SUCCESS) {
369 			free(sect);
370 			return (FRU_SUCCESS);
371 		}
372 	}
373 
374 	free(sect);
375 	return (FRU_INVALSEG);
376 }
377 
378 
379 static fru_errno_t
380 frt_get_seg_def(fru_treehdl_t handle, const char *seg_name, fru_segdef_t *def)
381 {
382 	fru_errno_t err = FRU_SUCCESS;
383 	int prot_flg = 0;
384 	segment_t segment;
385 
386 	if ((err = find_segment(handle, seg_name, &prot_flg, &segment))
387 	    != FRU_SUCCESS) {
388 		return (err);
389 	}
390 
391 	(void) memcpy(def->name, segment.name, SEG_NAME_LEN);
392 	def->name[SEG_NAME_LEN] = '\0';
393 	def->desc.raw_data = segment.descriptor;
394 	def->size = segment.length;
395 	def->address = segment.offset;
396 
397 	if (prot_flg == 0)
398 		def->hw_desc.field.read_only = 0;
399 	else
400 		def->hw_desc.field.read_only = 1;
401 
402 	return (FRU_SUCCESS);
403 
404 }
405 
406 /* ARGSUSED */
407 static fru_errno_t
408 frt_add_seg(fru_treehdl_t handle, fru_segdef_t *def)
409 {
410 	/* NOT SUPPORTED */
411 	return (FRU_NOTSUP);
412 }
413 
414 /* ARGSUSED */
415 static fru_errno_t
416 frt_delete_seg(fru_treehdl_t handle, const char *seg_name)
417 {
418 	/* NOT SUPPORTED */
419 	return (FRU_NOTSUP);
420 }
421 
422 /* ARGSUSED */
423 static fru_errno_t
424 frt_for_each_segment(fru_nodehdl_t node,
425     int (*function)(fru_seghdl_t hdl, void *args), void *args)
426 {
427 	int num_segment;
428 	int cnt;
429 	int num_sect;
430 	int each_seg;
431 	section_t *sects;
432 	segment_t *segs;
433 	segment_list_t *tmp_list;
434 	int acc_err;
435 	int status;
436 	container_hdl_t cont;
437 
438 	cont = g_raw->cont;
439 
440 	num_sect = fru_get_num_sections(cont, NULL);
441 	if (num_sect == -1) {
442 		return (map_errno(errno));
443 	}
444 
445 	sects = malloc((num_sect + 1) * sizeof (section_t));
446 	if (sects == NULL) {
447 		return (FRU_FAILURE);
448 	}
449 	num_sect = fru_get_sections(cont, sects, num_sect, NULL);
450 	if (num_sect == -1) {
451 		free(sects);
452 		return (map_errno(errno));
453 	}
454 	for (cnt = 0; cnt < num_sect; cnt++) {
455 		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
456 		if (num_segment == -1) {
457 			return (map_errno(errno));
458 		} else if (num_segment == 0) {
459 			continue;
460 		}
461 		segs = malloc((num_segment + 1) * sizeof (segment_t));
462 		if (segs == NULL) {
463 			free(sects);
464 			return (FRU_FAILURE);
465 		}
466 		acc_err = fru_get_segments(sects[cnt].handle, segs,
467 		    num_segment, NULL);
468 		if (acc_err == -1) {
469 			free(sects);
470 			free(segs);
471 			return (map_errno(errno));
472 		}
473 		for (each_seg = 0; each_seg < num_segment; each_seg++) {
474 			tmp_list = malloc(sizeof (segment_list_t));
475 			tmp_list->segment = &segs[each_seg];
476 			tmp_list->next = NULL;
477 			if (g_raw->segs == NULL) {
478 				g_raw->segs = tmp_list;
479 			} else {
480 				tmp_list->next = g_raw->segs;
481 				g_raw->segs = tmp_list;
482 			}
483 
484 			if ((status = function(segs[each_seg].handle, args))
485 			    != FRU_SUCCESS) {
486 				free(segs);
487 				free(sects);
488 				return (status);
489 			}
490 		}
491 		free(segs);
492 		free(sects);
493 
494 	}
495 	return (FRU_SUCCESS);
496 }
497 
498 
499 static fru_errno_t
500 frt_get_segment_name(fru_seghdl_t node, char **name)
501 {
502 	int num_sect;
503 	int acc_err;
504 	int cnt;
505 	int num_segment;
506 	section_t *sects;
507 	segment_t *segs;
508 	int each_seg;
509 	container_hdl_t cont;
510 
511 	cont = treehdl_to_conthdl(node);
512 
513 	num_sect = fru_get_num_sections(cont, NULL);
514 	if (num_sect == -1) {
515 		return (map_errno(errno));
516 	}
517 
518 	sects = malloc(sizeof (*sects) * (num_sect));
519 	if (sects == NULL) {
520 		return (FRU_FAILURE);
521 	}
522 	acc_err = fru_get_sections(cont, sects, num_sect, NULL);
523 	if (acc_err == -1) {
524 		free(sects);
525 		return (map_errno(errno));
526 	}
527 
528 	for (cnt = 0; cnt < num_sect; cnt++) {
529 		num_segment = fru_get_num_segments(sects[cnt].handle, NULL);
530 		if (num_segment == -1) {
531 			free(sects);
532 			return (map_errno(errno));
533 		} else if (num_segment == 0) {
534 			continue;
535 		}
536 
537 		segs = malloc(sizeof (*segs) * (num_segment));
538 		if (segs == NULL) {
539 			free(sects);
540 			return (FRU_FAILURE);
541 		}
542 
543 		acc_err = fru_get_segments(sects[cnt].handle, segs,
544 		    num_segment, NULL);
545 		if (acc_err == -1) {
546 			free(sects);
547 			free(segs);
548 			return (map_errno(errno));
549 		}
550 
551 		for (each_seg = 0; each_seg < num_segment; each_seg++) {
552 			if (segs[each_seg].handle == node) {
553 				segs[each_seg].name[FRU_SEGNAMELEN] = '\0';
554 				*name = segs[each_seg].name;
555 				free(sects);
556 				return (FRU_SUCCESS);
557 			}
558 		}
559 		free(segs);
560 	}
561 
562 	return (FRU_FAILURE);
563 }
564 
565 
566 /* ARGSUSED */
567 static fru_errno_t
568 frt_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 */
577 static fru_errno_t
578 frt_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 */
587 static fru_errno_t
588 frt_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 */
598 static fru_errno_t
599 frt_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 */
609 static fru_errno_t
610 frt_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 
618 static fru_errno_t
619 frt_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 */
714 fru_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