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