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 == NULL) {
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 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
frt_add_tag_to_seg(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,uint8_t * data,size_t data_len)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
frt_get_tag_list(fru_treehdl_t handle,const char * seg_name,fru_tag_t ** tags,int * number)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
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)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
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)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
frt_delete_tag(fru_treehdl_t handle,const char * seg_name,fru_tag_t tag,int instance)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
frt_for_each_packet(fru_seghdl_t node,int (* function)(fru_tag_t * tag,uint8_t * payload,size_t length,void * args),void * args)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