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 *
treehdl_to_rawlist(fru_treehdl_t handle)45 treehdl_to_rawlist(fru_treehdl_t handle)
46 {
47 	return (g_raw);
48 }
49 
50 
51 static container_hdl_t
treehdl_to_conthdl(fru_treehdl_t handle)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
map_errno(int err)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 *
make_raw(uint8_t * buffer,size_t size,char * cont_type)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
frt_initialize(int num,char ** args)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
frt_shutdown(void)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
frt_get_root(fru_treehdl_t * node)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
frt_get_peer(fru_treehdl_t sibling,fru_treehdl_t * peer)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
frt_get_child(fru_treehdl_t handle,fru_treehdl_t * child)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
frt_get_parent(fru_treehdl_t handle,fru_treehdl_t * parent)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
frt_get_name_from_hdl(fru_treehdl_t handle,char ** name)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
frt_get_node_type(fru_treehdl_t node,fru_node_t * type)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
add_segs_for_section(section_t * section,fru_strlist_t * list)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
frt_get_seg_list(fru_treehdl_t handle,fru_strlist_t * list)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
find_seg_in_sect(section_t * sect,const char * seg_name,int * prot_flg,segment_t * segment)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
find_segment(fru_treehdl_t handle,const char * seg_name,int * prot_flg,segment_t * segment)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
frt_get_seg_def(fru_treehdl_t handle,const char * seg_name,fru_segdef_t * def)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
frt_add_seg(fru_treehdl_t handle,fru_segdef_t * def)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
frt_delete_seg(fru_treehdl_t handle,const char * seg_name)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
frt_for_each_segment(fru_nodehdl_t node,int (* function)(fru_seghdl_t hdl,void * args),void * args)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
frt_get_segment_name(fru_seghdl_t node,char ** name)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 				*name = malloc(SEG_NAME_LEN + 1);
553 				if (*name != NULL) {
554 					(void) memcpy(*name,
555 					    segs[each_seg].name,
556 					    SEG_NAME_LEN);
557 					*name[SEG_NAME_LEN] = '\0';
558 				}
559 				free(sects);
560 				free(segs);
561 				if (*name == NULL)
562 					return (FRU_FAILURE);
563 				return (FRU_SUCCESS);
564 			}
565 		}
566 		free(segs);
567 	}
568 
569 	return (FRU_FAILURE);
570 }
571 
572 
573 /* ARGSUSED */
574 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)575 frt_add_tag_to_seg(fru_treehdl_t handle, const char *seg_name,
576     fru_tag_t tag, uint8_t *data, size_t data_len)
577 {
578 	/* NOT SUPPORTED */
579 	return (FRU_NOTSUP);
580 }
581 
582 
583 /* ARGSUSED */
584 static fru_errno_t
frt_get_tag_list(fru_treehdl_t handle,const char * seg_name,fru_tag_t ** tags,int * number)585 frt_get_tag_list(fru_treehdl_t handle, const char *seg_name,
586     fru_tag_t **tags, int *number)
587 {
588 	/* NOT SUPPORTED */
589 	return (FRU_NOTSUP);
590 }
591 
592 
593 /* ARGSUSED */
594 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)595 frt_get_tag_data(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
596     int instance, uint8_t **data, size_t *data_len)
597 {
598 	/* NOT SUPPORTED */
599 	return (FRU_NOTSUP);
600 }
601 
602 
603 /* ARGSUSED */
604 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)605 frt_set_tag_data(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
606     int instance, uint8_t *data, size_t data_len)
607 {
608 	/* NOT SUPPORTED */
609 	return (FRU_NOTSUP);
610 }
611 
612 
613 /* ARGSUSED */
614 static fru_errno_t
frt_delete_tag(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,int instance)615 frt_delete_tag(fru_treehdl_t handle, const char *seg_name, fru_tag_t tag,
616     int instance)
617 {
618 	/* NOT SUPPORTED */
619 	return (FRU_NOTSUP);
620 }
621 
622 
623 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)624 frt_for_each_packet(fru_seghdl_t node, int (*function)(fru_tag_t *tag,
625     uint8_t *payload, size_t length, void *args), void *args)
626 {
627 	int rc_num;
628 	int status;
629 	char *rc_data;
630 	int i;
631 	packet_t *packets = NULL;
632 	segment_list_t *tmp_list;
633 	fru_segdesc_t *descriptor;
634 
635 	tmp_list = g_raw->segs;
636 
637 	/* num of packet */
638 	rc_num = fru_get_num_packets(node, NULL);
639 	if (rc_num == -1) {
640 		return (map_errno(errno));
641 	} else if (rc_num == 0) {
642 		return (FRU_SUCCESS);
643 	}
644 	while (tmp_list) {
645 		if (node == tmp_list->segment->handle) {
646 			break;
647 		}
648 		tmp_list = tmp_list->next;
649 	}
650 	if (tmp_list) {
651 		descriptor = (fru_segdesc_t *)&tmp_list->segment->descriptor;
652 		if (descriptor->field.opaque) {
653 			return (FRU_SUCCESS);
654 		}
655 
656 		if (descriptor->field.encrypted && (encrypt_func == NULL)) {
657 			return (FRU_SUCCESS);
658 		}
659 	}
660 
661 	packets = malloc(sizeof (*packets) * (rc_num));
662 	if (packets == NULL) {
663 		return (FRU_FAILURE);
664 	}
665 	/* get all packets */
666 	if (fru_get_packets(node, packets, rc_num, NULL) == -1) {
667 		free(packets);
668 		return (map_errno(errno));
669 	}
670 
671 	/* number of tags */
672 	for (i = 0; i < rc_num; i++) {
673 		size_t rc_len =
674 		    get_payload_length((fru_tag_t *)&packets[i].tag);
675 
676 		rc_data = malloc(sizeof (*rc_data) * (rc_len));
677 		if (rc_data == NULL) {
678 			free(packets);
679 			return (FRU_FAILURE);
680 		}
681 		/* get the payload data */
682 		(void) fru_get_payload(packets[i].handle, (void *)rc_data,
683 		    rc_len, NULL);
684 
685 		if (tmp_list) {
686 			descriptor =
687 			    (fru_segdesc_t *)&tmp_list->segment->descriptor;
688 
689 			if ((descriptor->field.encrypted) &&
690 			    ((status = encrypt_func(FRU_DECRYPT,
691 			    (void *)rc_data, rc_len))
692 			    != FRU_SUCCESS)) {
693 				return (status);
694 			}
695 		}
696 		/* print packet */
697 		if ((status = function((fru_tag_t *)&packets[i].tag,
698 		    (uint8_t *)rc_data, rc_len, args)) != FRU_SUCCESS) {
699 			free(rc_data);
700 			free(packets);
701 			return (status);
702 		}
703 		free(rc_data);
704 	}
705 	return (FRU_SUCCESS);
706 
707 }
708 
709 
710 /* object for libfru to link to */
711 fru_datasource_t data_source =
712 {
713 	LIBFRU_DS_VER,
714 	frt_initialize,
715 	frt_shutdown,
716 	frt_get_root,
717 	frt_get_child,
718 	frt_get_peer,
719 	frt_get_parent,
720 	frt_get_name_from_hdl,
721 	frt_get_node_type,
722 	frt_get_seg_list,
723 	frt_get_seg_def,
724 	frt_add_seg,
725 	frt_delete_seg,
726 	frt_for_each_segment,
727 	frt_get_segment_name,
728 	frt_add_tag_to_seg,
729 	frt_get_tag_list,
730 	frt_get_tag_data,
731 	frt_set_tag_data,
732 	frt_delete_tag,
733 	frt_for_each_packet
734 };
735