static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len) { unsigned int values, i; /* How many values we need to decode */ uint8_t const *p = data; size_t value_len; ssize_t len; FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len); FR_PROTO_HEX_DUMP(data, data_len, NULL); /* * TLVs can't be coalesced as they're variable length */ if (parent->type == FR_TYPE_TLV) return decode_tlv(ctx, cursor, parent, data, data_len); /* * Values with a fixed length may be coalesced into a single option */ values = fr_dhcpv4_array_members(&value_len, data_len, parent); if (values) { FR_PROTO_TRACE("found %u coalesced values (%zu bytes each)", values, value_len); if ((values * value_len) != data_len) { fr_strerror_printf("Option length not divisible by its fixed value " "length (probably trailing garbage)"); return -1; } } /* * Decode each of the (maybe) coalesced values as its own * attribute. */ for (i = 0, p = data; i < values; i++) { len = decode_value_internal(ctx, cursor, parent, p, value_len); if (len <= 0) return len; if (len != (ssize_t)value_len) { fr_strerror_printf("Failed decoding complete option value"); return -1; } p += len; } return p - data; }
static int show_control(const char *space, snd_hctl_elem_t *elem, int level) { int err; unsigned int item, idx, count, *tlv; snd_ctl_elem_type_t type; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *control; snd_aes_iec958_t iec958; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_alloca(&info); snd_ctl_elem_value_alloca(&control); if ((err = snd_hctl_elem_info(elem, info)) < 0) { error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err)); return err; } if (level & LEVEL_ID) { snd_hctl_elem_get_id(elem, id); show_control_id(id); printf("\n"); } count = snd_ctl_elem_info_get_count(info); type = snd_ctl_elem_info_get_type(info); printf("%s; type=%s,access=%s,values=%i", space, control_type(info), control_access(info), count); switch (type) { case SND_CTL_ELEM_TYPE_INTEGER: printf(",min=%li,max=%li,step=%li\n", snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info), snd_ctl_elem_info_get_step(info)); break; case SND_CTL_ELEM_TYPE_INTEGER64: printf(",min=%Li,max=%Li,step=%Li\n", snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info), snd_ctl_elem_info_get_step64(info)); break; case SND_CTL_ELEM_TYPE_ENUMERATED: { unsigned int items = snd_ctl_elem_info_get_items(info); printf(",items=%u\n", items); for (item = 0; item < items; item++) { snd_ctl_elem_info_set_item(info, item); if ((err = snd_hctl_elem_info(elem, info)) < 0) { error("Control %s element info error: %s\n", card, snd_strerror(err)); return err; } printf("%s; Item #%u '%s'\n", space, item, snd_ctl_elem_info_get_item_name(info)); } break; } default: printf("\n"); break; } if (level & LEVEL_BASIC) { if (!snd_ctl_elem_info_is_readable(info)) goto __skip_read; if ((err = snd_hctl_elem_read(elem, control)) < 0) { error("Control %s element read error: %s\n", card, snd_strerror(err)); return err; } printf("%s: values=", space); for (idx = 0; idx < count; idx++) { if (idx > 0) printf(","); switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: printf("%s", snd_ctl_elem_value_get_boolean(control, idx) ? "on" : "off"); break; case SND_CTL_ELEM_TYPE_INTEGER: printf("%li", snd_ctl_elem_value_get_integer(control, idx)); break; case SND_CTL_ELEM_TYPE_INTEGER64: printf("%Li", snd_ctl_elem_value_get_integer64(control, idx)); break; case SND_CTL_ELEM_TYPE_ENUMERATED: printf("%u", snd_ctl_elem_value_get_enumerated(control, idx)); break; case SND_CTL_ELEM_TYPE_BYTES: printf("0x%02x", snd_ctl_elem_value_get_byte(control, idx)); break; case SND_CTL_ELEM_TYPE_IEC958: snd_ctl_elem_value_get_iec958(control, &iec958); printf("[AES0=0x%02x AES1=0x%02x AES2=0x%02x AES3=0x%02x]", iec958.status[0], iec958.status[1], iec958.status[2], iec958.status[3]); break; default: printf("?"); break; } } printf("\n"); __skip_read: if (!snd_ctl_elem_info_is_tlv_readable(info)) goto __skip_tlv; tlv = malloc(4096); if ((err = snd_hctl_elem_tlv_read(elem, tlv, 4096)) < 0) { error("Control %s element TLV read error: %s\n", card, snd_strerror(err)); free(tlv); return err; } decode_tlv(strlen(space), tlv, 4096); free(tlv); } __skip_tlv: return 0; }
static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size) { unsigned int type = tlv[0]; unsigned int size; unsigned int idx = 0; if (tlv_size < 2 * sizeof(unsigned int)) { printf("TLV size error!\n"); return; } print_spaces(spaces); printf("| "); type = tlv[idx++]; size = tlv[idx++]; tlv_size -= 2 * sizeof(unsigned int); if (size > tlv_size) { printf("TLV size error (%i, %i, %i)!\n", type, size, tlv_size); return; } switch (type) { case SND_CTL_TLVT_CONTAINER: size += sizeof(unsigned int) - 1; size /= sizeof(unsigned int); while (idx < size) { if (tlv[idx + 1] > (size - idx) * sizeof(unsigned int)) { printf("TLV size error in compound!\n"); return; } decode_tlv(spaces + 2, tlv + idx, tlv[idx + 1]); idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int); } break; case SND_CTL_TLVT_DB_SCALE: printf("dBscale-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB((int)tlv[2]); printf(",step="); print_dB(tlv[3] & 0xffff); printf(",mute=%i", (tlv[3] >> 16) & 1); } break; #ifdef SND_CTL_TLVT_DB_LINEAR case SND_CTL_TLVT_DB_LINEAR: printf("dBlinear-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB(tlv[2]); printf(",max="); print_dB(tlv[3]); } break; #endif #ifdef SND_CTL_TLVT_DB_RANGE case SND_CTL_TLVT_DB_RANGE: printf("dBrange-\n"); if ((size % (6 * sizeof(unsigned int))) != 0) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } break; } while (size > 0) { print_spaces(spaces + 2); printf("rangemin=%i,", tlv[idx++]); printf(",rangemax=%i\n", tlv[idx++]); decode_tlv(spaces + 4, tlv + idx, 4 * sizeof(unsigned int)); idx += 4; size -= 6 * sizeof(unsigned int); } break; #endif #ifdef SND_CTL_TLVT_DB_MINMAX case SND_CTL_TLVT_DB_MINMAX: case SND_CTL_TLVT_DB_MINMAX_MUTE: if (type == SND_CTL_TLVT_DB_MINMAX_MUTE) printf("dBminmaxmute-"); else printf("dBminmax-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB(tlv[2]); printf(",max="); print_dB(tlv[3]); } break; #endif default: printf("unk-%i-", type); while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } break; } putc('\n', stdout); }