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 
40 raw_list_t *g_raw = NULL;
41 
42 
43 /* ARGSUSED */
44 static raw_list_t *
45 treehdl_to_rawlist(fru_treehdl_t handle)
46 {
47 	return (g_raw);
48 }
49 
50 
51 static container_hdl_t
52 treehdl_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 
65 static fru_errno_t
66 map_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 
82 static raw_list_t *
83 make_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  */
112 static fru_errno_t
113 frt_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 == 0) {
128 		return (FRU_FAILURE);
129 	}
130 
131 	return (FRU_SUCCESS);
132 }
133 
134 
135 static fru_errno_t
136 frt_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 
154 static fru_errno_t
155 frt_get_root(fru_treehdl_t *node)
156 {
157 	*node = g_raw->hdl;
158 
159 	return (FRU_SUCCESS);
160 }
161 
162 /* ARGSUSED */
163 static fru_errno_t
164 frt_get_peer(fru_treehdl_t sibling, fru_treehdl_t *peer)
165 {
166 	return (FRU_NODENOTFOUND);
167 }
168 /* ARGSUSED */
169 static fru_errno_t
170 frt_get_child(fru_treehdl_t handle, fru_treehdl_t *child)
171 {
172 	return (FRU_NODENOTFOUND);
173 }
174 
175 /* ARGSUSED */
176 static fru_errno_t
177 frt_get_parent(fru_treehdl_t handle, fru_treehdl_t *parent)
178 {
179 	return (FRU_NODENOTFOUND);
180 }
181 
182 /* ARGSUSED */
183 static fru_errno_t
184 frt_get_name_from_hdl(fru_treehdl_t handle, char **name)
185 {
186 	*name = strdup("unknown");
187 	return (FRU_SUCCESS);
188 }
189 
190 /* ARGSUSED */
191 static fru_errno_t
192 frt_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 
200 static fru_errno_t
201 add_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 
248 static fru_errno_t
249 frt_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 
295 static fru_errno_t
296 find_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 
337 static fru_errno_t
338 find_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 
378 static fru_errno_t
379 frt_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 */
406 static fru_errno_t
407 frt_add_seg(fru_treehdl_t handle, fru_segdef_t *def)
408 {
409 	/* NOT SUPPORTED */
410 	return (FRU_NOTSUP);
411 }
412 
413 /* ARGSUSED */
414 static fru_errno_t
415 frt_delete_seg(fru_treehdl_t handle, const char *seg_name)
416 {
417 	/* NOT SUPPORTED */
418 	return (FRU_NOTSUP);
419 }
420 
421 /* ARGSUSED */
422 static fru_errno_t
423 frt_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 
498 static fru_errno_t
499 frt_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 */
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, fru_tag_t tag,
589     int instance, uint8_t **data, size_t *data_len)
590 {
591 	/* NOT SUPPORTED */
592 	return (FRU_NOTSUP);
593 }
594 
595 
596 /* ARGSUSED */
597 static fru_errno_t
598 frt_set_tag_data(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
599     int instance, uint8_t *data, size_t data_len)
600 {
601 	/* NOT SUPPORTED */
602 	return (FRU_NOTSUP);
603 }
604 
605 
606 /* ARGSUSED */
607 static fru_errno_t
608 frt_delete_tag(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
609     int instance)
610 {
611 	/* NOT SUPPORTED */
612 	return (FRU_NOTSUP);
613 }
614 
615 
616 static fru_errno_t
617 frt_for_each_packet(fru_seghdl_t node, int (*function)(fru_tag_t *tag,
618     uint8_t *payload, size_t length, void *args), void *args)
619 {
620 	int rc_num;
621 	int status;
622 	char *rc_data;
623 	int i;
624 	packet_t *packets = NULL;
625 	segment_list_t *tmp_list;
626 	fru_segdesc_t *descriptor;
627 
628 	tmp_list = g_raw->segs;
629 
630 	/* num of packet */
631 	rc_num = fru_get_num_packets(node, NULL);
632 	if (rc_num == -1) {
633 		return (map_errno(errno));
634 	} else if (rc_num == 0) {
635 		return (FRU_SUCCESS);
636 	}
637 	while (tmp_list) {
638 		if (node == tmp_list->segment->handle) {
639 			break;
640 		}
641 		tmp_list = tmp_list->next;
642 	}
643 	if (tmp_list) {
644 		descriptor = (fru_segdesc_t *)&tmp_list->segment->descriptor;
645 		if (descriptor->field.opaque) {
646 			return (FRU_SUCCESS);
647 		}
648 
649 		if (descriptor->field.encrypted && (encrypt_func == NULL)) {
650 			return (FRU_SUCCESS);
651 		}
652 	}
653 
654 	packets = malloc(sizeof (*packets) * (rc_num));
655 	if (packets == NULL) {
656 		return (FRU_FAILURE);
657 	}
658 	/* get all packets */
659 	if (fru_get_packets(node, packets, rc_num, NULL) == -1) {
660 		free(packets);
661 		return (map_errno(errno));
662 	}
663 
664 	/* number of tags */
665 	for (i = 0; i < rc_num; i++) {
666 		size_t rc_len =
667 		    get_payload_length((fru_tag_t *)&packets[i].tag);
668 
669 		rc_data = malloc(sizeof (*rc_data) * (rc_len));
670 		if (rc_data == NULL) {
671 			free(packets);
672 			return (FRU_FAILURE);
673 		}
674 		/* get the payload data */
675 		(void) fru_get_payload(packets[i].handle, (void *)rc_data,
676 		    rc_len, NULL);
677 
678 		if (tmp_list) {
679 			descriptor =
680 			    (fru_segdesc_t *)&tmp_list->segment->descriptor;
681 
682 			if ((descriptor->field.encrypted) &&
683 			    ((status = encrypt_func(FRU_DECRYPT,
684 			    (void *)rc_data, rc_len))
685 			    != FRU_SUCCESS)) {
686 				return (status);
687 			}
688 		}
689 		/* print packet */
690 		if ((status = function((fru_tag_t *)&packets[i].tag,
691 		    (uint8_t *)rc_data, rc_len, args)) != FRU_SUCCESS) {
692 			free(rc_data);
693 			free(packets);
694 			return (status);
695 		}
696 		free(rc_data);
697 	}
698 	return (FRU_SUCCESS);
699 
700 }
701 
702 
703 /* object for libfru to link to */
704 fru_datasource_t data_source =
705 {
706 	LIBFRU_DS_VER,
707 	frt_initialize,
708 	frt_shutdown,
709 	frt_get_root,
710 	frt_get_child,
711 	frt_get_peer,
712 	frt_get_parent,
713 	frt_get_name_from_hdl,
714 	frt_get_node_type,
715 	frt_get_seg_list,
716 	frt_get_seg_def,
717 	frt_add_seg,
718 	frt_delete_seg,
719 	frt_for_each_segment,
720 	frt_get_segment_name,
721 	frt_add_tag_to_seg,
722 	frt_get_tag_list,
723 	frt_get_tag_data,
724 	frt_set_tag_data,
725 	frt_delete_tag,
726 	frt_for_each_packet
727 };
728