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 <stdlib.h>
28 #include <alloca.h>
29 #include <sys/byteorder.h>
30 #include "fru_access_impl.h"
31 #include "fruraw.h"
32
33 #pragma init(initialize_raw_access)
34
35 static hash_obj_t *hash_table[TABLE_SIZE];
36 extern raw_list_t *g_raw;
37
38 static void
initialize_raw_access(void)39 initialize_raw_access(void)
40 {
41 int count;
42
43 for (count = 0; count < TABLE_SIZE; count++) {
44 hash_table[count] = NULL;
45 }
46 }
47
48
49 static hash_obj_t *
lookup_handle_object(handle_t handle,int object_type)50 lookup_handle_object(handle_t handle, int object_type)
51 {
52 handle_t index_to_hash;
53 hash_obj_t *first_hash_obj;
54 hash_obj_t *next_hash_obj;
55
56 index_to_hash = (handle % TABLE_SIZE);
57
58 first_hash_obj = hash_table[index_to_hash];
59 for (next_hash_obj = first_hash_obj; next_hash_obj != NULL;
60 next_hash_obj = next_hash_obj->next) {
61 if ((handle == next_hash_obj->obj_hdl) &&
62 (object_type == next_hash_obj->object_type)) {
63 return (next_hash_obj);
64 }
65 }
66 return (NULL);
67 }
68
69
70 static void
add_hashobject_to_hashtable(hash_obj_t * hash_obj)71 add_hashobject_to_hashtable(hash_obj_t *hash_obj)
72 {
73 handle_t index_to_hash;
74 static uint64_t handle_count = 0;
75
76 hash_obj->obj_hdl = ++handle_count; /* store the handle */
77
78 /* where to add ? */
79 index_to_hash = ((hash_obj->obj_hdl) % TABLE_SIZE);
80
81 hash_obj->next = hash_table[index_to_hash];
82 hash_table[index_to_hash] = hash_obj; /* hash obj. added */
83
84 if (hash_obj->next != NULL) {
85 hash_obj->next->prev = hash_obj;
86 }
87 }
88
89
90 static hash_obj_t *
create_container_hash_object(void)91 create_container_hash_object(void)
92 {
93 hash_obj_t *hash_obj;
94 container_obj_t *cont_obj;
95
96 cont_obj = malloc(sizeof (container_obj_t));
97 if (cont_obj == NULL) {
98 return (NULL);
99 }
100
101 hash_obj = malloc(sizeof (hash_obj_t));
102 if (hash_obj == NULL) {
103 free(cont_obj);
104 return (NULL);
105 }
106
107 cont_obj->sec_obj_list = NULL;
108
109 hash_obj->object_type = CONTAINER_TYPE;
110 hash_obj->u.cont_obj = cont_obj;
111 hash_obj->next = NULL;
112 hash_obj->prev = NULL;
113
114 return (hash_obj);
115 }
116
117
118 static hash_obj_t *
create_section_hash_object(void)119 create_section_hash_object(void)
120 {
121 hash_obj_t *hash_obj;
122 section_obj_t *sec_obj;
123
124 sec_obj = malloc(sizeof (section_obj_t));
125 if (sec_obj == NULL) {
126 return (NULL);
127 }
128
129 hash_obj = malloc(sizeof (hash_obj_t));
130 if (hash_obj == NULL) {
131 free(sec_obj);
132 return (NULL);
133 }
134
135 sec_obj->next = NULL;
136 sec_obj->seg_obj_list = NULL;
137
138 hash_obj->u.sec_obj = sec_obj;
139 hash_obj->object_type = SECTION_TYPE;
140 hash_obj->next = NULL;
141 hash_obj->prev = NULL;
142
143 return (hash_obj);
144 }
145
146
147 static hash_obj_t *
create_segment_hash_object(void)148 create_segment_hash_object(void)
149 {
150 hash_obj_t *hash_obj;
151 segment_obj_t *seg_obj;
152
153 seg_obj = malloc(sizeof (segment_obj_t));
154 if (seg_obj == NULL) {
155 return (NULL);
156 }
157
158 hash_obj = malloc(sizeof (hash_obj_t));
159 if (hash_obj == NULL) {
160 free(seg_obj);
161 return (NULL);
162 }
163
164 seg_obj->next = NULL;
165 seg_obj->pkt_obj_list = NULL;
166
167 hash_obj->object_type = SEGMENT_TYPE;
168 hash_obj->u.seg_obj = seg_obj;
169 hash_obj->next = NULL;
170 hash_obj->prev = NULL;
171
172 return (hash_obj);
173 }
174
175
176 static hash_obj_t *
create_packet_hash_object(void)177 create_packet_hash_object(void)
178 {
179 hash_obj_t *hash_obj;
180 packet_obj_t *pkt_obj;
181
182 pkt_obj = malloc(sizeof (packet_obj_t));
183 if (pkt_obj == NULL) {
184 return (NULL);
185 }
186
187 hash_obj = malloc(sizeof (hash_obj_t));
188 if (hash_obj == NULL) {
189 free(pkt_obj);
190 return (NULL);
191 }
192
193 pkt_obj->next = NULL;
194
195 hash_obj->object_type = PACKET_TYPE;
196 hash_obj->u.pkt_obj = pkt_obj;
197 hash_obj->next = NULL;
198 hash_obj->prev = NULL;
199
200 return (hash_obj);
201 }
202
203
204
205 static hash_obj_t *
get_container_hash_object(int object_type,handle_t handle)206 get_container_hash_object(int object_type, handle_t handle)
207 {
208 hash_obj_t *hash_obj;
209
210 switch (object_type) {
211 case CONTAINER_TYPE:
212 break;
213 case SECTION_TYPE:
214 hash_obj = lookup_handle_object(handle, CONTAINER_TYPE);
215 if (hash_obj == NULL) {
216 return (NULL);
217 }
218 break;
219 case SEGMENT_TYPE:
220 hash_obj = lookup_handle_object(handle, SECTION_TYPE);
221 if (hash_obj == NULL) {
222 return (NULL);
223 }
224 hash_obj = lookup_handle_object(hash_obj->u.sec_obj->cont_hdl,
225 CONTAINER_TYPE);
226 break;
227 case PACKET_TYPE:
228 break;
229 default:
230 return (NULL);
231 }
232
233 return (hash_obj);
234 }
235
236
237 static void
add_to_pkt_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)238 add_to_pkt_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
239 {
240 hash_obj_t *next_hash;
241
242 /* add the packet object in the end of list */
243 child_obj->u.pkt_obj->segment_hdl = parent_obj->obj_hdl;
244
245 if (parent_obj->u.seg_obj->pkt_obj_list == NULL) {
246 parent_obj->u.seg_obj->pkt_obj_list = child_obj;
247 return;
248 }
249
250 for (next_hash = parent_obj->u.seg_obj->pkt_obj_list;
251 next_hash->u.pkt_obj->next != NULL;
252 next_hash = next_hash->u.pkt_obj->next) {
253 ;
254 }
255
256 next_hash->u.pkt_obj->next = child_obj;
257 }
258
259
260 static void
free_pkt_object_list(hash_obj_t * hash_obj)261 free_pkt_object_list(hash_obj_t *hash_obj)
262 {
263 hash_obj_t *next_obj;
264 hash_obj_t *free_obj;
265
266 next_obj = hash_obj->u.seg_obj->pkt_obj_list;
267 while (next_obj != NULL) {
268 free_obj = next_obj;
269 next_obj = next_obj->u.pkt_obj->next;
270 /* if prev is NULL it's the first object in the list */
271 if (free_obj->prev == NULL) {
272 hash_table[(free_obj->obj_hdl % TABLE_SIZE)] =
273 free_obj->next;
274 if (free_obj->next != NULL) {
275 free_obj->next->prev = free_obj->prev;
276 }
277 } else {
278 free_obj->prev->next = free_obj->next;
279 if (free_obj->next != NULL) {
280 free_obj->next->prev = free_obj->prev;
281 }
282 }
283
284 free(free_obj->u.pkt_obj->payload);
285 free(free_obj->u.pkt_obj);
286 free(free_obj);
287 }
288
289 hash_obj->u.seg_obj->pkt_obj_list = NULL;
290 }
291
292
293 static void
free_segment_hash(handle_t handle,hash_obj_t * sec_hash)294 free_segment_hash(handle_t handle, hash_obj_t *sec_hash)
295 {
296 hash_obj_t *seg_hash;
297 hash_obj_t *next_hash;
298
299 seg_hash = sec_hash->u.sec_obj->seg_obj_list;
300 if (seg_hash == NULL) {
301 return;
302 }
303
304 if (seg_hash->obj_hdl == handle) {
305 sec_hash->u.sec_obj->seg_obj_list = seg_hash->u.seg_obj->next;
306 } else {
307 while (seg_hash->obj_hdl != handle) {
308 next_hash = seg_hash;
309 seg_hash = seg_hash->u.seg_obj->next;
310 if (seg_hash == NULL) {
311 return;
312 }
313 }
314 next_hash->u.seg_obj->next = seg_hash->u.seg_obj->next;
315 }
316
317 if (seg_hash->prev == NULL) {
318 hash_table[(seg_hash->obj_hdl % TABLE_SIZE)] = seg_hash->next;
319 if (seg_hash->next != NULL) {
320 seg_hash->next->prev = NULL;
321 }
322 } else {
323 seg_hash->prev->next = seg_hash->next;
324 if (seg_hash->next != NULL) {
325 seg_hash->next->prev = seg_hash->prev;
326 }
327 }
328
329 free_pkt_object_list(seg_hash);
330 free(seg_hash->u.seg_obj);
331 free(seg_hash);
332 }
333
334
335
336 static void
add_to_sec_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)337 add_to_sec_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
338 {
339 hash_obj_t *next_hash;
340
341 child_obj->u.sec_obj->cont_hdl = parent_obj->obj_hdl;
342 if (parent_obj->u.cont_obj->sec_obj_list == NULL) {
343 parent_obj->u.cont_obj->sec_obj_list = child_obj;
344 return;
345 }
346
347 for (next_hash = parent_obj->u.cont_obj->sec_obj_list;
348 next_hash->u.sec_obj->next != NULL;
349 next_hash = next_hash->u.sec_obj->next) {
350 ;
351 }
352
353 next_hash->u.sec_obj->next = child_obj;
354 }
355
356
357 static void
add_to_seg_object_list(hash_obj_t * parent_obj,hash_obj_t * child_obj)358 add_to_seg_object_list(hash_obj_t *parent_obj, hash_obj_t *child_obj)
359 {
360 hash_obj_t *next_hash;
361
362 child_obj->u.seg_obj->section_hdl = parent_obj->obj_hdl;
363 if (parent_obj->u.sec_obj->seg_obj_list == NULL) {
364 parent_obj->u.sec_obj->seg_obj_list = child_obj;
365 return;
366 }
367
368 for (next_hash = parent_obj->u.sec_obj->seg_obj_list;
369 next_hash->u.seg_obj->next != NULL;
370 next_hash = next_hash->u.seg_obj->next) {
371 ;
372 }
373
374 next_hash->u.seg_obj->next = child_obj;
375 }
376
377
378 static char *
tokenizer(char * buf,char * separator,char ** nextBuf,char * matched)379 tokenizer(char *buf, char *separator, char **nextBuf, char *matched)
380 {
381 int i = 0;
382 int j = 0;
383
384 for (i = 0; buf[i] != '\0'; i++) {
385 for (j = 0; j < strlen(separator); j++) {
386 if (buf[i] == separator[j]) {
387 buf[i] = '\0';
388 *nextBuf = &(buf[i+1]);
389 *matched = separator[j];
390 return (buf);
391 }
392 }
393 }
394
395 *nextBuf = buf;
396 *matched = '\0';
397 return (NULL);
398 }
399
400
401 static void
copy_segment_layout(segment_t * seghdr,void * layout)402 copy_segment_layout(segment_t *seghdr, void *layout)
403 {
404 segment_layout_t *seg_layout;
405
406 seg_layout = (segment_layout_t *)layout;
407 (void) memcpy(seghdr->name, &seg_layout->name, SEG_NAME_LEN);
408 seghdr->descriptor = GET_SEGMENT_DESCRIPTOR;
409 seghdr->offset = BE_16(seg_layout->offset);
410 seghdr->length = BE_16(seg_layout->length);
411 }
412
413
414 static int
get_container_info(const char * def_file,const char * cont_desc_str,container_info_t * cont_info)415 get_container_info(const char *def_file, const char *cont_desc_str,
416 container_info_t *cont_info)
417 {
418 char *item;
419 char *token;
420 char *field;
421 char matched;
422 char buf[1024];
423 int foundIt = 0;
424 FILE *file = fopen(def_file, "r");
425
426 if (file == NULL)
427 return (-1);
428
429 cont_info->num_sections = 0;
430
431 while (fgets(buf, sizeof (buf), file) != NULL) {
432 /* ignore all comments */
433 token = tokenizer(buf, "#", &field, &matched);
434 /* find the names */
435 token = tokenizer(buf, ":", &field, &matched);
436 if (token != 0x00) {
437 token = tokenizer(token, "|", &item, &matched);
438 while (token != 0x00) {
439 if (strcmp(token, cont_desc_str) == 0) {
440 foundIt = 1;
441 goto found;
442 }
443 token = tokenizer(item, "|", &item, &matched);
444 }
445 /* check the last remaining item */
446 if ((item != 0x00) &&
447 (strcmp(item, cont_desc_str) == 0)) {
448 foundIt = 1;
449 goto found;
450 }
451 }
452 }
453
454 found :
455 if (foundIt == 1) {
456 token = tokenizer(field, ":", &field, &matched);
457 if (token == 0x00) {
458 (void) fclose(file);
459 return (-1);
460 }
461 cont_info->header_ver = (headerrev_t)atoi(token);
462
463 token = tokenizer(field, ":\n", &field, &matched);
464 while (token != 0x00) {
465 token = tokenizer(token, ",", &item, &matched);
466 if (token == 0x00) {
467 (void) fclose(file);
468 return (-1);
469 }
470 if (atoi(token) == 1) {
471 cont_info->section_info[cont_info->
472 num_sections].description.field.read_only
473 = 1;
474 } else if (atoi(token) == 0) {
475 cont_info->section_info[cont_info->
476 num_sections].description.field.read_only
477 = 0;
478 } else {
479 (void) fclose(file);
480 return (-1);
481 }
482
483 token = tokenizer(item, ",", &item, &matched);
484 if (token == 0x00) {
485 (void) fclose(file);
486 return (-1);
487 }
488
489 cont_info->section_info[cont_info->
490 num_sections].address = atoi(token);
491 if (item == '\0') {
492 (void) fclose(file);
493 return (-1);
494 }
495 cont_info->section_info[cont_info->num_sections].size =
496 atoi(item);
497 (cont_info->num_sections)++;
498
499 token = tokenizer(field, ":\n ", &field, &matched);
500 }
501 }
502 (void) fclose(file);
503
504 return (0);
505 }
506
507
508 /* ARGSUSED */
509 int
fru_get_segments(section_hdl_t section,segment_t * segment,int maxseg,door_cred_t * cred)510 fru_get_segments(section_hdl_t section, segment_t *segment, int maxseg,
511 door_cred_t *cred)
512 {
513 int count;
514 hash_obj_t *sec_object;
515 hash_obj_t *seg_object;
516 section_obj_t *sec_obj;
517
518 sec_object = lookup_handle_object(section, SECTION_TYPE);
519 if (sec_object == NULL) {
520 return (-1);
521 }
522
523 sec_obj = sec_object->u.sec_obj;
524 if (sec_obj == NULL) {
525 return (-1);
526 }
527
528 if (sec_obj->num_of_segment > maxseg) {
529 return (-1);
530 }
531
532 seg_object = sec_object->u.sec_obj->seg_obj_list;
533 if (seg_object == NULL) {
534 return (-1);
535 }
536
537 for (count = 0; count < sec_obj->num_of_segment; count++) {
538
539 /* populate segment_t */
540 segment->handle = seg_object->obj_hdl;
541 (void) memcpy(segment->name,
542 seg_object->u.seg_obj->segment.name, SEG_NAME_LEN);
543 segment->descriptor = seg_object->u.seg_obj->segment.descriptor;
544
545 segment->offset = seg_object->u.seg_obj->segment.offset;
546 segment->length = seg_object->u.seg_obj->segment.length;
547 seg_object = seg_object->u.seg_obj->next;
548 segment++;
549 }
550 return (0);
551 }
552
553
554 static int
raw_memcpy(void * buffer,raw_list_t * rawlist,int offset,int size)555 raw_memcpy(void *buffer, raw_list_t *rawlist, int offset, int size)
556 {
557 if (offset + size > rawlist->size) {
558 size = rawlist->size - offset;
559 }
560
561 (void) memcpy(buffer, &rawlist->raw[offset], size);
562
563 return (size);
564 }
565
566
567 static int
verify_header_crc8(headerrev_t head_ver,unsigned char * bytes,int length)568 verify_header_crc8(headerrev_t head_ver, unsigned char *bytes, int length)
569 {
570 int crc_offset = 0;
571 unsigned char orig_crc8 = 0;
572 unsigned char calc_crc8 = 0;
573
574 switch (head_ver) {
575 case SECTION_HDR_VER:
576 crc_offset = 4;
577 break;
578 default:
579 errno = EINVAL;
580 return (0);
581 }
582
583 orig_crc8 = bytes[crc_offset];
584 bytes[crc_offset] = 0x00; /* clear for calc */
585 calc_crc8 = compute_crc8(bytes, length);
586 bytes[crc_offset] = orig_crc8; /* restore */
587
588 return (orig_crc8 == calc_crc8);
589 }
590
591
592 static int
get_section(raw_list_t * rawlist,hash_obj_t * sec_hash,section_t * section)593 get_section(raw_list_t *rawlist, hash_obj_t *sec_hash, section_t *section)
594 {
595 int retval;
596 int size;
597 int count;
598 uint16_t hdrver;
599 hash_obj_t *seg_hash;
600 unsigned char *buffer;
601 section_obj_t *sec_obj;
602 section_layout_t sec_hdr;
603 segment_layout_t *seg_hdr;
604 segment_layout_t *seg_buf;
605
606 sec_obj = sec_hash->u.sec_obj;
607 if (sec_obj == NULL) {
608 return (-1);
609 }
610
611 /* populate section_t */
612 section->handle = sec_hash->obj_hdl;
613 section->offset = sec_obj->section.offset;
614 section->length = sec_obj->section.length;
615 section->protection = sec_obj->section.protection;
616 section->version = sec_obj->section.version;
617
618 /* read section header layout */
619 retval = raw_memcpy(&sec_hdr, rawlist, sec_obj->section.offset,
620 sizeof (sec_hdr));
621
622 if (retval != sizeof (sec_hdr)) {
623 return (-1);
624 }
625
626
627 hdrver = GET_SECTION_HDR_VERSION;
628
629 if ((sec_hdr.headertag != SECTION_HDR_TAG) &&
630 (hdrver != section->version)) {
631 return (-1);
632 }
633
634 /* size = section layout + total sizeof segment header */
635 size = sizeof (sec_hdr) + ((sec_hdr.segmentcount)
636 * sizeof (segment_layout_t));
637
638 buffer = alloca(size);
639 if (buffer == NULL) {
640 return (-1);
641 }
642
643 /* segment header buffer */
644 seg_buf = alloca(size - sizeof (sec_hdr));
645 if (seg_buf == NULL) {
646 return (-1);
647 }
648
649 /* read segment header */
650 retval = raw_memcpy(seg_buf, rawlist,
651 sec_obj->section.offset + sizeof (sec_hdr),
652 size - sizeof (sec_hdr));
653
654 if (retval != (size - sizeof (sec_hdr))) {
655 return (-1);
656 }
657
658 /* copy section header layout */
659 (void) memcpy(buffer, &sec_hdr, sizeof (sec_hdr));
660
661 /* copy segment header layout */
662 (void) memcpy(buffer + sizeof (sec_hdr), seg_buf, size -
663 sizeof (sec_hdr));
664
665 /* verify crc8 */
666 retval = verify_header_crc8(hdrver, buffer, size);
667 if (retval != TRUE) {
668 return (-1);
669 }
670
671 section->version = hdrver;
672 sec_obj->section.version = hdrver;
673
674 seg_hdr = (segment_layout_t *)seg_buf;
675
676 /* bug fix for frutool */
677 if (sec_hash->u.sec_obj->seg_obj_list != NULL) {
678 return (0);
679 } else {
680 sec_obj->num_of_segment = 0;
681 }
682 for (count = 0; count < sec_hdr.segmentcount; count++, seg_hdr++) {
683
684 seg_hash = create_segment_hash_object();
685 if (seg_hash == NULL) {
686 return (-1);
687 }
688 add_hashobject_to_hashtable(seg_hash);
689 copy_segment_layout(&seg_hash->u.seg_obj->segment, seg_hdr);
690 add_to_seg_object_list(sec_hash, seg_hash);
691 sec_obj->num_of_segment++;
692 }
693 return (0);
694 }
695
696 /* ARGSUSED */
697 int
fru_get_sections(container_hdl_t container,section_t * section,int maxsec,door_cred_t * cred)698 fru_get_sections(container_hdl_t container, section_t *section, int maxsec,
699 door_cred_t *cred)
700 {
701 int count;
702 int num_sec = 0;
703 hash_obj_t *cont_object;
704 hash_obj_t *sec_hash;
705
706 cont_object = lookup_handle_object(container, CONTAINER_TYPE);
707 if (cont_object == NULL) {
708 return (-1);
709 }
710
711 if (cont_object->u.cont_obj->num_of_section > maxsec) {
712 return (-1);
713 }
714
715 sec_hash = cont_object->u.cont_obj->sec_obj_list;
716 if (sec_hash == NULL) {
717 return (-1);
718 }
719
720 for (count = 0; count < cont_object->u.cont_obj->num_of_section;
721 count++) {
722 section->version = -1;
723 /* populate section_t */
724 if (get_section(g_raw, sec_hash, section) == 0) {
725 section++;
726 num_sec++;
727 }
728 sec_hash = sec_hash->u.sec_obj->next;
729 }
730 return (num_sec);
731 }
732
733
734 static uint32_t
get_checksum_crc(hash_obj_t * seg_hash,int data_size)735 get_checksum_crc(hash_obj_t *seg_hash, int data_size)
736 {
737 int protection;
738 int offset = 0;
739 uint32_t crc;
740 hash_obj_t *sec_hash;
741 hash_obj_t *pkt_hash;
742 unsigned char *buffer;
743
744 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
745 SECTION_TYPE);
746 if (sec_hash == NULL) {
747 return ((uint32_t)-1);
748 }
749
750 buffer = alloca(data_size);
751 if (buffer == NULL) {
752 return ((uint32_t)-1);
753 }
754
755 /* traverse the packet object list for all the tags and payload */
756 for (pkt_hash = seg_hash->u.seg_obj->pkt_obj_list; pkt_hash != NULL;
757 pkt_hash = pkt_hash->u.pkt_obj->next) {
758 (void) memcpy(buffer + offset, &pkt_hash->u.pkt_obj->tag,
759 pkt_hash->u.pkt_obj->tag_size);
760 offset += pkt_hash->u.pkt_obj->tag_size;
761 (void) memcpy(buffer + offset, pkt_hash->u.pkt_obj->payload,
762 pkt_hash->u.pkt_obj->paylen);
763 offset += pkt_hash->u.pkt_obj->paylen;
764 }
765
766 protection = sec_hash->u.sec_obj->section.protection;
767
768 if (protection == READ_ONLY_SECTION) { /* read-only section */
769 crc = compute_crc32(buffer, data_size);
770 } else { /* read/write section */
771 crc = compute_checksum32(buffer, data_size);
772 }
773 return (crc); /* computed crc */
774 }
775
776
777 static int
get_packet(raw_list_t * rawlist,void * buffer,int size,int offset)778 get_packet(raw_list_t *rawlist, void *buffer, int size, int offset)
779 {
780 int retval;
781
782 retval = raw_memcpy(buffer, rawlist, offset, size);
783
784 if (retval != -1) {
785 return (0);
786 }
787 return (-1);
788 }
789
790
791 static int
get_packets(hash_obj_t * seg_hash,raw_list_t * rawlist,int offset,int length)792 get_packets(hash_obj_t *seg_hash, raw_list_t *rawlist, int offset, int length)
793 {
794 int tag_size;
795 int paylen;
796 int retval;
797 int seg_limit = 0;
798 int pktcnt = 0;
799 char *data;
800 uint32_t crc;
801 uint32_t origcrc;
802 fru_tag_t tag;
803 hash_obj_t *pkt_hash_obj;
804 hash_obj_t *sec_hash;
805 fru_segdesc_t *segdesc;
806 fru_tagtype_t tagtype;
807 char *ignore_flag;
808
809 retval = get_packet(rawlist, &tag, sizeof (fru_tag_t), offset);
810 if (retval == -1) {
811 return (-1);
812 }
813
814 /* section hash object */
815 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
816 SECTION_TYPE);
817
818 if (sec_hash == NULL) {
819 return (-1);
820 }
821
822 seg_hash->u.seg_obj->trailer_offset = offset;
823
824 data = (char *)&tag;
825 while (data[0] != SEG_TRAILER_TAG) {
826 tagtype = get_tag_type(&tag); /* verify tag type */
827 if (tagtype == -1) {
828 return (-1);
829 }
830
831 tag_size = get_tag_size(tagtype);
832 if (tag_size == -1) {
833 return (-1);
834 }
835
836 seg_limit += tag_size;
837 if (seg_limit > length) {
838 return (-1);
839 }
840
841 paylen = get_payload_length((void *)&tag);
842 if (paylen == -1) {
843 return (-1);
844 }
845
846 seg_limit += paylen;
847 if (seg_limit > length) {
848 return (-1);
849 }
850 if ((offset + tag_size + paylen) >
851 (sec_hash->u.sec_obj->section.offset +
852 sec_hash->u.sec_obj->section.length)) {
853 return (-1);
854 }
855
856 pkt_hash_obj = create_packet_hash_object();
857 if (pkt_hash_obj == NULL) {
858 return (-1);
859 }
860
861 pkt_hash_obj->u.pkt_obj->payload = malloc(paylen);
862 if (pkt_hash_obj->u.pkt_obj->payload == NULL) {
863 free(pkt_hash_obj);
864 return (-1);
865 }
866
867 offset += tag_size;
868
869 retval = raw_memcpy(pkt_hash_obj->u.pkt_obj->payload, rawlist,
870 offset, paylen);
871
872 if (retval != paylen) {
873 free(pkt_hash_obj->u.pkt_obj->payload);
874 free(pkt_hash_obj);
875 return (-1);
876 }
877
878 /* don't change this */
879 pkt_hash_obj->u.pkt_obj->tag.raw_data = 0;
880 (void) memcpy(&pkt_hash_obj->u.pkt_obj->tag, &tag, tag_size);
881 pkt_hash_obj->u.pkt_obj->paylen = paylen;
882 pkt_hash_obj->u.pkt_obj->tag_size = tag_size;
883 pkt_hash_obj->u.pkt_obj->payload_offset = offset;
884
885 offset += paylen;
886
887 add_hashobject_to_hashtable(pkt_hash_obj);
888 add_to_pkt_object_list(seg_hash, pkt_hash_obj);
889
890 pktcnt++;
891
892 retval = get_packet(rawlist, &tag, sizeof (fru_tag_t),
893 offset);
894 if (retval == -1) {
895 return (retval);
896 }
897
898 data = (char *)&tag;
899 }
900
901 segdesc = (fru_segdesc_t *)&seg_hash->u.seg_obj->segment.descriptor;
902
903 seg_hash->u.seg_obj->trailer_offset = offset;
904
905 if (!segdesc->field.ignore_checksum) {
906 crc = get_checksum_crc(seg_hash, seg_limit);
907 offset = seg_hash->u.seg_obj->segment.offset;
908
909 retval = raw_memcpy(&origcrc, rawlist, offset + seg_limit + 1,
910 sizeof (origcrc));
911
912 ignore_flag = getenv(IGNORE_CHECK);
913 if (ignore_flag != NULL) {
914 return (pktcnt);
915 }
916
917 if (retval != sizeof (origcrc)) {
918 return (-1);
919 }
920
921 origcrc = BE_32(origcrc);
922 if (origcrc != crc) {
923 seg_hash->u.seg_obj->trailer_offset = offset;
924 return (-1);
925 }
926 }
927
928 return (pktcnt);
929 }
930
931 /* ARGSUSED */
932 int
fru_get_num_sections(container_hdl_t container,door_cred_t * cred)933 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
934 {
935 hash_obj_t *hash_object;
936
937 hash_object = lookup_handle_object(container, CONTAINER_TYPE);
938 if (hash_object == NULL) {
939 return (-1);
940 }
941
942 return (hash_object->u.cont_obj->num_of_section);
943 }
944
945 /* ARGSUSED */
946 int
fru_get_num_segments(section_hdl_t section,door_cred_t * cred)947 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
948 {
949 hash_obj_t *sec_object;
950 section_obj_t *sec_obj;
951
952 sec_object = lookup_handle_object(section, SECTION_TYPE);
953 if (sec_object == NULL) {
954 return (-1);
955 }
956
957 sec_obj = sec_object->u.sec_obj;
958 if (sec_obj == NULL) {
959 return (-1);
960 }
961
962 return (sec_obj->num_of_segment);
963 }
964
965 /* ARGSUSED */
966 int
fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)967 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
968 {
969 int pktcnt;
970 int length;
971 uint16_t offset;
972 hash_obj_t *cont_hash_obj;
973 hash_obj_t *seg_hash;
974 hash_obj_t *sec_hash;
975 fru_segdesc_t *segdesc;
976 segment_obj_t *segment_object;
977
978 seg_hash = lookup_handle_object(segment, SEGMENT_TYPE);
979 if (seg_hash == NULL) {
980 return (-1);
981 }
982
983 segment_object = seg_hash->u.seg_obj;
984 if (segment_object == NULL) {
985 return (-1);
986 }
987
988 segdesc = (fru_segdesc_t *)&segment_object->segment.descriptor;
989 if (segdesc->field.opaque) {
990 return (0);
991 }
992
993 offset = segment_object->segment.offset;
994 length = segment_object->segment.length;
995
996 cont_hash_obj = get_container_hash_object(SEGMENT_TYPE,
997 segment_object->section_hdl);
998
999 if (cont_hash_obj == NULL) {
1000 return (-1);
1001 }
1002
1003 if (seg_hash->u.seg_obj->pkt_obj_list != NULL) {
1004 return (segment_object->num_of_packets);
1005 }
1006 /* section hash object */
1007 sec_hash = lookup_handle_object(seg_hash->u.seg_obj->section_hdl,
1008 SECTION_TYPE);
1009 if (sec_hash == NULL) {
1010 return (-1);
1011 }
1012
1013 /* valid segment header b'cos crc8 already validated */
1014 if (offset < sec_hash->u.sec_obj->section.offset) {
1015 return (-1);
1016 }
1017
1018 segment_object->num_of_packets = 0;
1019
1020 pktcnt = get_packets(seg_hash, g_raw, offset, length);
1021 if (pktcnt == -1) {
1022 free_pkt_object_list(seg_hash);
1023 seg_hash->u.seg_obj->pkt_obj_list = NULL;
1024 }
1025
1026 segment_object->num_of_packets = pktcnt;
1027
1028 return (segment_object->num_of_packets);
1029 }
1030
1031 /* ARGSUSED */
1032 int
fru_get_packets(segment_hdl_t segment,packet_t * packet,int maxpackets,door_cred_t * cred)1033 fru_get_packets(segment_hdl_t segment, packet_t *packet, int maxpackets,
1034 door_cred_t *cred)
1035 {
1036 int count;
1037 hash_obj_t *seg_hash_obj;
1038 hash_obj_t *pkt_hash_obj;
1039
1040 /* segment hash object */
1041 seg_hash_obj = lookup_handle_object(segment, SEGMENT_TYPE);
1042 if (seg_hash_obj == NULL) {
1043 return (-1);
1044 }
1045
1046 if (seg_hash_obj->u.seg_obj->num_of_packets != maxpackets) {
1047 return (-1);
1048 }
1049
1050 pkt_hash_obj = seg_hash_obj->u.seg_obj->pkt_obj_list;
1051 if (pkt_hash_obj == NULL) {
1052 return (-1);
1053 }
1054
1055 for (count = 0; count < maxpackets; count++, packet++) {
1056 packet->handle = pkt_hash_obj->obj_hdl;
1057 packet->tag = 0;
1058 (void) memcpy(&packet->tag, &pkt_hash_obj->u.pkt_obj->tag,
1059 pkt_hash_obj->u.pkt_obj->tag_size);
1060 pkt_hash_obj = pkt_hash_obj->u.pkt_obj->next;
1061 }
1062
1063 return (0);
1064 }
1065
1066 /* ARGSUSED */
1067 ssize_t
fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)1068 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
1069 door_cred_t *cred)
1070 {
1071 hash_obj_t *packet_hash_obj;
1072
1073 /* packet hash object */
1074 packet_hash_obj = lookup_handle_object(packet, PACKET_TYPE);
1075 if (packet_hash_obj == NULL) {
1076 return (-1);
1077 }
1078
1079 /* verify payload length */
1080 if (nbytes != packet_hash_obj->u.pkt_obj->paylen) {
1081 return (-1);
1082 }
1083
1084 (void) memcpy(buffer, packet_hash_obj->u.pkt_obj->payload, nbytes);
1085 return (nbytes);
1086 }
1087
1088
1089 container_hdl_t
open_raw_data(raw_list_t * node)1090 open_raw_data(raw_list_t *node)
1091 {
1092 char *cont_conf_file = NULL;
1093 hash_obj_t *cont_hash_obj;
1094 hash_obj_t *sec_hash_obj;
1095 container_info_t cont_info;
1096 int retval;
1097 int count;
1098
1099 cont_hash_obj = create_container_hash_object();
1100 if (cont_hash_obj == NULL) {
1101 return (NULL);
1102 }
1103
1104 add_hashobject_to_hashtable(cont_hash_obj);
1105
1106 (void) strncpy(cont_hash_obj->u.cont_obj->device_pathname, "unknown",
1107 sizeof (cont_hash_obj->u.cont_obj->device_pathname));
1108
1109 cont_conf_file = getenv(FRU_CONT_CONF_ENV_VAR);
1110 if (cont_conf_file == NULL) {
1111 cont_conf_file = FRU_CONT_CONF_SPARC;
1112 retval = get_container_info(cont_conf_file, node->cont_type,
1113 &cont_info);
1114 if (retval < 0) {
1115 cont_conf_file = FRU_CONT_CONF_X86;
1116 retval = get_container_info(cont_conf_file,
1117 node->cont_type, &cont_info);
1118 }
1119 } else {
1120 retval = get_container_info(cont_conf_file, node->cont_type,
1121 &cont_info);
1122 }
1123
1124 if (retval < 0) {
1125 return (NULL);
1126 }
1127
1128 cont_hash_obj->u.cont_obj->num_of_section = cont_info.num_sections;
1129 cont_hash_obj->u.cont_obj->sec_obj_list = NULL;
1130
1131 for (count = 0; count < cont_info.num_sections; count++) {
1132 sec_hash_obj = create_section_hash_object();
1133 if (sec_hash_obj == NULL) {
1134 return (NULL);
1135 }
1136
1137 add_hashobject_to_hashtable(sec_hash_obj);
1138
1139 sec_hash_obj->u.sec_obj->section.offset =
1140 cont_info.section_info[count].address;
1141
1142 sec_hash_obj->u.sec_obj->section.protection =
1143 cont_info.section_info[count].description.field.read_only;
1144
1145 sec_hash_obj->u.sec_obj->section.length =
1146 cont_info.section_info[count].size;
1147 sec_hash_obj->u.sec_obj->section.version =
1148 cont_info.header_ver;
1149
1150 add_to_sec_object_list(cont_hash_obj, sec_hash_obj);
1151 }
1152
1153 return (cont_hash_obj->obj_hdl);
1154 }
1155
1156
1157 int
fru_close_container(container_hdl_t container)1158 fru_close_container(container_hdl_t container)
1159 {
1160 hash_obj_t *hash_obj;
1161 hash_obj_t *prev_hash;
1162 hash_obj_t *sec_hash_obj;
1163 handle_t obj_hdl;
1164
1165 /* lookup for container hash object */
1166 hash_obj = lookup_handle_object(container, CONTAINER_TYPE);
1167 if (hash_obj == NULL) {
1168 return (0);
1169 }
1170
1171 /* points to section object list */
1172 sec_hash_obj = hash_obj->u.cont_obj->sec_obj_list;
1173
1174 /* traverse section object list */
1175 while (sec_hash_obj != NULL) {
1176
1177 /* traverse segment hash object in the section */
1178 while (sec_hash_obj->u.sec_obj->seg_obj_list != NULL) {
1179 /* object handle of the segment hash object */
1180 obj_hdl =
1181 sec_hash_obj->u.sec_obj->seg_obj_list->obj_hdl;
1182 free_segment_hash(obj_hdl, sec_hash_obj);
1183 }
1184
1185 /* going to free section hash object, relink the hash object */
1186 if (sec_hash_obj->prev == NULL) {
1187 hash_table[(sec_hash_obj->obj_hdl % TABLE_SIZE)] =
1188 sec_hash_obj->next;
1189 if (sec_hash_obj->next != NULL) {
1190 sec_hash_obj->next->prev = NULL;
1191 }
1192 } else {
1193 sec_hash_obj->prev->next = sec_hash_obj->next;
1194 if (sec_hash_obj->next != NULL) {
1195 sec_hash_obj->next->prev = sec_hash_obj->prev;
1196 }
1197 }
1198
1199 prev_hash = sec_hash_obj;
1200 sec_hash_obj = sec_hash_obj->u.sec_obj->next;
1201
1202 free(prev_hash->u.sec_obj); /* free section hash object */
1203 free(prev_hash); /* free section hash */
1204 }
1205
1206 /* free container hash object */
1207 if (hash_obj->prev == NULL) {
1208 hash_table[(hash_obj->obj_hdl % TABLE_SIZE)] =
1209 hash_obj->next;
1210 if (hash_obj->next != NULL) {
1211 hash_obj->next->prev = NULL;
1212 }
1213 } else {
1214 hash_obj->prev->next = hash_obj->next;
1215 if (hash_obj->next != NULL) {
1216 hash_obj->next->prev = hash_obj->prev;
1217 }
1218 }
1219
1220 free(hash_obj->u.cont_obj);
1221 free(hash_obj);
1222
1223 return (0);
1224 }
1225