+
+/*
+ * Walk over Evil WIMAX TLVs, creating attributes.
+ */
+static VALUE_PAIR *tlv2wimax(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret,
+ int attribute, int vendor,
+ uint8_t *ptr, size_t len, int nest)
+{
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR **tail = &head;
+ VALUE_PAIR *vp;
+ uint8_t *y; /* why do I need to do this? */
+
+ if (nest > fr_wimax_max_tlv) return NULL;
+
+ /*
+ * Sanity check the attribute.
+ */
+ for (y = ptr; y < (ptr + len); y += y[1]) {
+ if ((y[0] == 0) || ((y + 2) > (ptr + len)) ||
+ (y[1] < 2) || ((y + y[1]) > (ptr + len))) {
+ return NULL;
+ }
+
+ /*
+ * Attribute number is too large for us to
+ * represent it in our horrible internal
+ * representation.
+ */
+ if ((ptr[0] & ~fr_wimax_mask[nest]) != 0) {
+ return NULL;
+ }
+ }
+
+ for (y = ptr; y < (ptr + len); y += y[1]) {
+ DICT_ATTR *da;
+
+ da = dict_attrbyvalue(attribute | (ptr[0] << fr_wimax_shift[nest]), vendor);
+ if (da && (da->type == PW_TYPE_TLV)) {
+ vp = tlv2wimax(packet, original, secret,
+ attribute | (ptr[0] << fr_wimax_shift[nest]),
+ vendor, ptr + 2, ptr[1] - 2,
+ nest + 1);
+ if (!vp) goto error;
+ } else {
+ vp = paircreate(attribute | (ptr[0] << fr_wimax_shift[nest]), vendor,
+ PW_TYPE_OCTETS);
+ if (!vp) {
+ error:
+ pairfree(&head);
+ return NULL;
+ }
+
+ if (!data2vp(packet, original, secret,
+ y[1] - 2, y + 2, vp)) {
+ goto error;
+ }
+ }
+
+ *tail = vp;
+ while (*tail) tail = &((*tail)->next);
+ }
+
+ return head;
+}
+