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