xref: /illumos-gate/usr/src/lib/libdevinfo/devinfo_prop_decode.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file contains kernel property decode routines adopted from
30  * sunddi.c and ddi_impl.c. The following changes have been applied.
31  *
32  * (1) Replace kmem_alloc by malloc. Remove negative indexing
33  * (2) Decoding applies only to prom properties.
34  * (3) For strings, the return value is a composite string, not a string array.
35  * (4) impl_ddi_prop_int_from_prom() uses _LITTLE_ENDIAN from isa_defs.h
36  *
37  * XXX This file should be kept in sync with kernel property encoding.
38  */
39 
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <synch.h>
43 #include <ctype.h>
44 #include <sys/types.h>
45 #include <sys/dditypes.h>
46 #include <sys/ddipropdefs.h>
47 #include <sys/isa_defs.h>
48 
49 #include "libdevinfo.h"
50 
51 /*
52  * Return an integer in native machine format from an OBP 1275 integer
53  * representation, which is big-endian, with no particular alignment
54  * guarantees. intp points to the OBP data, and n the number of bytes.
55  *
56  * Byte-swapping may be needed on some implementations.
57  */
58 int
59 impl_di_prop_int_from_prom(uchar_t *intp, int n)
60 {
61 	int i = 0;
62 
63 #if defined(_LITTLE_ENDIAN)
64 	intp += n;
65 	while (n-- > 0) {
66 		i = (i << 8) | *(--intp);
67 	}
68 #else
69 	while (n-- > 0) {
70 		i = (i << 8) | *intp++;
71 	}
72 #endif	/* defined(_LITTLE_ENDIAN) */
73 
74 	return (i);
75 }
76 
77 /*
78  * Reset the current location pointer in the property handle to the
79  * beginning of the data.
80  */
81 void
82 di_prop_reset_pos(prop_handle_t *ph)
83 {
84 	ph->ph_cur_pos = ph->ph_data;
85 	ph->ph_save_pos = ph->ph_data;
86 }
87 
88 /*
89  * Restore the current location pointer in the property handle to the
90  * saved position.
91  */
92 void
93 di_prop_save_pos(prop_handle_t *ph)
94 {
95 	ph->ph_save_pos = ph->ph_cur_pos;
96 }
97 
98 /*
99  * Save the location that the current location poiner is pointing to..
100  */
101 void
102 di_prop_restore_pos(prop_handle_t *ph)
103 {
104 	ph->ph_cur_pos = ph->ph_save_pos;
105 }
106 
107 /*
108  * Property encode/decode functions
109  */
110 
111 /*
112  * Decode an array of integers property
113  */
114 static int
115 di_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
116 {
117 	int	i;
118 	int	cnt = 0;
119 	int	*tmp;
120 	int	*intp;
121 	int	n;
122 
123 	/*
124 	 * Figure out how many array elements there are by going through the
125 	 * data without decoding it first and counting.
126 	 */
127 	for (;;) {
128 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
129 		if (i < 0)
130 			break;
131 		cnt++;
132 	}
133 
134 	/*
135 	 * If there are no elements return an error
136 	 */
137 	if (cnt == 0)
138 		return (DDI_PROP_END_OF_DATA);
139 
140 	/*
141 	 * If we cannot skip through the data, we cannot decode it
142 	 */
143 	if (i == DDI_PROP_RESULT_ERROR)
144 		return (DDI_PROP_CANNOT_DECODE);
145 
146 	/*
147 	 * Reset the data pointer to the beginning of the encoded data
148 	 */
149 	di_prop_reset_pos(ph);
150 
151 	/*
152 	 * Allocated memory to store the decoded value in.
153 	 */
154 	if ((intp = malloc(cnt * sizeof (int))) == NULL) {
155 		return (DDI_PROP_CANNOT_DECODE);
156 	}
157 
158 
159 	/*
160 	 * Decode each elemente and place it in the space we just allocated
161 	 */
162 	tmp = intp;
163 	for (n = 0; n < cnt; n++, tmp++) {
164 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
165 		if (i < DDI_PROP_RESULT_OK) {
166 			/*
167 			 * Free the space we just allocated
168 			 * and return an error.
169 			 */
170 			free(intp);
171 			switch (i) {
172 			case DDI_PROP_RESULT_EOF:
173 				return (DDI_PROP_END_OF_DATA);
174 
175 			case DDI_PROP_RESULT_ERROR:
176 				return (DDI_PROP_CANNOT_DECODE);
177 			}
178 		}
179 	}
180 
181 	*nelements = cnt;
182 	*(int **)data = intp;
183 
184 	return (DDI_PROP_SUCCESS);
185 }
186 
187 /*
188  * Decode an array of strings.
189  */
190 static int
191 di_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
192 {
193 	int		cnt = 0;
194 	char		*strs;
195 	char		*tmp;
196 	int		size;
197 	int		i;
198 	int		n;
199 	int		nbytes;
200 
201 	/*
202 	 * Figure out how much memory we need for the sum total
203 	 */
204 	nbytes = 0;
205 
206 	for (;;) {
207 		/*
208 		 * Get the decoded size of the current encoded string.
209 		 */
210 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
211 		if (size < 0)
212 			break;
213 
214 		cnt++;
215 		nbytes += size;
216 	}
217 
218 	/*
219 	 * If there are no elements return an error
220 	 */
221 	if (cnt == 0)
222 		return (DDI_PROP_END_OF_DATA);
223 
224 	/*
225 	 * If we cannot skip through the data, we cannot decode it
226 	 */
227 	if (size == DDI_PROP_RESULT_ERROR)
228 		return (DDI_PROP_CANNOT_DECODE);
229 
230 	/*
231 	 * Allocate memory in which to store the decoded strings.
232 	 */
233 	if ((strs = malloc(nbytes)) == NULL) {
234 		return (DDI_PROP_CANNOT_DECODE);
235 	}
236 
237 	/*
238 	 * Finally, we can decode each string
239 	 */
240 	di_prop_reset_pos(ph);
241 	tmp = strs;
242 	for (n = 0; n < cnt; n++) {
243 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
244 		if (i < DDI_PROP_RESULT_OK) {
245 			/*
246 			 * Free the space we just allocated
247 			 * and return an error
248 			 */
249 			free(strs);
250 			switch (i) {
251 			case DDI_PROP_RESULT_EOF:
252 				return (DDI_PROP_END_OF_DATA);
253 
254 			case DDI_PROP_RESULT_ERROR:
255 				return (DDI_PROP_CANNOT_DECODE);
256 			}
257 		}
258 		tmp += strlen(tmp) + 1;
259 	}
260 
261 	*(char **)data = strs;
262 	*nelements = cnt;
263 
264 	return (DDI_PROP_SUCCESS);
265 }
266 
267 /*
268  * Decode an array of bytes.
269  */
270 static int
271 di_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
272 {
273 	uchar_t		*tmp;
274 	int		nbytes;
275 	int		i;
276 
277 	/*
278 	 * If there are no elements return an error
279 	 */
280 	if (ph->ph_size == 0)
281 		return (DDI_PROP_END_OF_DATA);
282 
283 	/*
284 	 * Get the size of the encoded array of bytes.
285 	 */
286 	nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
287 		data, ph->ph_size);
288 	if (nbytes < DDI_PROP_RESULT_OK) {
289 		switch (nbytes) {
290 		case DDI_PROP_RESULT_EOF:
291 			return (DDI_PROP_END_OF_DATA);
292 
293 		case DDI_PROP_RESULT_ERROR:
294 			return (DDI_PROP_CANNOT_DECODE);
295 		}
296 	}
297 
298 	/*
299 	 * Allocated memory to store the decoded value in.
300 	 */
301 	if ((tmp = malloc(nbytes)) == NULL) {
302 		return (DDI_PROP_CANNOT_DECODE);
303 	}
304 
305 	/*
306 	 * Decode each element and place it in the space we just allocated
307 	 */
308 	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
309 	if (i < DDI_PROP_RESULT_OK) {
310 		/*
311 		 * Free the space we just allocated
312 		 * and return an error
313 		 */
314 		free(tmp);
315 		switch (i) {
316 		case DDI_PROP_RESULT_EOF:
317 			return (DDI_PROP_END_OF_DATA);
318 
319 		case DDI_PROP_RESULT_ERROR:
320 			return (DDI_PROP_CANNOT_DECODE);
321 		}
322 	}
323 
324 	*(uchar_t **)data = tmp;
325 	*nelements = nbytes;
326 
327 	return (DDI_PROP_SUCCESS);
328 }
329 
330 /*
331  * OBP 1275 integer, string and byte operators.
332  *
333  * DDI_PROP_CMD_DECODE:
334  *
335  *	DDI_PROP_RESULT_ERROR:		cannot decode the data
336  *	DDI_PROP_RESULT_EOF:		end of data
337  *	DDI_PROP_OK:			data was decoded
338  *
339  * DDI_PROP_CMD_ENCODE:
340  *
341  *	DDI_PROP_RESULT_ERROR:		cannot encode the data
342  *	DDI_PROP_RESULT_EOF:		end of data
343  *	DDI_PROP_OK:			data was encoded
344  *
345  * DDI_PROP_CMD_SKIP:
346  *
347  *	DDI_PROP_RESULT_ERROR:		cannot skip the data
348  *	DDI_PROP_RESULT_EOF:		end of data
349  *	DDI_PROP_OK:			data was skipped
350  *
351  * DDI_PROP_CMD_GET_ESIZE:
352  *
353  *	DDI_PROP_RESULT_ERROR:		cannot get encoded size
354  *	DDI_PROP_RESULT_EOF:		end of data
355  *	> 0:				the encoded size
356  *
357  * DDI_PROP_CMD_GET_DSIZE:
358  *
359  *	DDI_PROP_RESULT_ERROR:		cannot get decoded size
360  *	DDI_PROP_RESULT_EOF:		end of data
361  *	> 0:				the decoded size
362  */
363 
364 /*
365  * OBP 1275 integer operator
366  *
367  * OBP properties are a byte stream of data, so integers may not be
368  * properly aligned. Therefore we need to copy them one byte at a time.
369  */
370 int
371 di_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
372 {
373 	int	i;
374 
375 	switch (cmd) {
376 	case DDI_PROP_CMD_DECODE:
377 		/*
378 		 * Check that there is encoded data
379 		 */
380 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
381 			return (DDI_PROP_RESULT_ERROR);
382 		if (ph->ph_flags & PH_FROM_PROM) {
383 			i = ph->ph_size < PROP_1275_INT_SIZE ?
384 			    ph->ph_size : PROP_1275_INT_SIZE;
385 			if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
386 			    ph->ph_size - i))
387 				return (DDI_PROP_RESULT_ERROR);
388 		} else if (ph->ph_size < sizeof (int) ||
389 		    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
390 		    ph->ph_size - sizeof (int)))) {
391 			return (DDI_PROP_RESULT_ERROR);
392 		}
393 
394 		/*
395 		 * Copy the integer, using the implementation-specific
396 		 * copy function if the property is coming from the PROM.
397 		 */
398 		if (ph->ph_flags & PH_FROM_PROM) {
399 			*data = impl_di_prop_int_from_prom(
400 			    (uchar_t *)ph->ph_cur_pos,
401 			    (ph->ph_size < PROP_1275_INT_SIZE) ?
402 			    ph->ph_size : PROP_1275_INT_SIZE);
403 		} else {
404 			bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int));
405 		}
406 
407 		/*
408 		 * Move the current location to the start of the next
409 		 * bit of undecoded data.
410 		 */
411 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
412 		return (DDI_PROP_RESULT_OK);
413 
414 	case DDI_PROP_CMD_ENCODE:
415 		/*
416 		 * Check that there is room to encoded the data
417 		 */
418 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
419 		    ph->ph_size < PROP_1275_INT_SIZE ||
420 		    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
421 		    ph->ph_size - sizeof (int))))
422 			return (DDI_PROP_RESULT_ERROR);
423 
424 		/*
425 		 * Encode the integer into the byte stream one byte at a
426 		 * time.
427 		 */
428 		bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int));
429 
430 		/*
431 		 * Move the current location to the start of the next bit of
432 		 * space where we can store encoded data.
433 		 */
434 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
435 		return (DDI_PROP_RESULT_OK);
436 
437 	case DDI_PROP_CMD_SKIP:
438 		/*
439 		 * Check that there is encoded data
440 		 */
441 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
442 		    ph->ph_size < PROP_1275_INT_SIZE)
443 			return (DDI_PROP_RESULT_ERROR);
444 
445 
446 		if ((caddr_t)ph->ph_cur_pos ==
447 		    (caddr_t)ph->ph_data + ph->ph_size) {
448 			return (DDI_PROP_RESULT_EOF);
449 		} else if ((caddr_t)ph->ph_cur_pos >
450 		    (caddr_t)ph->ph_data + ph->ph_size) {
451 			return (DDI_PROP_RESULT_EOF);
452 		}
453 
454 		/*
455 		 * Move the current location to the start of the next bit of
456 		 * undecoded data.
457 		 */
458 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
459 		return (DDI_PROP_RESULT_OK);
460 
461 	case DDI_PROP_CMD_GET_ESIZE:
462 		/*
463 		 * Return the size of an encoded integer on OBP
464 		 */
465 		return (PROP_1275_INT_SIZE);
466 
467 	case DDI_PROP_CMD_GET_DSIZE:
468 		/*
469 		 * Return the size of a decoded integer on the system.
470 		 */
471 		return (sizeof (int));
472 	}
473 
474 	/*NOTREACHED*/
475 	return (0);	/* keep gcc happy */
476 }
477 
478 /*
479  * 64 bit integer operator
480  *
481  * This is an extension, defined by Sun, to the 1275 integer
482  * operator.  This routine handles the encoding/decoding of
483  * 64 bit integer properties.
484  */
485 int
486 di_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
487 {
488 	switch (cmd) {
489 	case DDI_PROP_CMD_DECODE:
490 		/*
491 		 * Check that there is encoded data
492 		 */
493 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
494 			return (DDI_PROP_RESULT_ERROR);
495 		if (ph->ph_flags & PH_FROM_PROM) {
496 			return (DDI_PROP_RESULT_ERROR);
497 		} else if (ph->ph_size < sizeof (int64_t) ||
498 		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
499 		    ph->ph_size - sizeof (int64_t)))) {
500 			return (DDI_PROP_RESULT_ERROR);
501 		}
502 
503 		/*
504 		 * Copy the integer, using the implementation-specific
505 		 * copy function if the property is coming from the PROM.
506 		 */
507 		bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int64_t));
508 
509 		/*
510 		 * Move the current location to the start of the next
511 		 * bit of undecoded data.
512 		 */
513 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
514 		    sizeof (int64_t);
515 		return (DDI_PROP_RESULT_OK);
516 
517 	case DDI_PROP_CMD_ENCODE:
518 		/*
519 		 * Check that there is room to encoded the data
520 		 */
521 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
522 		    ph->ph_size < sizeof (int64_t) ||
523 		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
524 		    ph->ph_size - sizeof (int64_t))))
525 			return (DDI_PROP_RESULT_ERROR);
526 
527 		/*
528 		 * Encode the integer into the byte stream one byte at a
529 		 * time.
530 		 */
531 		bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int64_t));
532 
533 		/*
534 		 * Move the current location to the start of the next bit of
535 		 * space where we can store encoded data.
536 		 */
537 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
538 		    sizeof (int64_t);
539 		return (DDI_PROP_RESULT_OK);
540 
541 	case DDI_PROP_CMD_SKIP:
542 		/*
543 		 * Check that there is encoded data
544 		 */
545 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
546 		    ph->ph_size < sizeof (int64_t))
547 			return (DDI_PROP_RESULT_ERROR);
548 
549 
550 		if ((caddr_t)ph->ph_cur_pos ==
551 		    (caddr_t)ph->ph_data + ph->ph_size) {
552 			return (DDI_PROP_RESULT_EOF);
553 		} else if ((caddr_t)ph->ph_cur_pos >
554 		    (caddr_t)ph->ph_data + ph->ph_size) {
555 			return (DDI_PROP_RESULT_EOF);
556 		}
557 
558 		/*
559 		 * Move the current location to the start of the next bit of
560 		 * undecoded data.
561 		 */
562 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
563 		    sizeof (int64_t);
564 		return (DDI_PROP_RESULT_OK);
565 
566 	case DDI_PROP_CMD_GET_ESIZE:
567 		/*
568 		 * Return the size of an encoded integer on OBP
569 		 */
570 		return (sizeof (int64_t));
571 
572 	case DDI_PROP_CMD_GET_DSIZE:
573 		/*
574 		 * Return the size of a decoded integer on the system.
575 		 */
576 		return (sizeof (int64_t));
577 	}
578 
579 	/*NOTREACHED*/
580 	return (0);	/* keep gcc happy */
581 }
582 
583 /*
584  * OBP 1275 string operator.
585  *
586  * OBP strings are NULL terminated.
587  */
588 int
589 di_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
590 {
591 	int	n;
592 	char	*p;
593 	char	*end;
594 
595 	switch (cmd) {
596 	case DDI_PROP_CMD_DECODE:
597 		/*
598 		 * Check that there is encoded data
599 		 */
600 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
601 			return (DDI_PROP_RESULT_ERROR);
602 		}
603 
604 		n = strlen((char *)ph->ph_cur_pos) + 1;
605 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
606 		    ph->ph_size - n)) {
607 			return (DDI_PROP_RESULT_ERROR);
608 		}
609 
610 		/*
611 		 * Copy the NULL terminated string
612 		 */
613 		bcopy((char *)ph->ph_cur_pos, data, n);
614 
615 		/*
616 		 * Move the current location to the start of the next bit of
617 		 * undecoded data.
618 		 */
619 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
620 		return (DDI_PROP_RESULT_OK);
621 
622 	case DDI_PROP_CMD_ENCODE:
623 		/*
624 		 * Check that there is room to encoded the data
625 		 */
626 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
627 			return (DDI_PROP_RESULT_ERROR);
628 		}
629 
630 		n = strlen(data) + 1;
631 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
632 		    ph->ph_size - n)) {
633 			return (DDI_PROP_RESULT_ERROR);
634 		}
635 
636 		/*
637 		 * Copy the NULL terminated string
638 		 */
639 		bcopy(data, (char *)ph->ph_cur_pos, n);
640 
641 		/*
642 		 * Move the current location to the start of the next bit of
643 		 * space where we can store encoded data.
644 		 */
645 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
646 		return (DDI_PROP_RESULT_OK);
647 
648 	case DDI_PROP_CMD_SKIP:
649 		/*
650 		 * Check that there is encoded data
651 		 */
652 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
653 			return (DDI_PROP_RESULT_ERROR);
654 		}
655 
656 		/*
657 		 * Return the string length plus one for the NULL
658 		 * We know the size of the property, we need to
659 		 * ensure that the string is properly formatted,
660 		 * since we may be looking up random OBP data.
661 		 */
662 		p = (char *)ph->ph_cur_pos;
663 		end = (char *)ph->ph_data + ph->ph_size;
664 
665 		if (p == end) {
666 			return (DDI_PROP_RESULT_EOF);
667 		}
668 
669 		/*
670 		 * Make sure each char is printable
671 		 */
672 		for (n = 0; p < end && isascii(*p) && !iscntrl(*p); n++, p++)
673 			;
674 
675 		/* Check termination and non-zero length */
676 		if ((*p == 0) && (n != 0)) {
677 			ph->ph_cur_pos = p + 1;
678 			return (DDI_PROP_RESULT_OK);
679 		}
680 
681 		return (DDI_PROP_RESULT_ERROR);
682 
683 	case DDI_PROP_CMD_GET_ESIZE:
684 		/*
685 		 * Return the size of the encoded string on OBP.
686 		 */
687 		return (strlen(data) + 1);
688 
689 	case DDI_PROP_CMD_GET_DSIZE:
690 		/*
691 		 * Return the string length plus one for the NULL
692 		 * We know the size of the property, we need to
693 		 * ensure that the string is properly formatted,
694 		 * since we may be looking up random OBP data.
695 		 */
696 		p = (char *)ph->ph_cur_pos;
697 		end = (char *)ph->ph_data + ph->ph_size;
698 		for (n = 0; p < end; n++) {
699 			if (*p++ == '\0') {
700 				ph->ph_cur_pos = p;
701 				return (n+1);
702 			}
703 		}
704 
705 		/*
706 		 * Add check here to separate EOF and ERROR.
707 		 */
708 		if (p == end)
709 			return (DDI_PROP_RESULT_EOF);
710 
711 		return (DDI_PROP_RESULT_ERROR);
712 
713 	}
714 
715 	/*NOTREACHED*/
716 	return (0);	/* keep gcc happy */
717 }
718 
719 /*
720  * OBP 1275 byte operator
721  *
722  * Caller must specify the number of bytes to get. OBP encodes bytes
723  * as a byte so there is a 1-to-1 translation.
724  */
725 int
726 di_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
727     uint_t nelements)
728 {
729 	switch (cmd) {
730 	case DDI_PROP_CMD_DECODE:
731 		/*
732 		 * Check that there is encoded data
733 		 */
734 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
735 		    ph->ph_size < nelements ||
736 		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
737 		    ph->ph_size - nelements)))
738 			return (DDI_PROP_RESULT_ERROR);
739 
740 		/*
741 		 * Copy out the bytes
742 		 */
743 		bcopy((char *)ph->ph_cur_pos, (char *)data, nelements);
744 
745 		/*
746 		 * Move the current location
747 		 */
748 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
749 		return (DDI_PROP_RESULT_OK);
750 
751 	case DDI_PROP_CMD_ENCODE:
752 		/*
753 		 * Check that there is room to encode the data
754 		 */
755 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
756 		    ph->ph_size < nelements ||
757 		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
758 		    ph->ph_size - nelements)))
759 			return (DDI_PROP_RESULT_ERROR);
760 
761 		/*
762 		 * Copy in the bytes
763 		 */
764 		bcopy((char *)data, (char *)ph->ph_cur_pos, nelements);
765 
766 		/*
767 		 * Move the current location to the start of the next bit of
768 		 * space where we can store encoded data.
769 		 */
770 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
771 		return (DDI_PROP_RESULT_OK);
772 
773 	case DDI_PROP_CMD_SKIP:
774 		/*
775 		 * Check that there is encoded data
776 		 */
777 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
778 		    ph->ph_size < nelements)
779 			return (DDI_PROP_RESULT_ERROR);
780 
781 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
782 		    ph->ph_size - nelements))
783 			return (DDI_PROP_RESULT_EOF);
784 
785 		/*
786 		 * Move the current location
787 		 */
788 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
789 		return (DDI_PROP_RESULT_OK);
790 
791 	case DDI_PROP_CMD_GET_ESIZE:
792 		/*
793 		 * The size in bytes of the encoded size is the
794 		 * same as the decoded size provided by the caller.
795 		 */
796 		return (nelements);
797 
798 	case DDI_PROP_CMD_GET_DSIZE:
799 		/*
800 		 * Just return the number of bytes specified by the caller.
801 		 */
802 		return (nelements);
803 
804 	}
805 
806 	/*NOTREACHED*/
807 	return (0);	/* keep gcc happy */
808 }
809 
810 /*
811  * Used for properties that come from the OBP, hardware configuration files,
812  * or that are created by calls to ddi_prop_update(9F).
813  */
814 static struct prop_handle_ops prop_1275_ops = {
815 	di_prop_1275_int,
816 	di_prop_1275_string,
817 	di_prop_1275_bytes,
818 	di_prop_int64_op
819 };
820 
821 /*
822  * Now the real thing:
823  * Extract type-specific values of an property
824  */
825 int
826 di_prop_decode_common(void *data, int size, int prop_type, int prom)
827 {
828 	int n;
829 	int nelements;
830 	char *cp, *end;
831 	prop_handle_t ph;
832 	int (*prop_decoder)(prop_handle_t *, void *, uint_t *);
833 
834 	/*
835 	 * If the encoded data came from software, no decoding needed
836 	 */
837 	if (!prom) {
838 		switch (prop_type) {
839 		case DI_PROP_TYPE_INT:
840 			if (size % sizeof (int))
841 				nelements = -1;
842 			else
843 				nelements = size / sizeof (int);
844 			break;
845 
846 		case DI_PROP_TYPE_INT64:
847 			if (size % sizeof (int64_t))
848 				nelements = -1;
849 			else
850 				nelements = size / sizeof (int64_t);
851 			break;
852 
853 		case DI_PROP_TYPE_STRING:
854 			nelements = 0;
855 			cp = *(char **)data;
856 			end = cp + size;
857 			/*
858 			 * Don't trust the data passed in by the caller.
859 			 * Check every char to make sure it is indeed a
860 			 * string property.
861 			 */
862 			while (cp < end) {
863 				/* skip to next non-printable char */
864 				for (n = 0; cp < end &&
865 				    isascii(*cp) && !iscntrl(*cp); n++, cp++)
866 					;
867 
868 				/*
869 				 * Fail if reached end (i.e. last char != 0),
870 				 * or has a non-printable char. A zero length
871 				 * string is acceptable.
872 				 */
873 				if (cp == end || *cp != 0) {
874 					nelements = -1;
875 					break;
876 				}
877 				/*
878 				 * Increment # strings and keep going
879 				 */
880 				nelements++;
881 				cp++;
882 			}
883 
884 			break;
885 
886 		case DI_PROP_TYPE_BYTE:
887 			nelements = size;
888 		}
889 
890 		return (nelements);
891 	}
892 
893 	/*
894 	 * Get the encoded data
895 	 */
896 	bzero((caddr_t)&ph, sizeof (prop_handle_t));
897 	ph.ph_data = *(uchar_t **)data;
898 	ph.ph_size = size;
899 
900 	/*
901 	 * The data came from prom, use the 1275 OBP decode/encode routines.
902 	 */
903 	ph.ph_cur_pos = ph.ph_data;
904 	ph.ph_save_pos = ph.ph_data;
905 	ph.ph_ops = &prop_1275_ops;
906 	ph.ph_flags = PH_FROM_PROM;
907 
908 	switch (prop_type) {
909 	case DI_PROP_TYPE_INT:
910 		prop_decoder = di_prop_fm_decode_ints;
911 		break;
912 	case DI_PROP_TYPE_STRING:
913 		prop_decoder = di_prop_fm_decode_strings;
914 		break;
915 	case DI_PROP_TYPE_BYTE:
916 	default:
917 		prop_decoder = di_prop_fm_decode_bytes;
918 		break;
919 	}
920 
921 	if ((*prop_decoder)(&ph, data, (uint_t *)&nelements)
922 	    != DDI_PROP_SUCCESS)
923 		return (-1);
924 
925 	/*
926 	 * Free the encoded data
927 	 */
928 	if (size != 0)
929 		free(ph.ph_data);
930 
931 	return (nelements);
932 }
933 
934 void
935 di_slot_names_free(int count, di_slot_name_t *slot_names)
936 {
937 	if (slot_names == NULL)
938 		return;
939 
940 	while (--count >= 0) {
941 		if (slot_names[count].name != NULL)
942 			free(slot_names[count].name);
943 	}
944 	free(slot_names);
945 }
946 
947 /*
948  * 1275 "slot-names" format: [int][string1][string2]...[stringN]
949  *	- [int] is a 1275 encoded integer
950  *      - [string1]...[stringN] are concatenated null-terminated strings
951  *      - each bit position in [int] represents a pci device number
952  *	- each bit which is set in [int] represents a slot with a device
953  *	  number of that bit position
954  *      - each string in [string1]...[stringN] identifies a slot name only
955  *	  for the bits which are set in [int]
956  *	- the ordering of strings follow the ordering of bits set in [int]
957  *
958  * an allocated array of di_slot_name_t is returned through prop_data if
959  * [int] is non-zero and the number of entries as the return value;
960  * use di_slot_names_free() to free the array
961  */
962 int
963 di_slot_names_decode(uchar_t *rawdata, int rawlen,
964     di_slot_name_t **prop_data)
965 {
966 	char *sp, *maxsp;
967 	int count, i;
968 	size_t len;
969 	int slots;
970 	int maxcount = 0;
971 	int maxslots = 0;
972 	di_slot_name_t *slot_names = NULL;
973 
974 	if (rawlen < sizeof (slots))
975 		goto ERROUT;
976 
977 	slots = impl_di_prop_int_from_prom(rawdata, sizeof (slots));
978 	if (slots == 0) {
979 		*prop_data = NULL;
980 		return (0);
981 	}
982 
983 	maxslots = sizeof (slots) * 8;
984 	count = 0;
985 	for (i = 0; i < maxslots; i++) {
986 		if (slots & (1 << i))
987 			count++;
988 	}
989 	maxslots = i;
990 	maxcount = count;
991 	slot_names = malloc(sizeof (*slot_names) * maxcount);
992 	bzero(slot_names, sizeof (*slot_names) * maxcount);
993 
994 	/* also handle unterminated strings */
995 	sp = (char *)(rawdata + sizeof (slots));
996 	maxsp = sp + (rawlen - sizeof (slots));
997 	count = 0;
998 	for (i = 0; i < maxslots; i++) {
999 		if (slots & (1 << i)) {
1000 			if (sp > maxsp)
1001 				break;
1002 			len = strnlen(sp, (maxsp - sp) + 1);
1003 			if (len == 0)
1004 				break;
1005 
1006 			slot_names[count].name =
1007 			    malloc(sizeof (char) * (len + 1));
1008 			(void) strlcpy(slot_names[count].name, sp, len + 1);
1009 
1010 			slot_names[count].num = i;
1011 
1012 			sp += len + 1;
1013 			count++;
1014 		}
1015 	}
1016 
1017 	/*
1018 	 * check if the number of strings match with the number of slots;
1019 	 * we can also get a lesser string count even when there appears to be
1020 	 * the correct number of strings if one or more pair of strings are
1021 	 * seperated by more than one NULL byte
1022 	 */
1023 	if (count != maxcount)
1024 		goto ERROUT;
1025 
1026 	*prop_data = slot_names;
1027 	return (maxcount);
1028 	/*NOTREACHED*/
1029 ERROUT:
1030 	di_slot_names_free(maxcount, slot_names);
1031 	*prop_data = NULL;
1032 	return (-1);
1033 }
1034