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