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 *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 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 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 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 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 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 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