#include <stdlib.h>
#include <strings.h>
#include <synch.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/dditypes.h>
#include <sys/ddipropdefs.h>
#include <sys/isa_defs.h>
#include "libdevinfo.h"
int
impl_di_prop_int_from_prom(uchar_t *intp, int n)
{
int i = 0;
#if defined(_LITTLE_ENDIAN)
intp += n;
while (n-- > 0) {
i = (i << 8) | *(--intp);
}
#else
while (n-- > 0) {
i = (i << 8) | *intp++;
}
#endif
return (i);
}
void
di_prop_reset_pos(prop_handle_t *ph)
{
ph->ph_cur_pos = ph->ph_data;
ph->ph_save_pos = ph->ph_data;
}
void
di_prop_save_pos(prop_handle_t *ph)
{
ph->ph_save_pos = ph->ph_cur_pos;
}
void
di_prop_restore_pos(prop_handle_t *ph)
{
ph->ph_cur_pos = ph->ph_save_pos;
}
static int
di_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
{
int i;
int cnt = 0;
int *tmp;
int *intp;
int n;
for (;;) {
i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
if (i < 0)
break;
cnt++;
}
if (cnt == 0)
return (DDI_PROP_END_OF_DATA);
if (i == DDI_PROP_RESULT_ERROR)
return (DDI_PROP_CANNOT_DECODE);
di_prop_reset_pos(ph);
if ((intp = malloc(cnt * sizeof (int))) == NULL) {
return (DDI_PROP_CANNOT_DECODE);
}
tmp = intp;
for (n = 0; n < cnt; n++, tmp++) {
i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
if (i < DDI_PROP_RESULT_OK) {
free(intp);
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
*nelements = cnt;
*(int **)data = intp;
return (DDI_PROP_SUCCESS);
}
static int
di_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
{
int cnt = 0;
char *strs;
char *tmp;
int size;
int i;
int n;
int nbytes;
nbytes = 0;
for (;;) {
size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
if (size < 0)
break;
cnt++;
nbytes += size;
}
if (cnt == 0)
return (DDI_PROP_END_OF_DATA);
if (size == DDI_PROP_RESULT_ERROR)
return (DDI_PROP_CANNOT_DECODE);
if ((strs = malloc(nbytes)) == NULL) {
return (DDI_PROP_CANNOT_DECODE);
}
di_prop_reset_pos(ph);
tmp = strs;
for (n = 0; n < cnt; n++) {
i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
if (i < DDI_PROP_RESULT_OK) {
free(strs);
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
tmp += strlen(tmp) + 1;
}
*(char **)data = strs;
*nelements = cnt;
return (DDI_PROP_SUCCESS);
}
static int
di_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
{
uchar_t *tmp;
int nbytes;
int i;
if (ph->ph_size == 0)
return (DDI_PROP_END_OF_DATA);
nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
data, ph->ph_size);
if (nbytes < DDI_PROP_RESULT_OK) {
switch (nbytes) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
if ((tmp = malloc(nbytes)) == NULL) {
return (DDI_PROP_CANNOT_DECODE);
}
i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
if (i < DDI_PROP_RESULT_OK) {
free(tmp);
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
*(uchar_t **)data = tmp;
*nelements = nbytes;
return (DDI_PROP_SUCCESS);
}
int
di_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
{
int i;
switch (cmd) {
case DDI_PROP_CMD_DECODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
return (DDI_PROP_RESULT_ERROR);
if (ph->ph_flags & PH_FROM_PROM) {
i = ph->ph_size < PROP_1275_INT_SIZE ?
ph->ph_size : PROP_1275_INT_SIZE;
if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
ph->ph_size - i))
return (DDI_PROP_RESULT_ERROR);
} else if (ph->ph_size < sizeof (int) ||
((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
ph->ph_size - sizeof (int)))) {
return (DDI_PROP_RESULT_ERROR);
}
if (ph->ph_flags & PH_FROM_PROM) {
*data = impl_di_prop_int_from_prom(
(uchar_t *)ph->ph_cur_pos,
(ph->ph_size < PROP_1275_INT_SIZE) ?
ph->ph_size : PROP_1275_INT_SIZE);
} else {
bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int));
}
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < PROP_1275_INT_SIZE ||
((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
ph->ph_size - sizeof (int))))
return (DDI_PROP_RESULT_ERROR);
bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int));
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < PROP_1275_INT_SIZE)
return (DDI_PROP_RESULT_ERROR);
if ((caddr_t)ph->ph_cur_pos ==
(caddr_t)ph->ph_data + ph->ph_size) {
return (DDI_PROP_RESULT_EOF);
} else if ((caddr_t)ph->ph_cur_pos >
(caddr_t)ph->ph_data + ph->ph_size) {
return (DDI_PROP_RESULT_EOF);
}
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
return (PROP_1275_INT_SIZE);
case DDI_PROP_CMD_GET_DSIZE:
return (sizeof (int));
}
return (0);
}
int
di_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
{
switch (cmd) {
case DDI_PROP_CMD_DECODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
return (DDI_PROP_RESULT_ERROR);
if (ph->ph_flags & PH_FROM_PROM) {
return (DDI_PROP_RESULT_ERROR);
} else if (ph->ph_size < sizeof (int64_t) ||
((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
ph->ph_size - sizeof (int64_t)))) {
return (DDI_PROP_RESULT_ERROR);
}
bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int64_t));
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < sizeof (int64_t) ||
((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
ph->ph_size - sizeof (int64_t))))
return (DDI_PROP_RESULT_ERROR);
bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int64_t));
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < sizeof (int64_t))
return (DDI_PROP_RESULT_ERROR);
if ((caddr_t)ph->ph_cur_pos ==
(caddr_t)ph->ph_data + ph->ph_size) {
return (DDI_PROP_RESULT_EOF);
} else if ((caddr_t)ph->ph_cur_pos >
(caddr_t)ph->ph_data + ph->ph_size) {
return (DDI_PROP_RESULT_EOF);
}
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
return (sizeof (int64_t));
case DDI_PROP_CMD_GET_DSIZE:
return (sizeof (int64_t));
}
return (0);
}
int
di_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
{
int n;
char *p;
char *end;
switch (cmd) {
case DDI_PROP_CMD_DECODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
return (DDI_PROP_RESULT_ERROR);
}
n = strlen((char *)ph->ph_cur_pos) + 1;
if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
ph->ph_size - n)) {
return (DDI_PROP_RESULT_ERROR);
}
bcopy((char *)ph->ph_cur_pos, data, n);
ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
return (DDI_PROP_RESULT_ERROR);
}
n = strlen(data) + 1;
if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
ph->ph_size - n)) {
return (DDI_PROP_RESULT_ERROR);
}
bcopy(data, (char *)ph->ph_cur_pos, n);
ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
return (DDI_PROP_RESULT_ERROR);
}
p = (char *)ph->ph_cur_pos;
end = (char *)ph->ph_data + ph->ph_size;
if (p == end) {
return (DDI_PROP_RESULT_EOF);
}
for (n = 0; p < end && isascii(*p) && !iscntrl(*p); n++, p++)
;
if ((*p == 0) && (n != 0)) {
ph->ph_cur_pos = p + 1;
return (DDI_PROP_RESULT_OK);
}
return (DDI_PROP_RESULT_ERROR);
case DDI_PROP_CMD_GET_ESIZE:
return (strlen(data) + 1);
case DDI_PROP_CMD_GET_DSIZE:
p = (char *)ph->ph_cur_pos;
end = (char *)ph->ph_data + ph->ph_size;
for (n = 0; p < end; n++) {
if (*p++ == '\0') {
ph->ph_cur_pos = p;
return (n+1);
}
}
if (p == end)
return (DDI_PROP_RESULT_EOF);
return (DDI_PROP_RESULT_ERROR);
}
return (0);
}
int
di_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
uint_t nelements)
{
switch (cmd) {
case DDI_PROP_CMD_DECODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < nelements ||
((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
ph->ph_size - nelements)))
return (DDI_PROP_RESULT_ERROR);
bcopy((char *)ph->ph_cur_pos, (char *)data, nelements);
ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < nelements ||
((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
ph->ph_size - nelements)))
return (DDI_PROP_RESULT_ERROR);
bcopy((char *)data, (char *)ph->ph_cur_pos, nelements);
ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
ph->ph_size < nelements)
return (DDI_PROP_RESULT_ERROR);
if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
ph->ph_size - nelements))
return (DDI_PROP_RESULT_EOF);
ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
return (nelements);
case DDI_PROP_CMD_GET_DSIZE:
return (nelements);
}
return (0);
}
static struct prop_handle_ops prop_1275_ops = {
di_prop_1275_int,
di_prop_1275_string,
di_prop_1275_bytes,
di_prop_int64_op
};
int
di_prop_decode_common(void *data, int size, int prop_type, int prom)
{
int n;
int nelements;
char *cp, *end;
prop_handle_t ph;
int (*prop_decoder)(prop_handle_t *, void *, uint_t *);
if (!prom) {
switch (prop_type) {
case DI_PROP_TYPE_INT:
if (size % sizeof (int))
nelements = -1;
else
nelements = size / sizeof (int);
break;
case DI_PROP_TYPE_INT64:
if (size % sizeof (int64_t))
nelements = -1;
else
nelements = size / sizeof (int64_t);
break;
case DI_PROP_TYPE_STRING:
nelements = 0;
cp = *(char **)data;
end = cp + size;
while (cp < end) {
for (n = 0; cp < end &&
isascii(*cp) && !iscntrl(*cp); n++, cp++)
;
if (cp == end || *cp != 0) {
nelements = -1;
break;
}
nelements++;
cp++;
}
break;
case DI_PROP_TYPE_BYTE:
nelements = size;
}
return (nelements);
}
bzero((caddr_t)&ph, sizeof (prop_handle_t));
ph.ph_data = *(uchar_t **)data;
ph.ph_size = size;
ph.ph_cur_pos = ph.ph_data;
ph.ph_save_pos = ph.ph_data;
ph.ph_ops = &prop_1275_ops;
ph.ph_flags = PH_FROM_PROM;
switch (prop_type) {
case DI_PROP_TYPE_INT:
prop_decoder = di_prop_fm_decode_ints;
break;
case DI_PROP_TYPE_STRING:
prop_decoder = di_prop_fm_decode_strings;
break;
case DI_PROP_TYPE_BYTE:
default:
prop_decoder = di_prop_fm_decode_bytes;
break;
}
if ((*prop_decoder)(&ph, data, (uint_t *)&nelements)
!= DDI_PROP_SUCCESS)
return (-1);
if (size != 0)
free(ph.ph_data);
return (nelements);
}
void
di_slot_names_free(int count, di_slot_name_t *slot_names)
{
if (slot_names == NULL)
return;
while (--count >= 0) {
if (slot_names[count].name != NULL)
free(slot_names[count].name);
}
free(slot_names);
}
int
di_slot_names_decode(uchar_t *rawdata, int rawlen,
di_slot_name_t **prop_data)
{
char *sp, *maxsp;
int count, i;
size_t len;
int slots;
int maxcount = 0;
int maxslots = 0;
di_slot_name_t *slot_names = NULL;
if (rawlen < sizeof (slots))
goto ERROUT;
slots = impl_di_prop_int_from_prom(rawdata, sizeof (slots));
if (slots == 0) {
*prop_data = NULL;
return (0);
}
maxslots = sizeof (slots) * 8;
count = 0;
for (i = 0; i < maxslots; i++) {
if (slots & (1 << i))
count++;
}
maxslots = i;
maxcount = count;
slot_names = malloc(sizeof (*slot_names) * maxcount);
bzero(slot_names, sizeof (*slot_names) * maxcount);
sp = (char *)(rawdata + sizeof (slots));
maxsp = sp + (rawlen - sizeof (slots));
count = 0;
for (i = 0; i < maxslots; i++) {
if (slots & (1 << i)) {
if (sp > maxsp)
break;
len = strnlen(sp, (maxsp - sp) + 1);
if (len == 0)
break;
slot_names[count].name =
malloc(sizeof (char) * (len + 1));
(void) strlcpy(slot_names[count].name, sp, len + 1);
slot_names[count].num = i;
sp += len + 1;
count++;
}
}
if (count != maxcount)
goto ERROUT;
*prop_data = slot_names;
return (maxcount);
ERROUT:
di_slot_names_free(maxcount, slot_names);
*prop_data = NULL;
return (-1);
}